From cf7558648bd5323eb21ce43dfb51e4722ff1b016 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 21 Oct 2008 07:00:00 -0700 Subject: [PATCH 0001/1150] Initial Contribution --- core/java/android/os/NetStat.java | 51 +++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 core/java/android/os/NetStat.java diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java new file mode 100644 index 0000000000..7312236d74 --- /dev/null +++ b/core/java/android/os/NetStat.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** @hide */ +public class NetStat{ + + /** + * Get total number of tx packets sent through ppp0 + * + * @return number of Tx packets through ppp0 + */ + + public native static int netStatGetTxPkts(); + + /** + * Get total number of rx packets received through ppp0 + * + * @return number of Rx packets through ppp0 + */ + public native static int netStatGetRxPkts(); + + /** + * Get total number of tx bytes received through ppp0 + * + * @return number of Tx bytes through ppp0 + */ + public native static int netStatGetTxBytes(); + + /** + * Get total number of rx bytes received through ppp0 + * + * @return number of Rx bytes through ppp0 + */ + public native static int netStatGetRxBytes(); + +} From 4bc9554dcc33a5e7351d57c5641b6d469a3368ef Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:44:00 -0800 Subject: [PATCH 0002/1150] auto import from //branches/cupcake/...@130745 --- core/java/android/os/NetStat.java | 187 +++++++++++++++++++++++++++--- 1 file changed, 174 insertions(+), 13 deletions(-) diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java index 7312236d74..733137a32c 100644 --- a/core/java/android/os/NetStat.java +++ b/core/java/android/os/NetStat.java @@ -16,36 +16,197 @@ package android.os; +import android.util.Log; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.IOException; + /** @hide */ public class NetStat{ /** - * Get total number of tx packets sent through ppp0 + * Get total number of tx packets sent through rmnet0 or ppp0 * - * @return number of Tx packets through ppp0 + * @return number of Tx packets through rmnet0 or ppp0 */ - - public native static int netStatGetTxPkts(); + public static long getMobileTxPkts() { + return getMobileStat("tx_packets"); + } /** - * Get total number of rx packets received through ppp0 + * Get total number of rx packets received through rmnet0 or ppp0 * - * @return number of Rx packets through ppp0 + * @return number of Rx packets through rmnet0 or ppp0 */ - public native static int netStatGetRxPkts(); + public static long getMobileRxPkts() { + return getMobileStat("rx_packets"); + } /** - * Get total number of tx bytes received through ppp0 + * Get total number of tx bytes received through rmnet0 or ppp0 * - * @return number of Tx bytes through ppp0 + * @return number of Tx bytes through rmnet0 or ppp0 */ - public native static int netStatGetTxBytes(); + public static long getMobileTxBytes() { + return getMobileStat("tx_bytes"); + } /** - * Get total number of rx bytes received through ppp0 + * Get total number of rx bytes received through rmnet0 or ppp0 * - * @return number of Rx bytes through ppp0 + * @return number of Rx bytes through rmnet0 or ppp0 */ - public native static int netStatGetRxBytes(); + public static long getMobileRxBytes() { + return getMobileStat("rx_bytes"); + } + /** + * Get the total number of packets sent through all network interfaces. + * + * @return the number of packets sent through all network interfaces + */ + public static long getTotalTxPkts() { + return getTotalStat("tx_packets"); + } + + /** + * Get the total number of packets received through all network interfaces. + * + * @return the number of packets received through all network interfaces + */ + public static long getTotalRxPkts() { + return getTotalStat("rx_packets"); + } + + /** + * Get the total number of bytes sent through all network interfaces. + * + * @return the number of bytes sent through all network interfaces + */ + public static long getTotalTxBytes() { + return getTotalStat("tx_bytes"); + } + + /** + * Get the total number of bytes received through all network interfaces. + * + * @return the number of bytes received through all network interfaces + */ + public static long getTotalRxBytes() { + return getTotalStat("rx_bytes"); + } + + /** + * Gets network bytes sent for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. + * + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count + */ + public static long getUidTxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); + } + + /** + * Gets network bytes received for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. + * + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count + */ + public static long getUidRxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); + } + + private static String TAG = "netstat"; + private static final byte[] buf = new byte[16]; + + private static long getTotalStat(String whatStat) { + File netdir = new File("/sys/class/net"); + + File[] nets = netdir.listFiles(); + if (nets == null) { + return 0; + } + long total = 0; + StringBuffer strbuf = new StringBuffer(); + for (File net : nets) { + strbuf.append(net.getPath()).append(File.separator).append("statistics") + .append(File.separator).append(whatStat); + total += getNumberFromFilePath(strbuf.toString()); + strbuf.setLength(0); + } + return total; + } + + private static long getMobileStat(String whatStat) { + String filename = "/sys/class/net/rmnet0/statistics/" + whatStat; + RandomAccessFile raf = getFile(filename); + if (raf == null) { + filename = "/sys/class/net/ppp0/statistics/" + whatStat; + raf = getFile(filename); + } + if (raf == null) { + return 0L; + } + return getNumberFromFile(raf, filename); + } + + // File will have format + private static long getNumberFromFilePath(String filename) { + RandomAccessFile raf = getFile(filename); + if (raf == null) { + return 0L; + } + return getNumberFromFile(raf, filename); + } + + private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { + try { + raf.read(buf); + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception getting TCP bytes from " + filename, e); + return 0L; + } finally { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception closing " + filename, e); + } + } + } + + long num = 0L; + for (int i = 0; i < buf.length; i++) { + if (buf[i] < '0' || buf[i] > '9') { + break; + } + num *= 10; + num += buf[i] - '0'; + } + return num; + } + + private static RandomAccessFile getFile(String filename) { + File f = new File(filename); + if (!f.canRead()) { + return null; + } + + try { + return new RandomAccessFile(f, "r"); + } catch (IOException e) { + Log.w(TAG, "Exception opening TCP statistics file " + filename, e); + return null; + } + } } From 61456276395fd5ec5cfdd01bc7afc7e6d09b6d07 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:45 -0800 Subject: [PATCH 0003/1150] auto import from //depot/cupcake/@135843 --- core/java/android/os/NetStat.java | 212 ------------------------------ 1 file changed, 212 deletions(-) delete mode 100644 core/java/android/os/NetStat.java diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java deleted file mode 100644 index 733137a32c..0000000000 --- a/core/java/android/os/NetStat.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; - -import java.io.File; -import java.io.RandomAccessFile; -import java.io.IOException; - -/** @hide */ -public class NetStat{ - - /** - * Get total number of tx packets sent through rmnet0 or ppp0 - * - * @return number of Tx packets through rmnet0 or ppp0 - */ - public static long getMobileTxPkts() { - return getMobileStat("tx_packets"); - } - - /** - * Get total number of rx packets received through rmnet0 or ppp0 - * - * @return number of Rx packets through rmnet0 or ppp0 - */ - public static long getMobileRxPkts() { - return getMobileStat("rx_packets"); - } - - /** - * Get total number of tx bytes received through rmnet0 or ppp0 - * - * @return number of Tx bytes through rmnet0 or ppp0 - */ - public static long getMobileTxBytes() { - return getMobileStat("tx_bytes"); - } - - /** - * Get total number of rx bytes received through rmnet0 or ppp0 - * - * @return number of Rx bytes through rmnet0 or ppp0 - */ - public static long getMobileRxBytes() { - return getMobileStat("rx_bytes"); - } - - /** - * Get the total number of packets sent through all network interfaces. - * - * @return the number of packets sent through all network interfaces - */ - public static long getTotalTxPkts() { - return getTotalStat("tx_packets"); - } - - /** - * Get the total number of packets received through all network interfaces. - * - * @return the number of packets received through all network interfaces - */ - public static long getTotalRxPkts() { - return getTotalStat("rx_packets"); - } - - /** - * Get the total number of bytes sent through all network interfaces. - * - * @return the number of bytes sent through all network interfaces - */ - public static long getTotalTxBytes() { - return getTotalStat("tx_bytes"); - } - - /** - * Get the total number of bytes received through all network interfaces. - * - * @return the number of bytes received through all network interfaces - */ - public static long getTotalRxBytes() { - return getTotalStat("rx_bytes"); - } - - /** - * Gets network bytes sent for this UID. - * The statistics are across all interfaces. - * The statistics come from /proc/uid_stat. - * - * {@see android.os.Process#myUid()}. - * - * @param uid - * @return byte count - */ - public static long getUidTxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); - } - - /** - * Gets network bytes received for this UID. - * The statistics are across all interfaces. - * The statistics come from /proc/uid_stat. - * - * {@see android.os.Process#myUid()}. - * - * @param uid - * @return byte count - */ - public static long getUidRxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); - } - - private static String TAG = "netstat"; - private static final byte[] buf = new byte[16]; - - private static long getTotalStat(String whatStat) { - File netdir = new File("/sys/class/net"); - - File[] nets = netdir.listFiles(); - if (nets == null) { - return 0; - } - long total = 0; - StringBuffer strbuf = new StringBuffer(); - for (File net : nets) { - strbuf.append(net.getPath()).append(File.separator).append("statistics") - .append(File.separator).append(whatStat); - total += getNumberFromFilePath(strbuf.toString()); - strbuf.setLength(0); - } - return total; - } - - private static long getMobileStat(String whatStat) { - String filename = "/sys/class/net/rmnet0/statistics/" + whatStat; - RandomAccessFile raf = getFile(filename); - if (raf == null) { - filename = "/sys/class/net/ppp0/statistics/" + whatStat; - raf = getFile(filename); - } - if (raf == null) { - return 0L; - } - return getNumberFromFile(raf, filename); - } - - // File will have format - private static long getNumberFromFilePath(String filename) { - RandomAccessFile raf = getFile(filename); - if (raf == null) { - return 0L; - } - return getNumberFromFile(raf, filename); - } - - private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { - try { - raf.read(buf); - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception getting TCP bytes from " + filename, e); - return 0L; - } finally { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception closing " + filename, e); - } - } - } - - long num = 0L; - for (int i = 0; i < buf.length; i++) { - if (buf[i] < '0' || buf[i] > '9') { - break; - } - num *= 10; - num += buf[i] - '0'; - } - return num; - } - - private static RandomAccessFile getFile(String filename) { - File f = new File(filename); - if (!f.canRead()) { - return null; - } - - try { - return new RandomAccessFile(f, "r"); - } catch (IOException e) { - Log.w(TAG, "Exception opening TCP statistics file " + filename, e); - return null; - } - } -} From ac96dda631c3eca805485cd0fc555aefce175239 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 19:31:44 -0800 Subject: [PATCH 0004/1150] auto import from //depot/cupcake/@135843 --- core/java/android/os/NetStat.java | 247 ++++++++++++++++++++++++++++++ 1 file changed, 247 insertions(+) create mode 100644 core/java/android/os/NetStat.java diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java new file mode 100644 index 0000000000..e294cdf11c --- /dev/null +++ b/core/java/android/os/NetStat.java @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.util.Log; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.IOException; + +/** @hide */ +public class NetStat { + + // Logging tag. + private final static String TAG = "netstat"; + + // We pre-create all the File objects so we don't spend a lot of + // CPU at runtime converting from Java Strings to byte[] for the + // kernel calls. + private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets"); + private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets"); + private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes"); + private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes"); + private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net"); + + /** + * Get total number of tx packets sent through rmnet0 or ppp0 + * + * @return number of Tx packets through rmnet0 or ppp0 + */ + public static long getMobileTxPkts() { + return getMobileStat(MOBILE_TX_PACKETS); + } + + /** + * Get total number of rx packets received through rmnet0 or ppp0 + * + * @return number of Rx packets through rmnet0 or ppp0 + */ + public static long getMobileRxPkts() { + return getMobileStat(MOBILE_RX_PACKETS); + } + + /** + * Get total number of tx bytes received through rmnet0 or ppp0 + * + * @return number of Tx bytes through rmnet0 or ppp0 + */ + public static long getMobileTxBytes() { + return getMobileStat(MOBILE_TX_BYTES); + } + + /** + * Get total number of rx bytes received through rmnet0 or ppp0 + * + * @return number of Rx bytes through rmnet0 or ppp0 + */ + public static long getMobileRxBytes() { + return getMobileStat(MOBILE_RX_BYTES); + } + + /** + * Get the total number of packets sent through all network interfaces. + * + * @return the number of packets sent through all network interfaces + */ + public static long getTotalTxPkts() { + return getTotalStat("tx_packets"); + } + + /** + * Get the total number of packets received through all network interfaces. + * + * @return the number of packets received through all network interfaces + */ + public static long getTotalRxPkts() { + return getTotalStat("rx_packets"); + } + + /** + * Get the total number of bytes sent through all network interfaces. + * + * @return the number of bytes sent through all network interfaces + */ + public static long getTotalTxBytes() { + return getTotalStat("tx_bytes"); + } + + /** + * Get the total number of bytes received through all network interfaces. + * + * @return the number of bytes received through all network interfaces + */ + public static long getTotalRxBytes() { + return getTotalStat("rx_bytes"); + } + + /** + * Gets network bytes sent for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. + * + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count + */ + public static long getUidTxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); + } + + /** + * Gets network bytes received for this UID. + * The statistics are across all interfaces. + * The statistics come from /proc/uid_stat. + * + * {@see android.os.Process#myUid()}. + * + * @param uid + * @return byte count + */ + public static long getUidRxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); + } + + /** + * Returns the array of two possible File locations for a given + * statistic. + */ + private static File[] mobileFiles(String whatStat) { + // Note that we stat them at runtime to see which is + // available, rather than here, to guard against the files + // coming & going later as modules shut down (e.g. airplane + // mode) and whatnot. The runtime stat() isn't expensive compared + // to the previous charset conversion that happened before we + // were reusing File instances. + File[] files = new File[2]; + files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat); + files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat); + return files; + } + + private static long getTotalStat(String whatStat) { + File netdir = new File("/sys/class/net"); + + File[] nets = SYS_CLASS_NET_DIR.listFiles(); + if (nets == null) { + return 0; + } + long total = 0; + StringBuffer strbuf = new StringBuffer(); + for (File net : nets) { + strbuf.append(net.getPath()).append(File.separator).append("statistics") + .append(File.separator).append(whatStat); + total += getNumberFromFilePath(strbuf.toString()); + strbuf.setLength(0); + } + return total; + } + + private static long getMobileStat(File[] files) { + for (int i = 0; i < files.length; i++) { + File file = files[i]; + if (!file.exists()) { + continue; + } + try { + RandomAccessFile raf = new RandomAccessFile(file, "r"); + return getNumberFromFile(raf, file.getAbsolutePath()); + } catch (IOException e) { + Log.w(TAG, + "Exception opening TCP statistics file " + file.getAbsolutePath(), + e); + } + } + return 0L; + } + + // File will have format + private static long getNumberFromFilePath(String filename) { + RandomAccessFile raf = getFile(filename); + if (raf == null) { + return 0L; + } + return getNumberFromFile(raf, filename); + } + + // Private buffer for getNumberFromFile. Safe for re-use because + // getNumberFromFile is synchronized. + private final static byte[] buf = new byte[16]; + + private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { + try { + raf.read(buf); + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception getting TCP bytes from " + filename, e); + return 0L; + } finally { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception closing " + filename, e); + } + } + } + + long num = 0L; + for (int i = 0; i < buf.length; i++) { + if (buf[i] < '0' || buf[i] > '9') { + break; + } + num *= 10; + num += buf[i] - '0'; + } + return num; + } + + private static RandomAccessFile getFile(String filename) { + File f = new File(filename); + if (!f.canRead()) { + return null; + } + + try { + return new RandomAccessFile(f, "r"); + } catch (IOException e) { + Log.w(TAG, "Exception opening TCP statistics file " + filename, e); + return null; + } + } +} From ae521152dd42f959de21edca423fd88cfaa17eb9 Mon Sep 17 00:00:00 2001 From: Ken Shirriff Date: Mon, 7 Dec 2009 15:56:05 -0800 Subject: [PATCH 0005/1150] Add TrafficStats class to SDK. This class (a rename of NetStat) provides network byte and packet statistics. NetStat will be removed separately, to avoid breaking other packages when submitting. --- core/java/android/net/TrafficStats.java | 265 ++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 core/java/android/net/TrafficStats.java diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java new file mode 100644 index 0000000000..62e9f1f04f --- /dev/null +++ b/core/java/android/net/TrafficStats.java @@ -0,0 +1,265 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.util.Log; + +import java.io.File; +import java.io.RandomAccessFile; +import java.io.IOException; + +/** + * Class that provides network traffic statistics. These statistics include bytes transmitted and + * received and network packets transmitted and received, over all interfaces, over the mobile + * interface, and on a per-UID basis. + *

+ * These statistics may not be available on all platforms. If the statistics are not supported + * by this device, {@link #UNSUPPORTED} will be returned. + */ +public class TrafficStats { + /** + * The return value to indicate that the device does not support the statistic. + */ + public final static int UNSUPPORTED = -1; + + // Logging tag. + private final static String TAG = "trafficstats"; + + // We pre-create all the File objects so we don't spend a lot of + // CPU at runtime converting from Java Strings to byte[] for the + // kernel calls. + private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets"); + private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets"); + private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes"); + private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes"); + private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net"); + + /** + * Get the total number of packets transmitted through the mobile interface. + * + * @return number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getMobileTxPkts() { + return getMobileStat(MOBILE_TX_PACKETS); + } + + /** + * Get the total number of packets received through the mobile interface. + * + * @return number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getMobileRxPkts() { + return getMobileStat(MOBILE_RX_PACKETS); + } + + /** + * Get the total number of bytes transmitted through the mobile interface. + * + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getMobileTxBytes() { + return getMobileStat(MOBILE_TX_BYTES); + } + + /** + * Get the total number of bytes received through the mobile interface. + * + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getMobileRxBytes() { + return getMobileStat(MOBILE_RX_BYTES); + } + + /** + * Get the total number of packets sent through all network interfaces. + * + * @return the number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getTotalTxPkts() { + return getTotalStat("tx_packets"); + } + + /** + * Get the total number of packets received through all network interfaces. + * + * @return number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getTotalRxPkts() { + return getTotalStat("rx_packets"); + } + + /** + * Get the total number of bytes sent through all network interfaces. + * + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getTotalTxBytes() { + return getTotalStat("tx_bytes"); + } + + /** + * Get the total number of bytes received through all network interfaces. + * + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getTotalRxBytes() { + return getTotalStat("rx_bytes"); + } + + /** + * Get the number of bytes sent through the network for this UID. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static long getUidTxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); + } + + /** + * Get the number of bytes received through the network for this UID. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes + */ + public static long getUidRxBytes(int uid) { + return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); + } + + /** + * Returns the array of two possible File locations for a given + * statistic. + */ + private static File[] mobileFiles(String whatStat) { + // Note that we stat them at runtime to see which is + // available, rather than here, to guard against the files + // coming & going later as modules shut down (e.g. airplane + // mode) and whatnot. The runtime stat() isn't expensive compared + // to the previous charset conversion that happened before we + // were reusing File instances. + File[] files = new File[2]; + files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat); + files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat); + return files; + } + + private static long getTotalStat(String whatStat) { + File netdir = new File("/sys/class/net"); + + File[] nets = SYS_CLASS_NET_DIR.listFiles(); + if (nets == null) { + return UNSUPPORTED; + } + long total = 0; + StringBuffer strbuf = new StringBuffer(); + for (File net : nets) { + strbuf.append(net.getPath()).append(File.separator).append("statistics") + .append(File.separator).append(whatStat); + total += getNumberFromFilePath(strbuf.toString()); + strbuf.setLength(0); + } + return total; + } + + private static long getMobileStat(File[] files) { + for (int i = 0; i < files.length; i++) { + File file = files[i]; + if (!file.exists()) { + continue; + } + try { + RandomAccessFile raf = new RandomAccessFile(file, "r"); + return getNumberFromFile(raf, file.getAbsolutePath()); + } catch (IOException e) { + Log.w(TAG, + "Exception opening TCP statistics file " + file.getAbsolutePath(), + e); + } + } + return UNSUPPORTED; + } + + // File will have format + private static long getNumberFromFilePath(String filename) { + RandomAccessFile raf = getFile(filename); + if (raf == null) { + return UNSUPPORTED; + } + return getNumberFromFile(raf, filename); + } + + // Private buffer for getNumberFromFile. Safe for re-use because + // getNumberFromFile is synchronized. + private final static byte[] buf = new byte[16]; + + private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { + try { + raf.read(buf); + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception getting TCP bytes from " + filename, e); + return UNSUPPORTED; + } finally { + if (raf != null) { + try { + raf.close(); + } catch (IOException e) { + Log.w(TAG, "Exception closing " + filename, e); + } + } + } + + long num = 0L; + for (int i = 0; i < buf.length; i++) { + if (buf[i] < '0' || buf[i] > '9') { + break; + } + num *= 10; + num += buf[i] - '0'; + } + return num; + } + + private static RandomAccessFile getFile(String filename) { + File f = new File(filename); + if (!f.canRead()) { + return null; + } + + try { + return new RandomAccessFile(f, "r"); + } catch (IOException e) { + Log.w(TAG, "Exception opening TCP statistics file " + filename, e); + return null; + } + } +} From c640964e95ac6581964885fd516b349d9cd9f688 Mon Sep 17 00:00:00 2001 From: Ken Shirriff Date: Mon, 7 Dec 2009 15:57:35 -0800 Subject: [PATCH 0006/1150] Migration to TrafficStats. TrafficStats is the SDK version of NetStat. --- core/java/android/os/NetStat.java | 247 ------------------------------ 1 file changed, 247 deletions(-) delete mode 100644 core/java/android/os/NetStat.java diff --git a/core/java/android/os/NetStat.java b/core/java/android/os/NetStat.java deleted file mode 100644 index e294cdf11c..0000000000 --- a/core/java/android/os/NetStat.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os; - -import android.util.Log; - -import java.io.File; -import java.io.RandomAccessFile; -import java.io.IOException; - -/** @hide */ -public class NetStat { - - // Logging tag. - private final static String TAG = "netstat"; - - // We pre-create all the File objects so we don't spend a lot of - // CPU at runtime converting from Java Strings to byte[] for the - // kernel calls. - private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets"); - private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets"); - private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes"); - private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes"); - private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net"); - - /** - * Get total number of tx packets sent through rmnet0 or ppp0 - * - * @return number of Tx packets through rmnet0 or ppp0 - */ - public static long getMobileTxPkts() { - return getMobileStat(MOBILE_TX_PACKETS); - } - - /** - * Get total number of rx packets received through rmnet0 or ppp0 - * - * @return number of Rx packets through rmnet0 or ppp0 - */ - public static long getMobileRxPkts() { - return getMobileStat(MOBILE_RX_PACKETS); - } - - /** - * Get total number of tx bytes received through rmnet0 or ppp0 - * - * @return number of Tx bytes through rmnet0 or ppp0 - */ - public static long getMobileTxBytes() { - return getMobileStat(MOBILE_TX_BYTES); - } - - /** - * Get total number of rx bytes received through rmnet0 or ppp0 - * - * @return number of Rx bytes through rmnet0 or ppp0 - */ - public static long getMobileRxBytes() { - return getMobileStat(MOBILE_RX_BYTES); - } - - /** - * Get the total number of packets sent through all network interfaces. - * - * @return the number of packets sent through all network interfaces - */ - public static long getTotalTxPkts() { - return getTotalStat("tx_packets"); - } - - /** - * Get the total number of packets received through all network interfaces. - * - * @return the number of packets received through all network interfaces - */ - public static long getTotalRxPkts() { - return getTotalStat("rx_packets"); - } - - /** - * Get the total number of bytes sent through all network interfaces. - * - * @return the number of bytes sent through all network interfaces - */ - public static long getTotalTxBytes() { - return getTotalStat("tx_bytes"); - } - - /** - * Get the total number of bytes received through all network interfaces. - * - * @return the number of bytes received through all network interfaces - */ - public static long getTotalRxBytes() { - return getTotalStat("rx_bytes"); - } - - /** - * Gets network bytes sent for this UID. - * The statistics are across all interfaces. - * The statistics come from /proc/uid_stat. - * - * {@see android.os.Process#myUid()}. - * - * @param uid - * @return byte count - */ - public static long getUidTxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); - } - - /** - * Gets network bytes received for this UID. - * The statistics are across all interfaces. - * The statistics come from /proc/uid_stat. - * - * {@see android.os.Process#myUid()}. - * - * @param uid - * @return byte count - */ - public static long getUidRxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); - } - - /** - * Returns the array of two possible File locations for a given - * statistic. - */ - private static File[] mobileFiles(String whatStat) { - // Note that we stat them at runtime to see which is - // available, rather than here, to guard against the files - // coming & going later as modules shut down (e.g. airplane - // mode) and whatnot. The runtime stat() isn't expensive compared - // to the previous charset conversion that happened before we - // were reusing File instances. - File[] files = new File[2]; - files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat); - files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat); - return files; - } - - private static long getTotalStat(String whatStat) { - File netdir = new File("/sys/class/net"); - - File[] nets = SYS_CLASS_NET_DIR.listFiles(); - if (nets == null) { - return 0; - } - long total = 0; - StringBuffer strbuf = new StringBuffer(); - for (File net : nets) { - strbuf.append(net.getPath()).append(File.separator).append("statistics") - .append(File.separator).append(whatStat); - total += getNumberFromFilePath(strbuf.toString()); - strbuf.setLength(0); - } - return total; - } - - private static long getMobileStat(File[] files) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; - if (!file.exists()) { - continue; - } - try { - RandomAccessFile raf = new RandomAccessFile(file, "r"); - return getNumberFromFile(raf, file.getAbsolutePath()); - } catch (IOException e) { - Log.w(TAG, - "Exception opening TCP statistics file " + file.getAbsolutePath(), - e); - } - } - return 0L; - } - - // File will have format - private static long getNumberFromFilePath(String filename) { - RandomAccessFile raf = getFile(filename); - if (raf == null) { - return 0L; - } - return getNumberFromFile(raf, filename); - } - - // Private buffer for getNumberFromFile. Safe for re-use because - // getNumberFromFile is synchronized. - private final static byte[] buf = new byte[16]; - - private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { - try { - raf.read(buf); - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception getting TCP bytes from " + filename, e); - return 0L; - } finally { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception closing " + filename, e); - } - } - } - - long num = 0L; - for (int i = 0; i < buf.length; i++) { - if (buf[i] < '0' || buf[i] > '9') { - break; - } - num *= 10; - num += buf[i] - '0'; - } - return num; - } - - private static RandomAccessFile getFile(String filename) { - File f = new File(filename); - if (!f.canRead()) { - return null; - } - - try { - return new RandomAccessFile(f, "r"); - } catch (IOException e) { - Log.w(TAG, "Exception opening TCP statistics file " + filename, e); - return null; - } - } -} From 85923343827cd1306639438fd6a71a5c5eb8b59e Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 12 Jan 2010 12:18:49 -0800 Subject: [PATCH 0007/1150] services: Introduce NativeDaemonConnector class This class provides an interface to communicate with native daemons using the libsysutils framework communication code. Signed-off-by: San Mehat NativeDaemonConnector: fix whitespace Signed-off-by: San Mehat NativeDaemonConnector: Fix review comments Signed-off-by: San Mehat NativeDaemonConnector: On an error, re-try the connection Signed-off-by: San Mehat --- .../INativeDaemonConnectorCallbacks.java | 24 ++ .../android/server/NativeDaemonConnector.java | 239 ++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 services/java/com/android/server/INativeDaemonConnectorCallbacks.java create mode 100644 services/java/com/android/server/NativeDaemonConnector.java diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java new file mode 100644 index 0000000000..6fbf713d3f --- /dev/null +++ b/services/java/com/android/server/INativeDaemonConnectorCallbacks.java @@ -0,0 +1,24 @@ + +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +interface INativeDaemonConnectorCallbacks { + + void onDaemonConnected(); + boolean onEvent(int code, String raw, String[] cooked); +} diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java new file mode 100644 index 0000000000..da3e562fb5 --- /dev/null +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -0,0 +1,239 @@ +/* + * Copyright (C) 2007 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.net.LocalSocketAddress; +import android.net.LocalSocket; +import android.os.Environment; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.util.Config; +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.lang.IllegalStateException; + +import java.util.List; +import java.util.ArrayList; +import java.util.ListIterator; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +/** + * Generic connector class for interfacing with a native + * daemon which uses the libsysutils FrameworkListener + * protocol. + */ +final class NativeDaemonConnector implements Runnable { + + private BlockingQueue mResponseQueue; + private OutputStream mOutputStream; + private String TAG = "NativeDaemonConnector"; + private String mSocket; + private INativeDaemonConnectorCallbacks mCallbacks; + + class ResponseCode { + public static final int ActionInitiated = 100; + + public static final int CommandOkay = 200; + + // The range of 400 -> 599 is reserved for cmd failures + public static final int OperationFailed = 400; + public static final int CommandSyntaxError = 500; + public static final int CommandParameterError = 501; + + public static final int UnsolicitedInformational = 600; + + // + public static final int FailedRangeStart = 400; + public static final int FailedRangeEnd = 599; + } + + NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, + String socket, int responseQueueSize, String logTag) { + mCallbacks = callbacks; + if (logTag != null) + TAG = logTag; + mSocket = socket; + mResponseQueue = new LinkedBlockingQueue(responseQueueSize); + } + + public void run() { + + while (true) { + try { + listenToSocket(); + } catch (Exception e) { + Log.e(TAG, "Error in NativeDaemonConnector", e); + SystemClock.sleep(1000); + } + } + } + + private void listenToSocket() { + LocalSocket socket = null; + + try { + socket = new LocalSocket(); + LocalSocketAddress address = new LocalSocketAddress(mSocket, + LocalSocketAddress.Namespace.RESERVED); + + socket.connect(address); + mCallbacks.onDaemonConnected(); + + InputStream inputStream = socket.getInputStream(); + mOutputStream = socket.getOutputStream(); + + byte[] buffer = new byte[4096]; + + while (true) { + int count = inputStream.read(buffer); + if (count < 0) break; + + int start = 0; + for (int i = 0; i < count; i++) { + if (buffer[i] == 0) { + String event = new String(buffer, start, i - start); +// Log.d(TAG, "Got packet {" + event + "}"); + + String[] tokens = event.split(" "); + try { + int code = Integer.parseInt(tokens[0]); + + if (code >= ResponseCode.UnsolicitedInformational) { + try { + if (!mCallbacks.onEvent(code, event, tokens)) { + Log.w(TAG, String.format( + "Unhandled event (%s)", event)); + } + } catch (Exception ex) { + Log.e(TAG, String.format( + "Error handling '%s'", event), ex); + } + } else { + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Log.e(TAG, "Failed to put response onto queue", ex); + } + } + } catch (NumberFormatException nfe) { + Log.w(TAG, String.format("Bad msg (%s)", event)); + } + start = i + 1; + } + } + } + } catch (IOException ex) { + Log.e(TAG, "Communications error", ex); + } + + synchronized (this) { + if (mOutputStream != null) { + try { + mOutputStream.close(); + } catch (IOException e) { + Log.w(TAG, "Failed closing output stream", e); + } + + mOutputStream = null; + } + } + + try { + if (socket != null) { + socket.close(); + } + } catch (IOException ex) { + Log.w(TAG, "Failed closing socket", ex); + } + + Log.e(TAG, "Failed to connect to native daemon", + new IllegalStateException()); + SystemClock.sleep(5000); + } + + private void sendCommand(String command) { + sendCommand(command, null); + } + + /** + * Sends a command to the daemon with a single argument + * + * @param command The command to send to the daemon + * @param argument The argument to send with the command (or null) + */ + private void sendCommand(String command, String argument) { + synchronized (this) { + Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}"); + if (mOutputStream == null) { + Log.e(TAG, "No connection to daemon", new IllegalStateException()); + } else { + StringBuilder builder = new StringBuilder(command); + if (argument != null) { + builder.append(argument); + } + builder.append('\0'); + + try { + mOutputStream.write(builder.toString().getBytes()); + } catch (IOException ex) { + Log.e(TAG, "IOException in sendCommand", ex); + } + } + } + } + + public synchronized ArrayList doCommand(String cmd) throws IllegalStateException { + sendCommand(cmd); + + ArrayList response = new ArrayList(); + boolean complete = false; + int code = -1; + + while (!complete) { + try { + String line = mResponseQueue.take(); +// Log.d(TAG, "Removed off queue -> " + line); + String[] tokens = line.split(" "); + try { + code = Integer.parseInt(tokens[0]); + } catch (NumberFormatException nfe) { + throw new IllegalStateException( + String.format("Invalid response from daemon (%s)", line)); + } + + if ((code >= 200) && (code < 600)) + complete = true; + response.add(line); + } catch (InterruptedException ex) { + Log.e(TAG, "InterruptedException"); + } + } + + if (code >= ResponseCode.FailedRangeStart && + code <= ResponseCode.FailedRangeEnd) { + throw new IllegalStateException(String.format( + "Command %s failed with code %d", + cmd, code)); + } + return response; + } +} From 4a32297c1e0b22b0d18a7eac55a9fdf65b20b632 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 20 Jan 2010 15:14:31 -0800 Subject: [PATCH 0008/1150] NativeDaemonConnector: Add a convenience method for obtaining lists Signed-off-by: San Mehat --- .../android/server/NativeDaemonConnector.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index da3e562fb5..98e00dc11f 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -201,6 +201,9 @@ final class NativeDaemonConnector implements Runnable { } } + /** + * Issue a command to the native daemon and return the responses + */ public synchronized ArrayList doCommand(String cmd) throws IllegalStateException { sendCommand(cmd); @@ -236,4 +239,38 @@ final class NativeDaemonConnector implements Runnable { } return response; } + + /* + * Issues a list command and returns the cooked list + */ + public String[] doListCommand(String cmd, int expectedResponseCode) + throws IllegalStateException { + + ArrayList rsp = doCommand(cmd); + String[] rdata = new String[rsp.size()-1]; + int idx = 0; + + for (String line : rsp) { + try { + String[] tok = line.split(" "); + int code = Integer.parseInt(tok[0]); + if (code == expectedResponseCode) { + if (tok.length !=2) { + throw new IllegalStateException( + String.format("Malformatted list entry '%s'", line)); + } + rdata[idx++] = tok[1]; + } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { + return rdata; + } else { + throw new IllegalStateException( + String.format("Expected list response %d, but got %d", + expectedResponseCode, code)); + } + } catch (NumberFormatException nfe) { + throw new IllegalStateException(String.format("Error reading code '%s'", line)); + } + } + throw new IllegalStateException("Got an empty response"); + } } From f2b0adabbdaaa091ca3ca38e684e574072443080 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Tue, 26 Jan 2010 12:48:39 -0800 Subject: [PATCH 0009/1150] NativeDaemonConnector: fix doListCommand() to return *all* list elements Signed-off-by: San Mehat --- services/java/com/android/server/NativeDaemonConnector.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 98e00dc11f..92ba5f80d5 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -255,11 +255,7 @@ final class NativeDaemonConnector implements Runnable { String[] tok = line.split(" "); int code = Integer.parseInt(tok[0]); if (code == expectedResponseCode) { - if (tok.length !=2) { - throw new IllegalStateException( - String.format("Malformatted list entry '%s'", line)); - } - rdata[idx++] = tok[1]; + rdata[idx++] = line.substring(tok[0].length() + 1); } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { return rdata; } else { From 0e0980b533290c15c5782a400ab17ed1a43aaa53 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Fri, 29 Jan 2010 05:22:17 -0800 Subject: [PATCH 0010/1150] NativeDaemonConnector: Cleanup socket code and use a proper exception Signed-off-by: San Mehat --- .../android/server/NativeDaemonConnector.java | 61 +++++++++---------- .../NativeDaemonConnectorException.java | 42 +++++++++++++ 2 files changed, 71 insertions(+), 32 deletions(-) create mode 100644 services/java/com/android/server/NativeDaemonConnectorException.java diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 92ba5f80d5..016aa52ac7 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -28,7 +28,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; -import java.lang.IllegalStateException; import java.util.List; import java.util.ArrayList; @@ -82,12 +81,12 @@ final class NativeDaemonConnector implements Runnable { listenToSocket(); } catch (Exception e) { Log.e(TAG, "Error in NativeDaemonConnector", e); - SystemClock.sleep(1000); + SystemClock.sleep(5000); } } } - private void listenToSocket() { + private void listenToSocket() throws IOException { LocalSocket socket = null; try { @@ -143,31 +142,27 @@ final class NativeDaemonConnector implements Runnable { } } catch (IOException ex) { Log.e(TAG, "Communications error", ex); - } - - synchronized (this) { - if (mOutputStream != null) { - try { - mOutputStream.close(); - } catch (IOException e) { - Log.w(TAG, "Failed closing output stream", e); + throw ex; + } finally { + synchronized (this) { + if (mOutputStream != null) { + try { + mOutputStream.close(); + } catch (IOException e) { + Log.w(TAG, "Failed closing output stream", e); + } + mOutputStream = null; } + } - mOutputStream = null; + try { + if (socket != null) { + socket.close(); + } + } catch (IOException ex) { + Log.w(TAG, "Failed closing socket", ex); } } - - try { - if (socket != null) { - socket.close(); - } - } catch (IOException ex) { - Log.w(TAG, "Failed closing socket", ex); - } - - Log.e(TAG, "Failed to connect to native daemon", - new IllegalStateException()); - SystemClock.sleep(5000); } private void sendCommand(String command) { @@ -204,7 +199,8 @@ final class NativeDaemonConnector implements Runnable { /** * Issue a command to the native daemon and return the responses */ - public synchronized ArrayList doCommand(String cmd) throws IllegalStateException { + public synchronized ArrayList doCommand(String cmd) + throws NativeDaemonConnectorException { sendCommand(cmd); ArrayList response = new ArrayList(); @@ -214,12 +210,12 @@ final class NativeDaemonConnector implements Runnable { while (!complete) { try { String line = mResponseQueue.take(); -// Log.d(TAG, "Removed off queue -> " + line); + Log.d(TAG, String.format("RSP -> {%s}", line)); String[] tokens = line.split(" "); try { code = Integer.parseInt(tokens[0]); } catch (NumberFormatException nfe) { - throw new IllegalStateException( + throw new NativeDaemonConnectorException( String.format("Invalid response from daemon (%s)", line)); } @@ -233,7 +229,7 @@ final class NativeDaemonConnector implements Runnable { if (code >= ResponseCode.FailedRangeStart && code <= ResponseCode.FailedRangeEnd) { - throw new IllegalStateException(String.format( + throw new NativeDaemonConnectorException(code, String.format( "Command %s failed with code %d", cmd, code)); } @@ -244,7 +240,7 @@ final class NativeDaemonConnector implements Runnable { * Issues a list command and returns the cooked list */ public String[] doListCommand(String cmd, int expectedResponseCode) - throws IllegalStateException { + throws NativeDaemonConnectorException { ArrayList rsp = doCommand(cmd); String[] rdata = new String[rsp.size()-1]; @@ -259,14 +255,15 @@ final class NativeDaemonConnector implements Runnable { } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { return rdata; } else { - throw new IllegalStateException( + throw new NativeDaemonConnectorException( String.format("Expected list response %d, but got %d", expectedResponseCode, code)); } } catch (NumberFormatException nfe) { - throw new IllegalStateException(String.format("Error reading code '%s'", line)); + throw new NativeDaemonConnectorException( + String.format("Error reading code '%s'", line)); } } - throw new IllegalStateException("Got an empty response"); + throw new NativeDaemonConnectorException("Got an empty response"); } } diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/java/com/android/server/NativeDaemonConnectorException.java new file mode 100644 index 0000000000..e60aaf8685 --- /dev/null +++ b/services/java/com/android/server/NativeDaemonConnectorException.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +/** + * An exception that indicates there was an error with a NativeDaemonConnector operation + */ +public class NativeDaemonConnectorException extends RuntimeException +{ + private int mCode = -1; + + public NativeDaemonConnectorException() {} + + public NativeDaemonConnectorException(String error) + { + super(error); + } + + public NativeDaemonConnectorException(int code, String error) + { + super(error); + mCode = code; + } + + public int getCode() { + return mCode; + } +} From a52a7439598a82dfdef460407bfad1ae288e66ba Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 3 Feb 2010 10:48:21 -0800 Subject: [PATCH 0011/1150] NativeDaemonConnector: Improve NativeDaemonException reporting to include the actual error response Signed-off-by: San Mehat --- .../com/android/server/NativeDaemonConnector.java | 14 +++++++++----- .../server/NativeDaemonConnectorException.java | 10 ++++++++-- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 016aa52ac7..9a066d3d66 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -219,19 +219,23 @@ final class NativeDaemonConnector implements Runnable { String.format("Invalid response from daemon (%s)", line)); } - if ((code >= 200) && (code < 600)) + if ((code >= 200) && (code < 600)) { complete = true; + } response.add(line); } catch (InterruptedException ex) { - Log.e(TAG, "InterruptedException"); + Log.e(TAG, "Failed to process response", ex); } } if (code >= ResponseCode.FailedRangeStart && code <= ResponseCode.FailedRangeEnd) { - throw new NativeDaemonConnectorException(code, String.format( - "Command %s failed with code %d", - cmd, code)); + /* + * Note: The format of the last response in this case is + * "NNN " + */ + throw new NativeDaemonConnectorException( + code, cmd, response.get(response.size()-1).substring(4)); } return response; } diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/java/com/android/server/NativeDaemonConnectorException.java index e60aaf8685..426742b1e2 100644 --- a/services/java/com/android/server/NativeDaemonConnectorException.java +++ b/services/java/com/android/server/NativeDaemonConnectorException.java @@ -22,6 +22,7 @@ package com.android.server; public class NativeDaemonConnectorException extends RuntimeException { private int mCode = -1; + private String mCmd; public NativeDaemonConnectorException() {} @@ -30,13 +31,18 @@ public class NativeDaemonConnectorException extends RuntimeException super(error); } - public NativeDaemonConnectorException(int code, String error) + public NativeDaemonConnectorException(int code, String cmd, String error) { - super(error); + super(String.format("Cmd {%s} failed with code %d : {%s}", cmd, code, error)); mCode = code; + mCmd = cmd; } public int getCode() { return mCode; } + + public String getCmd() { + return mCmd; + } } From c9b5476b73aafc44aeb9f364891f4ac59c98e7fb Mon Sep 17 00:00:00 2001 From: Ken Shirriff Date: Thu, 4 Feb 2010 13:33:45 -0800 Subject: [PATCH 0012/1150] API review: TrafficStats: rename Pkts to Packets Rename getMobileTxPackets(), getMobileRxPackets(), getTotalTxPackets(), getMobileRxPackets() bug 2420318 --- core/java/android/net/TrafficStats.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 62e9f1f04f..ad8e2bffbc 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -54,7 +54,7 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileTxPkts() { + public static long getMobileTxPackets() { return getMobileStat(MOBILE_TX_PACKETS); } @@ -64,7 +64,7 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileRxPkts() { + public static long getMobileRxPackets() { return getMobileStat(MOBILE_RX_PACKETS); } @@ -94,7 +94,7 @@ public class TrafficStats { * @return the number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalTxPkts() { + public static long getTotalTxPackets() { return getTotalStat("tx_packets"); } @@ -104,7 +104,7 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalRxPkts() { + public static long getTotalRxPackets() { return getTotalStat("rx_packets"); } From f0d2199fc73edebd3415a14015e993b52a0d2524 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Thu, 4 Feb 2010 15:09:02 -0800 Subject: [PATCH 0013/1150] NativeDaemonConnector: Improve error reporting and debug formatting Updated: NativeDaemonConnector: Put debugging behind a conditional Signed-off-by: San Mehat --- .../com/android/server/NativeDaemonConnector.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 9a066d3d66..cf083c04f5 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -21,7 +21,6 @@ import android.net.LocalSocket; import android.os.Environment; import android.os.SystemClock; import android.os.SystemProperties; -import android.util.Config; import android.util.Log; import java.io.IOException; @@ -41,6 +40,7 @@ import java.util.concurrent.LinkedBlockingQueue; * protocol. */ final class NativeDaemonConnector implements Runnable { + private static final boolean LOCAL_LOGD = false; private BlockingQueue mResponseQueue; private OutputStream mOutputStream; @@ -110,7 +110,7 @@ final class NativeDaemonConnector implements Runnable { for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); -// Log.d(TAG, "Got packet {" + event + "}"); + if (LOCAL_LOGD) Log.d(TAG, String.format("RCV <- {%s}", event)); String[] tokens = event.split(" "); try { @@ -177,7 +177,7 @@ final class NativeDaemonConnector implements Runnable { */ private void sendCommand(String command, String argument) { synchronized (this) { - Log.d(TAG, "sendCommand {" + command + "} {" + argument + "}"); + if (LOCAL_LOGD) Log.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); if (mOutputStream == null) { Log.e(TAG, "No connection to daemon", new IllegalStateException()); } else { @@ -210,7 +210,7 @@ final class NativeDaemonConnector implements Runnable { while (!complete) { try { String line = mResponseQueue.take(); - Log.d(TAG, String.format("RSP -> {%s}", line)); + if (LOCAL_LOGD) Log.d(TAG, String.format("RSP <- {%s}", line)); String[] tokens = line.split(" "); try { code = Integer.parseInt(tokens[0]); @@ -250,13 +250,18 @@ final class NativeDaemonConnector implements Runnable { String[] rdata = new String[rsp.size()-1]; int idx = 0; - for (String line : rsp) { + for (int i = 0; i < rsp.size(); i++) { + String line = rsp.get(i); try { String[] tok = line.split(" "); int code = Integer.parseInt(tok[0]); if (code == expectedResponseCode) { rdata[idx++] = line.substring(tok[0].length() + 1); } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { + if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line)); + if (i != rsp.size()) { + Log.w(TAG, String.format("Recv'd %d lines after list term", (rsp.size()-i))); + } return rdata; } else { throw new NativeDaemonConnectorException( From 6eec2a8bf517487ab8445812dc1559bc7ad5b173 Mon Sep 17 00:00:00 2001 From: San Mehat Date: Wed, 17 Feb 2010 09:03:29 -0800 Subject: [PATCH 0014/1150] NativeDaemonConnector: Improve bad list IPC diagnostics Signed-off-by: San Mehat --- .../java/com/android/server/NativeDaemonConnector.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index cf083c04f5..ceae973199 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -259,8 +259,12 @@ final class NativeDaemonConnector implements Runnable { rdata[idx++] = line.substring(tok[0].length() + 1); } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line)); - if (i != rsp.size()) { - Log.w(TAG, String.format("Recv'd %d lines after list term", (rsp.size()-i))); + int last = rsp.size() -1; + if (i != last) { + Log.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd)); + for (int j = i; j <= last ; j++) { + Log.w(TAG, String.format("ExtraData <%s>", rsp.get(i))); + } } return rdata; } else { From f7791634a205427f98075919151509c535f5b9ed Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Fri, 26 Feb 2010 18:56:32 -0800 Subject: [PATCH 0015/1150] Switch the services library to using the new Slog --- .../android/server/NativeDaemonConnector.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index ceae973199..39c847ab22 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -21,7 +21,7 @@ import android.net.LocalSocket; import android.os.Environment; import android.os.SystemClock; import android.os.SystemProperties; -import android.util.Log; +import android.util.Slog; import java.io.IOException; import java.io.InputStream; @@ -80,7 +80,7 @@ final class NativeDaemonConnector implements Runnable { try { listenToSocket(); } catch (Exception e) { - Log.e(TAG, "Error in NativeDaemonConnector", e); + Slog.e(TAG, "Error in NativeDaemonConnector", e); SystemClock.sleep(5000); } } @@ -110,7 +110,7 @@ final class NativeDaemonConnector implements Runnable { for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); - if (LOCAL_LOGD) Log.d(TAG, String.format("RCV <- {%s}", event)); + if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event)); String[] tokens = event.split(" "); try { @@ -119,29 +119,29 @@ final class NativeDaemonConnector implements Runnable { if (code >= ResponseCode.UnsolicitedInformational) { try { if (!mCallbacks.onEvent(code, event, tokens)) { - Log.w(TAG, String.format( + Slog.w(TAG, String.format( "Unhandled event (%s)", event)); } } catch (Exception ex) { - Log.e(TAG, String.format( + Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } } else { try { mResponseQueue.put(event); } catch (InterruptedException ex) { - Log.e(TAG, "Failed to put response onto queue", ex); + Slog.e(TAG, "Failed to put response onto queue", ex); } } } catch (NumberFormatException nfe) { - Log.w(TAG, String.format("Bad msg (%s)", event)); + Slog.w(TAG, String.format("Bad msg (%s)", event)); } start = i + 1; } } } } catch (IOException ex) { - Log.e(TAG, "Communications error", ex); + Slog.e(TAG, "Communications error", ex); throw ex; } finally { synchronized (this) { @@ -149,7 +149,7 @@ final class NativeDaemonConnector implements Runnable { try { mOutputStream.close(); } catch (IOException e) { - Log.w(TAG, "Failed closing output stream", e); + Slog.w(TAG, "Failed closing output stream", e); } mOutputStream = null; } @@ -160,7 +160,7 @@ final class NativeDaemonConnector implements Runnable { socket.close(); } } catch (IOException ex) { - Log.w(TAG, "Failed closing socket", ex); + Slog.w(TAG, "Failed closing socket", ex); } } } @@ -177,9 +177,9 @@ final class NativeDaemonConnector implements Runnable { */ private void sendCommand(String command, String argument) { synchronized (this) { - if (LOCAL_LOGD) Log.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); + if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); if (mOutputStream == null) { - Log.e(TAG, "No connection to daemon", new IllegalStateException()); + Slog.e(TAG, "No connection to daemon", new IllegalStateException()); } else { StringBuilder builder = new StringBuilder(command); if (argument != null) { @@ -190,7 +190,7 @@ final class NativeDaemonConnector implements Runnable { try { mOutputStream.write(builder.toString().getBytes()); } catch (IOException ex) { - Log.e(TAG, "IOException in sendCommand", ex); + Slog.e(TAG, "IOException in sendCommand", ex); } } } @@ -210,7 +210,7 @@ final class NativeDaemonConnector implements Runnable { while (!complete) { try { String line = mResponseQueue.take(); - if (LOCAL_LOGD) Log.d(TAG, String.format("RSP <- {%s}", line)); + if (LOCAL_LOGD) Slog.d(TAG, String.format("RSP <- {%s}", line)); String[] tokens = line.split(" "); try { code = Integer.parseInt(tokens[0]); @@ -224,7 +224,7 @@ final class NativeDaemonConnector implements Runnable { } response.add(line); } catch (InterruptedException ex) { - Log.e(TAG, "Failed to process response", ex); + Slog.e(TAG, "Failed to process response", ex); } } @@ -258,12 +258,12 @@ final class NativeDaemonConnector implements Runnable { if (code == expectedResponseCode) { rdata[idx++] = line.substring(tok[0].length() + 1); } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { - if (LOCAL_LOGD) Log.d(TAG, String.format("List terminated with {%s}", line)); + if (LOCAL_LOGD) Slog.d(TAG, String.format("List terminated with {%s}", line)); int last = rsp.size() -1; if (i != last) { - Log.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd)); + Slog.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd)); for (int j = i; j <= last ; j++) { - Log.w(TAG, String.format("ExtraData <%s>", rsp.get(i))); + Slog.w(TAG, String.format("ExtraData <%s>", rsp.get(i))); } } return rdata; From 07726310aefaf6477824bc300caa9d89ce04f595 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Mon, 22 Mar 2010 18:02:45 -0700 Subject: [PATCH 0016/1150] Compact when NativeDaemonConnector hits buffer limit If NativeDaemonConnector hits its buffer limit, it would truncate the data and lose some information. This change compacts the buffer and then retries to read the rest of the data. Change-Id: I0d5fee097bdd6808212ef3ad6fb4abbc6310fd4a --- .../android/server/NativeDaemonConnector.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 39c847ab22..08d7ce6b30 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -48,6 +48,8 @@ final class NativeDaemonConnector implements Runnable { private String mSocket; private INativeDaemonConnectorCallbacks mCallbacks; + private final int BUFFER_SIZE = 4096; + class ResponseCode { public static final int ActionInitiated = 100; @@ -87,7 +89,7 @@ final class NativeDaemonConnector implements Runnable { } private void listenToSocket() throws IOException { - LocalSocket socket = null; + LocalSocket socket = null; try { socket = new LocalSocket(); @@ -100,13 +102,13 @@ final class NativeDaemonConnector implements Runnable { InputStream inputStream = socket.getInputStream(); mOutputStream = socket.getOutputStream(); - byte[] buffer = new byte[4096]; + byte[] buffer = new byte[BUFFER_SIZE]; + int start = 0; while (true) { - int count = inputStream.read(buffer); + int count = inputStream.read(buffer, start, BUFFER_SIZE - start); if (count < 0) break; - int start = 0; for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); @@ -139,6 +141,13 @@ final class NativeDaemonConnector implements Runnable { start = i + 1; } } + if (start != count) { + final int remaining = BUFFER_SIZE - start; + System.arraycopy(buffer, start, buffer, 0, remaining); + start = remaining; + } else { + start = 0; + } } } catch (IOException ex) { Slog.e(TAG, "Communications error", ex); From eaeb70241c8741c91b25e4b48df8ae27eea008fa Mon Sep 17 00:00:00 2001 From: Dan Egnor Date: Wed, 7 Apr 2010 17:30:50 -0700 Subject: [PATCH 0017/1150] Change TrafficStats to a new JNI implementation. Also change phone's ConnectionStateTrackers to use it directly, rather than through the INetStat binder interface. Bug: 2578938 Change-Id: I8858e2609cbec3be845a0ce5178cb03f67e01b41 --- core/java/android/net/TrafficStats.java | 170 +++--------------------- core/jni/android_net_TrafficStats.cpp | 165 +++++++++++++++++++++++ 2 files changed, 180 insertions(+), 155 deletions(-) create mode 100644 core/jni/android_net_TrafficStats.cpp diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ad8e2bffbc..0d64dab179 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -23,12 +23,12 @@ import java.io.RandomAccessFile; import java.io.IOException; /** - * Class that provides network traffic statistics. These statistics include bytes transmitted and - * received and network packets transmitted and received, over all interfaces, over the mobile - * interface, and on a per-UID basis. + * Class that provides network traffic statistics. These statistics include + * bytes transmitted and received and network packets transmitted and received, + * over all interfaces, over the mobile interface, and on a per-UID basis. *

- * These statistics may not be available on all platforms. If the statistics are not supported - * by this device, {@link #UNSUPPORTED} will be returned. + * These statistics may not be available on all platforms. If the statistics + * are not supported by this device, {@link #UNSUPPORTED} will be returned. */ public class TrafficStats { /** @@ -36,27 +36,13 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - // Logging tag. - private final static String TAG = "trafficstats"; - - // We pre-create all the File objects so we don't spend a lot of - // CPU at runtime converting from Java Strings to byte[] for the - // kernel calls. - private final static File[] MOBILE_TX_PACKETS = mobileFiles("tx_packets"); - private final static File[] MOBILE_RX_PACKETS = mobileFiles("rx_packets"); - private final static File[] MOBILE_TX_BYTES = mobileFiles("tx_bytes"); - private final static File[] MOBILE_RX_BYTES = mobileFiles("rx_bytes"); - private final static File SYS_CLASS_NET_DIR = new File("/sys/class/net"); - /** * Get the total number of packets transmitted through the mobile interface. * * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileTxPackets() { - return getMobileStat(MOBILE_TX_PACKETS); - } + public static native long getMobileTxPackets(); /** * Get the total number of packets received through the mobile interface. @@ -64,9 +50,7 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileRxPackets() { - return getMobileStat(MOBILE_RX_PACKETS); - } + public static native long getMobileRxPackets(); /** * Get the total number of bytes transmitted through the mobile interface. @@ -74,9 +58,7 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileTxBytes() { - return getMobileStat(MOBILE_TX_BYTES); - } + public static native long getMobileTxBytes(); /** * Get the total number of bytes received through the mobile interface. @@ -84,9 +66,7 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getMobileRxBytes() { - return getMobileStat(MOBILE_RX_BYTES); - } + public static native long getMobileRxBytes(); /** * Get the total number of packets sent through all network interfaces. @@ -94,9 +74,7 @@ public class TrafficStats { * @return the number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalTxPackets() { - return getTotalStat("tx_packets"); - } + public static native long getTotalTxPackets(); /** * Get the total number of packets received through all network interfaces. @@ -104,9 +82,7 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalRxPackets() { - return getTotalStat("rx_packets"); - } + public static native long getTotalRxPackets(); /** * Get the total number of bytes sent through all network interfaces. @@ -114,9 +90,7 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalTxBytes() { - return getTotalStat("tx_bytes"); - } + public static native long getTotalTxBytes(); /** * Get the total number of bytes received through all network interfaces. @@ -124,9 +98,7 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getTotalRxBytes() { - return getTotalStat("rx_bytes"); - } + public static native long getTotalRxBytes(); /** * Get the number of bytes sent through the network for this UID. @@ -138,9 +110,7 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static long getUidTxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_snd"); - } + public static native long getUidTxBytes(int uid); /** * Get the number of bytes received through the network for this UID. @@ -151,115 +121,5 @@ public class TrafficStats { * @param uid The UID of the process to examine. * @return number of bytes */ - public static long getUidRxBytes(int uid) { - return getNumberFromFilePath("/proc/uid_stat/" + uid + "/tcp_rcv"); - } - - /** - * Returns the array of two possible File locations for a given - * statistic. - */ - private static File[] mobileFiles(String whatStat) { - // Note that we stat them at runtime to see which is - // available, rather than here, to guard against the files - // coming & going later as modules shut down (e.g. airplane - // mode) and whatnot. The runtime stat() isn't expensive compared - // to the previous charset conversion that happened before we - // were reusing File instances. - File[] files = new File[2]; - files[0] = new File("/sys/class/net/rmnet0/statistics/" + whatStat); - files[1] = new File("/sys/class/net/ppp0/statistics/" + whatStat); - return files; - } - - private static long getTotalStat(String whatStat) { - File netdir = new File("/sys/class/net"); - - File[] nets = SYS_CLASS_NET_DIR.listFiles(); - if (nets == null) { - return UNSUPPORTED; - } - long total = 0; - StringBuffer strbuf = new StringBuffer(); - for (File net : nets) { - strbuf.append(net.getPath()).append(File.separator).append("statistics") - .append(File.separator).append(whatStat); - total += getNumberFromFilePath(strbuf.toString()); - strbuf.setLength(0); - } - return total; - } - - private static long getMobileStat(File[] files) { - for (int i = 0; i < files.length; i++) { - File file = files[i]; - if (!file.exists()) { - continue; - } - try { - RandomAccessFile raf = new RandomAccessFile(file, "r"); - return getNumberFromFile(raf, file.getAbsolutePath()); - } catch (IOException e) { - Log.w(TAG, - "Exception opening TCP statistics file " + file.getAbsolutePath(), - e); - } - } - return UNSUPPORTED; - } - - // File will have format - private static long getNumberFromFilePath(String filename) { - RandomAccessFile raf = getFile(filename); - if (raf == null) { - return UNSUPPORTED; - } - return getNumberFromFile(raf, filename); - } - - // Private buffer for getNumberFromFile. Safe for re-use because - // getNumberFromFile is synchronized. - private final static byte[] buf = new byte[16]; - - private static synchronized long getNumberFromFile(RandomAccessFile raf, String filename) { - try { - raf.read(buf); - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception getting TCP bytes from " + filename, e); - return UNSUPPORTED; - } finally { - if (raf != null) { - try { - raf.close(); - } catch (IOException e) { - Log.w(TAG, "Exception closing " + filename, e); - } - } - } - - long num = 0L; - for (int i = 0; i < buf.length; i++) { - if (buf[i] < '0' || buf[i] > '9') { - break; - } - num *= 10; - num += buf[i] - '0'; - } - return num; - } - - private static RandomAccessFile getFile(String filename) { - File f = new File(filename); - if (!f.canRead()) { - return null; - } - - try { - return new RandomAccessFile(f, "r"); - } catch (IOException e) { - Log.w(TAG, "Exception opening TCP statistics file " + filename, e); - return null; - } - } + public static native long getUidRxBytes(int uid); } diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp new file mode 100644 index 0000000000..db8fdf2d4b --- /dev/null +++ b/core/jni/android_net_TrafficStats.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "TrafficStats" + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace android { + +// Returns an ASCII decimal number read from the specified file, -1 on error. +static jlong readNumber(char const* filename) { + char buf[80]; + int fd = open(filename, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) LOGE("Can't open %s: %s", filename, strerror(errno)); + return -1; + } + + int len = read(fd, buf, sizeof(buf) - 1); + if (len < 0) { + LOGE("Can't read %s: %s", filename, strerror(errno)); + close(fd); + return -1; + } + + close(fd); + buf[len] = '\0'; + return atoll(buf); +} + +// Return the number from the first file which exists and contains data +static jlong tryBoth(char const* a, char const* b) { + jlong num = readNumber(a); + return num >= 0 ? num : readNumber(b); +} + +// Returns the sum of numbers from the specified path under /sys/class/net/*, +// -1 if no such file exists. +static jlong readTotal(char const* suffix) { + char filename[PATH_MAX] = "/sys/class/net/"; + DIR *dir = opendir(filename); + if (dir == NULL) { + LOGE("Can't list %s: %s", filename, strerror(errno)); + return -1; + } + + int len = strlen(filename); + jlong total = -1; + while (struct dirent *entry = readdir(dir)) { + // Skip ., .., and localhost interfaces. + if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) { + strlcpy(filename + len, entry->d_name, sizeof(filename) - len); + strlcat(filename, suffix, sizeof(filename)); + jlong num = readNumber(filename); + if (num >= 0) total = total < 0 ? num : total + num; + } + } + + closedir(dir); + return total; +} + +// Mobile stats get accessed a lot more often than total stats. +// Note the individual files can come and go at runtime, so we check +// each file every time (rather than caching which ones exist). + +static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/tx_packets", + "/sys/class/net/ppp0/statistics/tx_packets"); +} + +static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/rx_packets", + "/sys/class/net/ppp0/statistics/rx_packets"); +} + +static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/tx_bytes", + "/sys/class/net/ppp0/statistics/tx_bytes"); +} + +static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { + return tryBoth( + "/sys/class/net/rmnet0/statistics/rx_bytes", + "/sys/class/net/ppp0/statistics/rx_bytes"); +} + +// Total stats are read less often, so we're willing to put up +// with listing the directory and concatenating filenames. + +static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/tx_packets"); +} + +static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/rx_packets"); +} + +static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/tx_bytes"); +} + +static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { + return readTotal("/statistics/rx_bytes"); +} + +// Per-UID stats require reading from a constructed filename. + +static jlong getUidRxBytes(JNIEnv* env, jobject clazz, jint uid) { + char filename[80]; + sprintf(filename, "/proc/uid_stat/%d/tcp_rcv", uid); + return readNumber(filename); +} + +static jlong getUidTxBytes(JNIEnv* env, jobject clazz, jint uid) { + char filename[80]; + sprintf(filename, "/proc/uid_stat/%d/tcp_snd", uid); + return readNumber(filename); +} + +static JNINativeMethod gMethods[] = { + {"getMobileTxPackets", "()J", (void*) getMobileTxPackets}, + {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, + {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, + {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, + {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, + {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, + {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, + {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, + {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, + {"getUidRxBytes", "(I)J", (void*) getUidRxBytes}, +}; + +int register_android_net_TrafficStats(JNIEnv* env) { + return AndroidRuntime::registerNativeMethods(env, "android/net/TrafficStats", + gMethods, NELEM(gMethods)); +} + +} From 71d780a711d579f956158ded18a61ec3a2dd4333 Mon Sep 17 00:00:00 2001 From: Dan Egnor Date: Thu, 8 Apr 2010 23:46:28 -0700 Subject: [PATCH 0018/1150] Fix sim build (sim doesn't have strl*() reliably...) Just stub out the TrafficStats code for the sim. Bug: 2578938 Change-Id: Ie555f67f581d05ee446ea29cb2223feb350c52f9 --- core/jni/android_net_TrafficStats.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index db8fdf2d4b..ff46bdd2ba 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -32,6 +32,7 @@ namespace android { // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { +#ifdef HAVE_ANDROID_OS char buf[80]; int fd = open(filename, O_RDONLY); if (fd < 0) { @@ -49,6 +50,9 @@ static jlong readNumber(char const* filename) { close(fd); buf[len] = '\0'; return atoll(buf); +#else // Simulator + return -1; +#endif } // Return the number from the first file which exists and contains data @@ -60,6 +64,7 @@ static jlong tryBoth(char const* a, char const* b) { // Returns the sum of numbers from the specified path under /sys/class/net/*, // -1 if no such file exists. static jlong readTotal(char const* suffix) { +#ifdef HAVE_ANDROID_OS char filename[PATH_MAX] = "/sys/class/net/"; DIR *dir = opendir(filename); if (dir == NULL) { @@ -81,6 +86,9 @@ static jlong readTotal(char const* suffix) { closedir(dir); return total; +#else // Simulator + return -1; +#endif } // Mobile stats get accessed a lot more often than total stats. From ef79060f4eed964cc801541f6b68e3966abb8990 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 1 Jun 2010 13:23:53 -0700 Subject: [PATCH 0019/1150] Add more error checking for ndc In NativeDaemonConnector.doCommand() calls, there was inconsistent error checking. This change adds error checking for every call and makes it so that any call to .doCommand() that gets an error code won't cause the code to hang forever. Change-Id: I4584953a759a48ad16adfe8ee9e564b5f5796680 --- .../com/android/server/NativeDaemonConnector.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 08d7ce6b30..c45259064c 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -128,12 +128,11 @@ final class NativeDaemonConnector implements Runnable { Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } - } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); - } + } + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue", ex); } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); From eeeaf73a023f66463f83f7048f98cc40a626e59a Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 1 Jun 2010 13:23:53 -0700 Subject: [PATCH 0020/1150] Add more error checking for ndc In NativeDaemonConnector.doCommand() calls, there was inconsistent error checking. This change adds error checking for every call and makes it so that any call to .doCommand() that gets an error code won't cause the code to hang forever. Change-Id: If714282b6642f278fb8137f652af1a012670253b --- .../com/android/server/NativeDaemonConnector.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 08d7ce6b30..c45259064c 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -128,12 +128,11 @@ final class NativeDaemonConnector implements Runnable { Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } - } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); - } + } + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue", ex); } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); From 877d231382b8dc08d32fb66f6e02faeb1953f660 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Tue, 1 Jun 2010 13:23:53 -0700 Subject: [PATCH 0021/1150] Add more error checking for ndc In NativeDaemonConnector.doCommand() calls, there was inconsistent error checking. This change adds error checking for every call and makes it so that any call to .doCommand() that gets an error code won't cause the code to hang forever. Change-Id: If714282b6642f278fb8137f652af1a012670253b --- .../com/android/server/NativeDaemonConnector.java | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 08d7ce6b30..c45259064c 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -128,12 +128,11 @@ final class NativeDaemonConnector implements Runnable { Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } - } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); - } + } + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue", ex); } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); From 405d5ff48273d038d27dd6a6c2a5a7f56d152d51 Mon Sep 17 00:00:00 2001 From: Danica Chang Date: Wed, 11 Aug 2010 14:54:43 -0700 Subject: [PATCH 0022/1150] bluetooth tethering Change-Id: Id6d5fb1922facc7013abc29214d3e1141995b767 --- .../com/android/server/NativeDaemonConnector.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c45259064c..249c32b8c2 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -128,11 +128,12 @@ final class NativeDaemonConnector implements Runnable { Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } - } - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); + } else { + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue", ex); + } } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); @@ -209,6 +210,7 @@ final class NativeDaemonConnector implements Runnable { */ public synchronized ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { + mResponseQueue.clear(); sendCommand(cmd); ArrayList response = new ArrayList(); From d347480a1898155fda11ad14323d5dc67344f2c3 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 2 Sep 2010 22:18:14 -0700 Subject: [PATCH 0023/1150] Fix buffer compacting in NativeDaemonConnector The buffer was being compacted in the read loop, but the start offset on the compacted buffer wasn't being considered after the next read. Bug: 2501075 Change-Id: I163297d751cf800d0bbc66df66b1a0fa0785de49 --- .../java/com/android/server/NativeDaemonConnector.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c45259064c..f3cb9b7828 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -109,6 +109,10 @@ final class NativeDaemonConnector implements Runnable { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); if (count < 0) break; + // Add our starting point to the count and reset the start. + count += start; + start = 0; + for (int i = 0; i < count; i++) { if (buffer[i] == 0) { String event = new String(buffer, start, i - start); @@ -140,6 +144,9 @@ final class NativeDaemonConnector implements Runnable { start = i + 1; } } + + // We should end at the amount we read. If not, compact then + // buffer and read again. if (start != count) { final int remaining = BUFFER_SIZE - start; System.arraycopy(buffer, start, buffer, 0, remaining); From 56451a44778af5f289695808e4c06485f26b4bef Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 22 Sep 2010 14:32:35 -0700 Subject: [PATCH 0024/1150] Cleanup Netd to prevent getting hung. If the sending of the command fails we should note it and not wait forever for the response. We should also not say we're ready until we actually are. bug:2993205 Change-Id: I380f0312ac4693ad184a526b330fdfa23f6ac558 --- .../java/com/android/server/NativeDaemonConnector.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index f3cb9b7828..7b68d68ddf 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -180,7 +180,8 @@ final class NativeDaemonConnector implements Runnable { } } - private void sendCommand(String command) { + private void sendCommand(String command) + throws NativeDaemonConnectorException { sendCommand(command, null); } @@ -190,11 +191,13 @@ final class NativeDaemonConnector implements Runnable { * @param command The command to send to the daemon * @param argument The argument to send with the command (or null) */ - private void sendCommand(String command, String argument) { + private void sendCommand(String command, String argument) + throws NativeDaemonConnectorException { synchronized (this) { if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); if (mOutputStream == null) { Slog.e(TAG, "No connection to daemon", new IllegalStateException()); + throw new NativeDaemonConnectorException("No output stream!"); } else { StringBuilder builder = new StringBuilder(command); if (argument != null) { @@ -224,6 +227,7 @@ final class NativeDaemonConnector implements Runnable { while (!complete) { try { + // TODO - this should not block forever String line = mResponseQueue.take(); if (LOCAL_LOGD) Slog.d(TAG, String.format("RSP <- {%s}", line)); String[] tokens = line.split(" "); From bc1c40a4846136ab2dfb6d558bb0a43ac6294030 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Sun, 16 Jan 2011 14:31:55 -0800 Subject: [PATCH 0025/1150] Do not add unsolicited events to queue Adding unsolicited events to response queue results in doCommand() returning the wrong result. Pulling this change from master. Bug: 3258529 Change-Id: I2a4b0bd8bb30b31682d7d61ee94a0d246bf10de2 --- .../com/android/server/NativeDaemonConnector.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 7b68d68ddf..cf87a9d393 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -132,11 +132,12 @@ final class NativeDaemonConnector implements Runnable { Slog.e(TAG, String.format( "Error handling '%s'", event), ex); } - } - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); + } else { + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue", ex); + } } } catch (NumberFormatException nfe) { Slog.w(TAG, String.format("Bad msg (%s)", event)); @@ -219,6 +220,7 @@ final class NativeDaemonConnector implements Runnable { */ public synchronized ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { + mResponseQueue.clear(); sendCommand(cmd); ArrayList response = new ArrayList(); From df852d886071e109afc3dab17c1576811a9a6a01 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Thu, 27 Jan 2011 15:52:38 -0800 Subject: [PATCH 0026/1150] TrafficStats: Include UDP stats and packet count to API Change-Id: I70063e6033d3c181bcc5b9e401f9474900e25281 Signed-off-by: Ashish Sharma --- core/java/android/net/TrafficStats.java | 135 ++++++++++++++++++++ core/jni/android_net_TrafficStats.cpp | 157 +++++++++++++++++++++++- 2 files changed, 286 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 0d64dab179..0492fcec85 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -122,4 +122,139 @@ public class TrafficStats { * @return number of bytes */ public static native long getUidRxBytes(int uid); + + /** + * Get the number of packets (TCP segments + UDP) sent through + * the network for this UID. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of packets. + * If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidTxPackets(int uid); + + /** + * Get the number of packets (TCP segments + UDP) received through + * the network for this UID. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of packets + */ + public static native long getUidRxPackets(int uid); + + /** + * Get the number of TCP payload bytes sent for this UID. + * This total does not include protocol and control overheads at + * the transport and the lower layers of the networking stack. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidTcpTxBytes(int uid); + + /** + * Get the number of TCP payload bytes received for this UID. + * This total does not include protocol and control overheads at + * the transport and the lower layers of the networking stack. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidTcpRxBytes(int uid); + + /** + * Get the number of UDP payload bytes sent for this UID. + * This total does not include protocol and control overheads at + * the transport and the lower layers of the networking stack. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidUdpTxBytes(int uid); + + /** + * Get the number of UDP payload bytes received for this UID. + * This total does not include protocol and control overheads at + * the transport and the lower layers of the networking stack. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of bytes. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidUdpRxBytes(int uid); + + /** + * Get the number of TCP segments sent for this UID. + * Does not include TCP control packets (SYN/ACKs/FIN/..). + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of TCP segments. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidTcpTxSegments(int uid); + + /** + * Get the number of TCP payload bytes received for this UID. + * Does not include TCP control packets (SYN/ACKs/FIN/..). + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of TCP segments. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidTcpRxSegments(int uid); + + + /** + * Get the number of UDP packets sent for this UID. + * Includes DNS requests. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidUdpTxPackets(int uid); + + /** + * Get the number of UDP packets received for this UID. + * Includes DNS responses. + * The statistics are across all interfaces. + * + * {@see android.os.Process#myUid()}. + * + * @param uid The UID of the process to examine. + * @return number of packets. If the statistics are not supported by this device, + * {@link #UNSUPPORTED} will be returned. + */ + public static native long getUidUdpRxPackets(int uid); } diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index ff46bdd2ba..dfa36cee81 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -30,6 +30,17 @@ namespace android { +enum Tx_Rx { + TX, + RX +}; + +enum Tcp_Udp { + TCP, + UDP, + TCP_AND_UDP +}; + // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { #ifdef HAVE_ANDROID_OS @@ -140,16 +151,136 @@ static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { // Per-UID stats require reading from a constructed filename. +static jlong getUidBytes(JNIEnv* env, jobject clazz, jint uid, + enum Tx_Rx tx_or_rx, enum Tcp_Udp tcp_or_udp) { + char tcp_filename[80], udp_filename[80]; + jlong tcp_bytes = -1, udp_bytes = -1, total_bytes = -1; + + switch (tx_or_rx) { + case TX: + sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_snd", uid); + sprintf(udp_filename, "/proc/uid_stat/%d/udp_snd", uid); + break; + case RX: + sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_rcv", uid); + sprintf(udp_filename, "/proc/uid_stat/%d/udp_rcv", uid); + break; + default: + return -1; + } + + switch (tcp_or_udp) { + case TCP: + tcp_bytes = readNumber(tcp_filename); + total_bytes = (tcp_bytes >= 0) ? tcp_bytes : -1; + break; + case UDP: + udp_bytes = readNumber(udp_filename); + total_bytes = (udp_bytes >= 0) ? udp_bytes : -1; + break; + case TCP_AND_UDP: + tcp_bytes = readNumber(tcp_filename); + total_bytes += (tcp_bytes >= 0 ? tcp_bytes : 0); + + udp_bytes = readNumber(udp_filename); + total_bytes += (udp_bytes >= 0 ? udp_bytes : 0); + break; + default: + return -1; + } + + return total_bytes; +} + +static jlong getUidPkts(JNIEnv* env, jobject clazz, jint uid, + enum Tx_Rx tx_or_rx, enum Tcp_Udp tcp_or_udp) { + char tcp_filename[80], udp_filename[80]; + jlong tcp_pkts = -1, udp_pkts = -1, total_pkts = -1; + + switch (tx_or_rx) { + case TX: + sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_snd_pkt", uid); + sprintf(udp_filename, "/proc/uid_stat/%d/udp_snd_pkt", uid); + break; + case RX: + sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_rcv_pkt", uid); + sprintf(udp_filename, "/proc/uid_stat/%d/udp_rcv_pkt", uid); + break; + default: + return -1; + } + + switch (tcp_or_udp) { + case TCP: + tcp_pkts = readNumber(tcp_filename); + total_pkts = (tcp_pkts >= 0) ? tcp_pkts : -1; + break; + case UDP: + udp_pkts = readNumber(udp_filename); + total_pkts = (udp_pkts >= 0) ? udp_pkts : -1; + break; + case TCP_AND_UDP: + tcp_pkts = readNumber(tcp_filename); + total_pkts += (tcp_pkts >= 0 ? tcp_pkts : 0); + + udp_pkts = readNumber(udp_filename); + total_pkts += (udp_pkts >= 0 ? udp_pkts : 0); + break; + default: + return -1; + } + + return total_pkts; +} + static jlong getUidRxBytes(JNIEnv* env, jobject clazz, jint uid) { - char filename[80]; - sprintf(filename, "/proc/uid_stat/%d/tcp_rcv", uid); - return readNumber(filename); + return getUidBytes(env, clazz, uid, RX, TCP_AND_UDP); } static jlong getUidTxBytes(JNIEnv* env, jobject clazz, jint uid) { - char filename[80]; - sprintf(filename, "/proc/uid_stat/%d/tcp_snd", uid); - return readNumber(filename); + return getUidBytes(env, clazz, uid, TX, TCP_AND_UDP); +} + +/* TCP Segments + UDP Packets */ +static jlong getUidTxPackets(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, TX, TCP_AND_UDP); +} + +/* TCP Segments + UDP Packets */ +static jlong getUidRxPackets(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, RX, TCP_AND_UDP); +} + +static jlong getUidTcpTxBytes(JNIEnv* env, jobject clazz, jint uid) { + return getUidBytes(env, clazz, uid, TX, TCP); +} + +static jlong getUidTcpRxBytes(JNIEnv* env, jobject clazz, jint uid) { + return getUidBytes(env, clazz, uid, RX, TCP); +} + +static jlong getUidUdpTxBytes(JNIEnv* env, jobject clazz, jint uid) { + return getUidBytes(env, clazz, uid, TX, UDP); +} + +static jlong getUidUdpRxBytes(JNIEnv* env, jobject clazz, jint uid) { + return getUidBytes(env, clazz, uid, RX, UDP); +} + +static jlong getUidTcpTxSegments(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, TX, TCP); +} + +static jlong getUidTcpRxSegments(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, RX, TCP); +} + +static jlong getUidUdpTxPackets(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, TX, UDP); +} + +static jlong getUidUdpRxPackets(JNIEnv* env, jobject clazz, jint uid) { + return getUidPkts(env, clazz, uid, RX, UDP); } static JNINativeMethod gMethods[] = { @@ -161,8 +292,22 @@ static JNINativeMethod gMethods[] = { {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, + + /* Per-UID Stats */ {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, {"getUidRxBytes", "(I)J", (void*) getUidRxBytes}, + {"getUidTxPackets", "(I)J", (void*) getUidTxPackets}, + {"getUidRxPackets", "(I)J", (void*) getUidRxPackets}, + + {"getUidTcpTxBytes", "(I)J", (void*) getUidTcpTxBytes}, + {"getUidTcpRxBytes", "(I)J", (void*) getUidTcpRxBytes}, + {"getUidUdpTxBytes", "(I)J", (void*) getUidUdpTxBytes}, + {"getUidUdpRxBytes", "(I)J", (void*) getUidUdpRxBytes}, + + {"getUidTcpTxSegments", "(I)J", (void*) getUidTcpTxSegments}, + {"getUidTcpRxSegments", "(I)J", (void*) getUidTcpRxSegments}, + {"getUidUdpTxPackets", "(I)J", (void*) getUidUdpTxPackets}, + {"getUidUdpRxPackets", "(I)J", (void*) getUidUdpRxPackets}, }; int register_android_net_TrafficStats(JNIEnv* env) { From 2e11488c900e6b6581ad4bd741fc61f024fc6e29 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Mon, 31 Jan 2011 14:29:42 -0800 Subject: [PATCH 0027/1150] Fix a minor documentation bug in TrafficStats. Change-Id: I3cf2199797d875ccb6ab432c298afaace44c7527 Signed-off-by: Ashish Sharma --- core/java/android/net/TrafficStats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 0492fcec85..d143243469 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -219,7 +219,7 @@ public class TrafficStats { public static native long getUidTcpTxSegments(int uid); /** - * Get the number of TCP payload bytes received for this UID. + * Get the number of TCP segments received for this UID. * Does not include TCP control packets (SYN/ACKs/FIN/..). * The statistics are across all interfaces. * From c4faee0b101024538754b8254cf4c057554f2bea Mon Sep 17 00:00:00 2001 From: anga Date: Tue, 1 Feb 2011 14:10:25 +0100 Subject: [PATCH 0028/1150] Fix a race condition in NativeDaemonConnector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes a race between the onDaemonConnected callback and setting the mOutputStream in NativeDaemonConnector. MountService connects to vold using the NativeDaemonConnector. Throws a “NativeDaemonConnectorException: No output stream!” when the onDaemonConnected callback in MountService calls the doListCommand. Change-Id: Ib895bab37f7df680e4362df6366198c0a673c5e9 --- services/java/com/android/server/NativeDaemonConnector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 7b68d68ddf..c0c6c36854 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -97,11 +97,12 @@ final class NativeDaemonConnector implements Runnable { LocalSocketAddress.Namespace.RESERVED); socket.connect(address); - mCallbacks.onDaemonConnected(); InputStream inputStream = socket.getInputStream(); mOutputStream = socket.getOutputStream(); + mCallbacks.onDaemonConnected(); + byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; From 042f4e10f093d207313ee35018cbb22afdb5626f Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Tue, 15 Feb 2011 19:30:27 -0800 Subject: [PATCH 0029/1150] data activity reporting on wifi Initial checkin, need icons to complete the feature Bug: 3412258 Change-Id: I9a3ecc8159cc314d84707065dafe23d402409a84 --- core/java/android/net/TrafficStats.java | 37 +++++++++++++++++++++++++ core/jni/android_net_TrafficStats.cpp | 31 +++++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index d143243469..eca06c50dd 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -68,6 +68,43 @@ public class TrafficStats { */ public static native long getMobileRxBytes(); + /** + * Get the total number of packets transmitted through the specified interface. + * + * @return number of packets. If the statistics are not supported by this interface, + * {@link #UNSUPPORTED} will be returned. + * @hide + */ + public static native long getTxPackets(String iface); + + /** + * Get the total number of packets received through the specified interface. + * + * @return number of packets. If the statistics are not supported by this interface, + * {@link #UNSUPPORTED} will be returned. + * @hide + */ + public static native long getRxPackets(String iface); + + /** + * Get the total number of bytes transmitted through the specified interface. + * + * @return number of bytes. If the statistics are not supported by this interface, + * {@link #UNSUPPORTED} will be returned. + * @hide + */ + public static native long getTxBytes(String iface); + + /** + * Get the total number of bytes received through the specified interface. + * + * @return number of bytes. If the statistics are not supported by this interface, + * {@link #UNSUPPORTED} will be returned. + * @hide + */ + public static native long getRxBytes(String iface); + + /** * Get the total number of packets sent through all network interfaces. * diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index dfa36cee81..0c84f1138e 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -130,6 +130,33 @@ static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { "/sys/class/net/ppp0/statistics/rx_bytes"); } +static jlong getData(JNIEnv* env, char *what, jstring interface) { + char filename[80]; + jboolean isCopy; + + const char *interfaceStr = env->GetStringUTFChars(interface, &isCopy); + snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interfaceStr, what); + + return readNumber(filename); +} + +static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) { + return getData(env, "tx_packets", interface); +} + +static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) { + return getData(env, "rx_packets", interface); +} + +static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) { + return getData(env, "tx_bytes", interface); +} + +static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) { + return getData(env, "rx_bytes", interface); +} + + // Total stats are read less often, so we're willing to put up // with listing the directory and concatenating filenames. @@ -288,6 +315,10 @@ static JNINativeMethod gMethods[] = { {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, + {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets}, + {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets}, + {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes}, + {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes}, {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, From df7efc2c9ff0e19d31ce34ac3dd20a6d4412a3e6 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 12 Apr 2011 16:12:09 -0700 Subject: [PATCH 0030/1150] More native code cleanup. Use ScopedUtfChars (fixes a leak in TrafficStats, and fixes a crash in Wifi in a case where GetStringChars could have been called with a pending exception). Change-Id: I3465ff392b4038dfdafa6af80ec1314cc6d6a11c --- core/jni/android_net_TrafficStats.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 0c84f1138e..203b5efc16 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -130,13 +131,14 @@ static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { "/sys/class/net/ppp0/statistics/rx_bytes"); } -static jlong getData(JNIEnv* env, char *what, jstring interface) { +static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) { + ScopedUtfChars interface(env, javaInterface); + if (interface.c_str() == NULL) { + return -1; + } + char filename[80]; - jboolean isCopy; - - const char *interfaceStr = env->GetStringUTFChars(interface, &isCopy); - snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interfaceStr, what); - + snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what); return readNumber(filename); } From ffd48a2cf8184187d8857d5177717ad2b0480d74 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 26 Apr 2011 16:25:36 -0700 Subject: [PATCH 0031/1150] Return NetworkStats bundle from NM service. Introduce NetworkStats which is a collection of network statistics, which should match the structure communicated by kernel module through netd. Will introduce tags and fg/bg stats later. Kept entirely in a flat data structure to optimize parcel speed. Initial pass at returning NetworkStats from NetworkManagementService, both summary and details. Will eventually pull data from kernel module over netd connection. Change-Id: I92d9f61678ec8c22e2ce26775fb035a0cf32413f --- core/java/android/net/NetworkStats.aidl | 19 +++ core/java/android/net/NetworkStats.java | 158 ++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 core/java/android/net/NetworkStats.aidl create mode 100644 core/java/android/net/NetworkStats.java diff --git a/core/java/android/net/NetworkStats.aidl b/core/java/android/net/NetworkStats.aidl new file mode 100644 index 0000000000..d06ca65a3e --- /dev/null +++ b/core/java/android/net/NetworkStats.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkStats; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java new file mode 100644 index 0000000000..4430e00057 --- /dev/null +++ b/core/java/android/net/NetworkStats.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.SystemClock; + +import java.io.CharArrayWriter; +import java.io.PrintWriter; + +/** + * Collection of network statistics. Can contain summary details across all + * interfaces, or details with per-UID granularity. Designed to parcel quickly + * across process boundaries. + * + * @hide + */ +public class NetworkStats implements Parcelable { + /** {@link #iface} value when entry is summarized over all interfaces. */ + public static final String IFACE_ALL = null; + /** {@link #uid} value when entry is summarized over all UIDs. */ + public static final int UID_ALL = 0; + + /** + * {@link SystemClock#elapsedRealtime()} timestamp when this data was + * generated. + */ + public final long elapsedRealtime; + public final String[] iface; + public final int[] uid; + public final long[] rx; + public final long[] tx; + + // TODO: add fg/bg stats and tag granularity + + private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) { + this.elapsedRealtime = elapsedRealtime; + this.iface = iface; + this.uid = uid; + this.rx = rx; + this.tx = tx; + } + + public NetworkStats(Parcel parcel) { + elapsedRealtime = parcel.readLong(); + iface = parcel.createStringArray(); + uid = parcel.createIntArray(); + rx = parcel.createLongArray(); + tx = parcel.createLongArray(); + } + + public static class Builder { + private long mElapsedRealtime; + private final String[] mIface; + private final int[] mUid; + private final long[] mRx; + private final long[] mTx; + + private int mIndex = 0; + + public Builder(long elapsedRealtime, int size) { + mElapsedRealtime = elapsedRealtime; + mIface = new String[size]; + mUid = new int[size]; + mRx = new long[size]; + mTx = new long[size]; + } + + public void addEntry(String iface, int uid, long rx, long tx) { + mIface[mIndex] = iface; + mUid[mIndex] = uid; + mRx[mIndex] = rx; + mTx[mIndex] = tx; + mIndex++; + } + + public NetworkStats build() { + if (mIndex != mIface.length) { + throw new IllegalArgumentException("unexpected number of entries"); + } + return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx); + } + } + + /** + * Find first stats index that matches the requested parameters. + */ + public int findIndex(String iface, int uid) { + for (int i = 0; i < this.iface.length; i++) { + if (equal(iface, this.iface[i]) && uid == this.uid[i]) { + return i; + } + } + return -1; + } + + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + /** {@inheritDoc} */ + public int describeContents() { + return 0; + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); + for (int i = 0; i < iface.length; i++) { + pw.print(prefix); + pw.print(" iface="); pw.print(iface[i]); + pw.print(" uid="); pw.print(uid[i]); + pw.print(" rx="); pw.print(rx[i]); + pw.print(" tx="); pw.println(tx[i]); + } + } + + @Override + public String toString() { + final CharArrayWriter writer = new CharArrayWriter(); + dump("", new PrintWriter(writer)); + return writer.toString(); + } + + /** {@inheritDoc} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(elapsedRealtime); + dest.writeStringArray(iface); + dest.writeIntArray(uid); + dest.writeLongArray(rx); + dest.writeLongArray(tx); + } + + public static final Creator CREATOR = new Creator() { + public NetworkStats createFromParcel(Parcel in) { + return new NetworkStats(in); + } + + public NetworkStats[] newArray(int size) { + return new NetworkStats[size]; + } + }; +} From b82cd3db7daf3c4dc33fcedd2e0a61cdff6dcf9e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 21 Apr 2011 18:45:43 -0700 Subject: [PATCH 0032/1150] Add Socket tagging for granular data accounting. Introduces public API to apply "tags" to track data traffic originating from the current thread. (Under the hood, the tags are maintained and applied in BlockGuard.) Also adds tag/untag methods for developers who maintain their own Socket pools. Change-Id: Ic2dd3155559a93a7b613c7853748d4c44fb3a39e --- core/java/android/net/TrafficStats.java | 64 +++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index eca06c50dd..7ee7a81f40 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,11 +16,10 @@ package android.net; -import android.util.Log; +import dalvik.system.BlockGuard; -import java.io.File; -import java.io.RandomAccessFile; -import java.io.IOException; +import java.net.Socket; +import java.net.SocketException; /** * Class that provides network traffic statistics. These statistics include @@ -36,6 +35,63 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; + /** + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. Only one active tag per thread is supported. + *

+ * Changes only take effect during subsequent calls to + * {@link #tagSocket(Socket)}. + */ + public static void setThreadStatsTag(String tag) { + BlockGuard.setThreadSocketStatsTag(tag); + } + + public static void clearThreadStatsTag() { + BlockGuard.setThreadSocketStatsTag(null); + } + + /** + * Set specific UID to use when accounting {@link Socket} traffic + * originating from the current thread. Designed for use when performing an + * operation on behalf of another application. + *

+ * Changes only take effect during subsequent calls to + * {@link #tagSocket(Socket)}. + *

+ * To take effect, caller must hold + * {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission. + * + * {@hide} + */ + public static void setThreadStatsUid(int uid) { + BlockGuard.setThreadSocketStatsUid(uid); + } + + /** {@hide} */ + public static void clearThreadStatsUid() { + BlockGuard.setThreadSocketStatsUid(-1); + } + + /** + * Tag the given {@link Socket} with any statistics parameters active for + * the current thread. Subsequent calls always replace any existing + * parameters. When finished, call {@link #untagSocket(Socket)} to remove + * statistics parameters. + * + * @see #setThreadStatsTag(String) + * @see #setThreadStatsUid(int) + */ + public static void tagSocket(Socket socket) throws SocketException { + BlockGuard.tagSocketFd(socket.getFileDescriptor$()); + } + + /** + * Remove any statistics parameters from the given {@link Socket}. + */ + public static void untagSocket(Socket socket) throws SocketException { + BlockGuard.untagSocketFd(socket.getFileDescriptor$()); + } + /** * Get the total number of packets transmitted through the mobile interface. * From 33936acd3e55a01093931daaa87d17449ea070bb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 17 May 2011 14:55:15 -0700 Subject: [PATCH 0033/1150] APIs to profile network usage for current UID. Added startDataProfiling() and stopDataProfiling() to TrafficStats, which can be used by apps to measure network usage delta between two points in time. Currently takes two NetworkStats snapshots and returns delta, which will eventually include tag-level granularity. Added tests for NetworkStats delta subtraction. Added NMS.getNetworkStatsUidDetail() that returns stats for specific UID. Always gives stats access for the calling UID, otherwise enforces that caller has permission. Fix readSingleLongFromFile(), since /proc/ files don't have well-defined lengths. Change-Id: Ic5b6414d8effbd66846e275b00d4b8a82c74589d --- core/java/android/net/NetworkStats.java | 54 ++++++++++++++++--- core/java/android/net/TrafficStats.java | 72 +++++++++++++++++++++++++ 2 files changed, 119 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 4430e00057..0f207bc953 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -36,6 +36,9 @@ public class NetworkStats implements Parcelable { /** {@link #uid} value when entry is summarized over all UIDs. */ public static final int UID_ALL = 0; + // NOTE: data should only be accounted for once in this structure; if data + // is broken out, the summarized version should not be included. + /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. @@ -81,12 +84,13 @@ public class NetworkStats implements Parcelable { mTx = new long[size]; } - public void addEntry(String iface, int uid, long rx, long tx) { + public Builder addEntry(String iface, int uid, long rx, long tx) { mIface[mIndex] = iface; mUid[mIndex] = uid; mRx[mIndex] = rx; mTx[mIndex] = tx; mIndex++; + return this; } public NetworkStats build() { @@ -97,11 +101,17 @@ public class NetworkStats implements Parcelable { } } + public int length() { + // length is identical for all fields + return iface.length; + } + /** * Find first stats index that matches the requested parameters. */ public int findIndex(String iface, int uid) { - for (int i = 0; i < this.iface.length; i++) { + final int length = length(); + for (int i = 0; i < length; i++) { if (equal(iface, this.iface[i]) && uid == this.uid[i]) { return i; } @@ -109,13 +119,38 @@ public class NetworkStats implements Parcelable { return -1; } - private static boolean equal(Object a, Object b) { - return a == b || (a != null && a.equals(b)); + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + */ + public NetworkStats subtract(NetworkStats value) { + // result will have our rows, but no meaningful timestamp + final int length = length(); + final NetworkStats.Builder result = new NetworkStats.Builder(-1, length); + + for (int i = 0; i < length; i++) { + final String iface = this.iface[i]; + final int uid = this.uid[i]; + + // find remote row that matches, and subtract + final int j = value.findIndex(iface, uid); + if (j == -1) { + // newly appearing row, return entire value + result.addEntry(iface, uid, this.rx[i], this.tx[i]); + } else { + // existing row, subtract remote value + final long rx = this.rx[i] - value.rx[j]; + final long tx = this.tx[i] - value.tx[j]; + result.addEntry(iface, uid, rx, tx); + } + } + + return result.build(); } - /** {@inheritDoc} */ - public int describeContents() { - return 0; + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); } public void dump(String prefix, PrintWriter pw) { @@ -137,6 +172,11 @@ public class NetworkStats implements Parcelable { return writer.toString(); } + /** {@inheritDoc} */ + public int describeContents() { + return 0; + } + /** {@inheritDoc} */ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 7ee7a81f40..c0ff73418a 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,6 +16,12 @@ package android.net; +import android.content.Context; +import android.os.IBinder; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.ServiceManager; + import dalvik.system.BlockGuard; import java.net.Socket; @@ -35,6 +41,17 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; + /** + * Snapshot of {@link NetworkStats} when the currently active profiling + * session started, or {@code null} if no session active. + * + * @see #startDataProfiling(Context) + * @see #stopDataProfiling(Context) + */ + private static NetworkStats sActiveProfilingStart; + + private static Object sProfilingLock = new Object(); + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -92,6 +109,44 @@ public class TrafficStats { BlockGuard.untagSocketFd(socket.getFileDescriptor$()); } + /** + * Start profiling data usage for current UID. Only one profiling session + * can be active at a time. + * + * @hide + */ + public static void startDataProfiling(Context context) { + synchronized (sProfilingLock) { + if (sActiveProfilingStart != null) { + throw new IllegalStateException("already profiling data"); + } + + // take snapshot in time; we calculate delta later + sActiveProfilingStart = getNetworkStatsForUid(context); + } + } + + /** + * Stop profiling data usage for current UID. + * + * @return Detailed {@link NetworkStats} of data that occurred since last + * {@link #startDataProfiling(Context)} call. + * @hide + */ + public static NetworkStats stopDataProfiling(Context context) { + synchronized (sProfilingLock) { + if (sActiveProfilingStart == null) { + throw new IllegalStateException("not profiling data"); + } + + // subtract starting values and return delta + final NetworkStats profilingStop = getNetworkStatsForUid(context); + final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart); + sActiveProfilingStart = null; + return profilingDelta; + } + } + /** * Get the total number of packets transmitted through the mobile interface. * @@ -350,4 +405,21 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. */ public static native long getUidUdpRxPackets(int uid); + + /** + * Return detailed {@link NetworkStats} for the current UID. Requires no + * special permission. + */ + private static NetworkStats getNetworkStatsForUid(Context context) { + final IBinder binder = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + final INetworkManagementService service = INetworkManagementService.Stub.asInterface( + binder); + + final int uid = android.os.Process.myUid(); + try { + return service.getNetworkStatsUidDetail(uid); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } } From 9ab8c6a64d5dbfaa9d5e57986ed899d07e3cb56c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 May 2011 18:39:45 -0700 Subject: [PATCH 0034/1150] Collect historical network stats. Periodically records delta network traffic into historical buckets to support other services, such NetworkPolicyManager and Settings UI. Introduces NetworkStatsHistory structure which contains sparse, uniform buckets of data usage defined by timestamps. Service periodically polls NetworkStats and records changes into buckets. It only persists to disk when substantial changes have occured. Current parameters create 4 buckets each day, and persist for 90 days, resulting in about 8kB of data per network. Only records stats for "well known" network interfaces that have been claimed by Telephony or Wi-Fi subsystems. Historical stats are also keyed off identity (such as IMSI) to support SIM swapping. Change-Id: Ia27d1289556a2bf9545fbc4f3b789425a01be53a --- .../android/net/INetworkStatsService.aidl | 27 ++ core/java/android/net/NetworkStats.java | 48 ++- .../java/android/net/NetworkStatsHistory.aidl | 19 + .../java/android/net/NetworkStatsHistory.java | 285 +++++++++++++ core/java/android/net/TrafficStats.java | 3 +- .../server/net/NetworkStatsService.java | 403 ++++++++++++++++++ 6 files changed, 773 insertions(+), 12 deletions(-) create mode 100644 core/java/android/net/INetworkStatsService.aidl create mode 100644 core/java/android/net/NetworkStatsHistory.aidl create mode 100644 core/java/android/net/NetworkStatsHistory.java create mode 100644 services/java/com/android/server/net/NetworkStatsService.java diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl new file mode 100644 index 0000000000..6d57036fbd --- /dev/null +++ b/core/java/android/net/INetworkStatsService.aidl @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.NetworkStatsHistory; + +/** {@hide} */ +interface INetworkStatsService { + + NetworkStatsHistory[] getNetworkStatsSummary(int networkType); + NetworkStatsHistory getNetworkStatsUid(int uid); + +} diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0f207bc953..588bf64b4a 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -22,19 +22,22 @@ import android.os.SystemClock; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.util.HashSet; /** - * Collection of network statistics. Can contain summary details across all - * interfaces, or details with per-UID granularity. Designed to parcel quickly - * across process boundaries. + * Collection of active network statistics. Can contain summary details across + * all interfaces, or details with per-UID granularity. Internally stores data + * as a large table, closely matching {@code /proc/} data format. This structure + * optimizes for rapid in-memory comparison, but consider using + * {@link NetworkStatsHistory} when persisting. * * @hide */ public class NetworkStats implements Parcelable { - /** {@link #iface} value when entry is summarized over all interfaces. */ + /** {@link #iface} value when interface details unavailable. */ public static final String IFACE_ALL = null; - /** {@link #uid} value when entry is summarized over all UIDs. */ - public static final int UID_ALL = 0; + /** {@link #uid} value when UID details unavailable. */ + public static final int UID_ALL = -1; // NOTE: data should only be accounted for once in this structure; if data // is broken out, the summarized version should not be included. @@ -49,7 +52,7 @@ public class NetworkStats implements Parcelable { public final long[] rx; public final long[] tx; - // TODO: add fg/bg stats and tag granularity + // TODO: add fg/bg stats once reported by kernel private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) { this.elapsedRealtime = elapsedRealtime; @@ -119,16 +122,36 @@ public class NetworkStats implements Parcelable { return -1; } + /** + * Return list of unique interfaces known by this data structure. + */ + public String[] getKnownIfaces() { + final HashSet ifaces = new HashSet(); + for (String iface : this.iface) { + if (iface != IFACE_ALL) { + ifaces.add(iface); + } + } + return ifaces.toArray(new String[ifaces.size()]); + } + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. + * + * @param enforceMonotonic Validate that incoming value is strictly + * monotonic compared to this object. */ - public NetworkStats subtract(NetworkStats value) { - // result will have our rows, but no meaningful timestamp - final int length = length(); - final NetworkStats.Builder result = new NetworkStats.Builder(-1, length); + public NetworkStats subtract(NetworkStats value, boolean enforceMonotonic) { + final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; + if (enforceMonotonic && deltaRealtime < 0) { + throw new IllegalArgumentException("found non-monotonic realtime"); + } + // result will have our rows, and elapsed time between snapshots + final int length = length(); + final NetworkStats.Builder result = new NetworkStats.Builder(deltaRealtime, length); for (int i = 0; i < length; i++) { final String iface = this.iface[i]; final int uid = this.uid[i]; @@ -142,6 +165,9 @@ public class NetworkStats implements Parcelable { // existing row, subtract remote value final long rx = this.rx[i] - value.rx[j]; final long tx = this.tx[i] - value.tx[j]; + if (enforceMonotonic && (rx < 0 || tx < 0)) { + throw new IllegalArgumentException("found non-monotonic values"); + } result.addEntry(iface, uid, rx, tx); } } diff --git a/core/java/android/net/NetworkStatsHistory.aidl b/core/java/android/net/NetworkStatsHistory.aidl new file mode 100644 index 0000000000..8b9069f8fa --- /dev/null +++ b/core/java/android/net/NetworkStatsHistory.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkStatsHistory; diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java new file mode 100644 index 0000000000..b16101fae6 --- /dev/null +++ b/core/java/android/net/NetworkStatsHistory.java @@ -0,0 +1,285 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.CharArrayWriter; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; + +/** + * Collection of historical network statistics, recorded into equally-sized + * "buckets" in time. Internally it stores data in {@code long} series for more + * efficient persistence. + *

+ * Each bucket is defined by a {@link #bucketStart} timestamp, and lasts for + * {@link #bucketDuration}. Internally assumes that {@link #bucketStart} is + * sorted at all times. + * + * @hide + */ +public class NetworkStatsHistory implements Parcelable { + private static final int VERSION = 1; + + /** {@link #uid} value when UID details unavailable. */ + public static final int UID_ALL = -1; + + // TODO: teach about zigzag encoding to use less disk space + // TODO: teach how to convert between bucket sizes + + public final int networkType; + public final String identity; + public final int uid; + public final long bucketDuration; + + int bucketCount; + long[] bucketStart; + long[] rx; + long[] tx; + + public NetworkStatsHistory(int networkType, String identity, int uid, long bucketDuration) { + this.networkType = networkType; + this.identity = identity; + this.uid = uid; + this.bucketDuration = bucketDuration; + bucketStart = new long[0]; + rx = new long[0]; + tx = new long[0]; + bucketCount = bucketStart.length; + } + + public NetworkStatsHistory(Parcel in) { + networkType = in.readInt(); + identity = in.readString(); + uid = in.readInt(); + bucketDuration = in.readLong(); + bucketStart = readLongArray(in); + rx = in.createLongArray(); + tx = in.createLongArray(); + bucketCount = bucketStart.length; + } + + /** {@inheritDoc} */ + public void writeToParcel(Parcel out, int flags) { + out.writeInt(networkType); + out.writeString(identity); + out.writeInt(uid); + out.writeLong(bucketDuration); + writeLongArray(out, bucketStart, bucketCount); + writeLongArray(out, rx, bucketCount); + writeLongArray(out, tx, bucketCount); + } + + public NetworkStatsHistory(DataInputStream in) throws IOException { + final int version = in.readInt(); + networkType = in.readInt(); + identity = in.readUTF(); + uid = in.readInt(); + bucketDuration = in.readLong(); + bucketStart = readLongArray(in); + rx = readLongArray(in); + tx = readLongArray(in); + bucketCount = bucketStart.length; + } + + public void writeToStream(DataOutputStream out) throws IOException { + out.writeInt(VERSION); + out.writeInt(networkType); + out.writeUTF(identity); + out.writeInt(uid); + out.writeLong(bucketDuration); + writeLongArray(out, bucketStart, bucketCount); + writeLongArray(out, rx, bucketCount); + writeLongArray(out, tx, bucketCount); + } + + /** {@inheritDoc} */ + public int describeContents() { + return 0; + } + + /** + * Record that data traffic occurred in the given time range. Will + * distribute across internal buckets, creating new buckets as needed. + */ + public void recordData(long start, long end, long rx, long tx) { + // create any buckets needed by this range + ensureBuckets(start, end); + + // distribute data usage into buckets + final long duration = end - start; + for (int i = bucketCount - 1; i >= 0; i--) { + final long curStart = bucketStart[i]; + final long curEnd = curStart + bucketDuration; + + // bucket is older than record; we're finished + if (curEnd < start) break; + // bucket is newer than record; keep looking + if (curStart > end) continue; + + final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); + if (overlap > 0) { + this.rx[i] += rx * overlap / duration; + this.tx[i] += tx * overlap / duration; + } + } + } + + /** + * Ensure that buckets exist for given time range, creating as needed. + */ + private void ensureBuckets(long start, long end) { + // normalize incoming range to bucket boundaries + start -= start % bucketDuration; + end += (bucketDuration - (end % bucketDuration)) % bucketDuration; + + for (long now = start; now < end; now += bucketDuration) { + // try finding existing bucket + final int index = Arrays.binarySearch(bucketStart, 0, bucketCount, now); + if (index < 0) { + // bucket missing, create and insert + insertBucket(~index, now); + } + } + } + + /** + * Insert new bucket at requested index and starting time. + */ + private void insertBucket(int index, long start) { + // create more buckets when needed + if (bucketCount + 1 > bucketStart.length) { + final int newLength = bucketStart.length + 10; + bucketStart = Arrays.copyOf(bucketStart, newLength); + rx = Arrays.copyOf(rx, newLength); + tx = Arrays.copyOf(tx, newLength); + } + + // create gap when inserting bucket in middle + if (index < bucketCount) { + final int dstPos = index + 1; + final int length = bucketCount - index; + + System.arraycopy(bucketStart, index, bucketStart, dstPos, length); + System.arraycopy(rx, index, rx, dstPos, length); + System.arraycopy(tx, index, tx, dstPos, length); + } + + bucketStart[index] = start; + rx[index] = 0; + tx[index] = 0; + bucketCount++; + } + + /** + * Remove buckets older than requested cutoff. + */ + public void removeBucketsBefore(long cutoff) { + int i; + for (i = 0; i < bucketCount; i++) { + final long curStart = bucketStart[i]; + final long curEnd = curStart + bucketDuration; + + // cutoff happens before or during this bucket; everything before + // this bucket should be removed. + if (curEnd > cutoff) break; + } + + if (i > 0) { + final int length = bucketStart.length; + bucketStart = Arrays.copyOfRange(bucketStart, i, length); + rx = Arrays.copyOfRange(rx, i, length); + tx = Arrays.copyOfRange(tx, i, length); + bucketCount -= i; + } + } + + public void dump(String prefix, PrintWriter pw) { + // TODO: consider stripping identity when dumping + pw.print(prefix); + pw.print("NetworkStatsHistory: networkType="); pw.print(networkType); + pw.print(" identity="); pw.print(identity); + pw.print(" uid="); pw.println(uid); + for (int i = 0; i < bucketCount; i++) { + pw.print(prefix); + pw.print(" timestamp="); pw.print(bucketStart[i]); + pw.print(" rx="); pw.print(rx[i]); + pw.print(" tx="); pw.println(tx[i]); + } + } + + @Override + public String toString() { + final CharArrayWriter writer = new CharArrayWriter(); + dump("", new PrintWriter(writer)); + return writer.toString(); + } + + public static final Creator CREATOR = new Creator() { + public NetworkStatsHistory createFromParcel(Parcel in) { + return new NetworkStatsHistory(in); + } + + public NetworkStatsHistory[] newArray(int size) { + return new NetworkStatsHistory[size]; + } + }; + + private static long[] readLongArray(DataInputStream in) throws IOException { + final int size = in.readInt(); + final long[] values = new long[size]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + return values; + } + + private static void writeLongArray(DataOutputStream out, long[] values, int size) throws IOException { + if (size > values.length) { + throw new IllegalArgumentException("size larger than length"); + } + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeLong(values[i]); + } + } + + private static long[] readLongArray(Parcel in) { + final int size = in.readInt(); + final long[] values = new long[size]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + return values; + } + + private static void writeLongArray(Parcel out, long[] values, int size) { + if (size > values.length) { + throw new IllegalArgumentException("size larger than length"); + } + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeLong(values[i]); + } + } + +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index c0ff73418a..8ab64fabd2 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -141,7 +141,8 @@ public class TrafficStats { // subtract starting values and return delta final NetworkStats profilingStop = getNetworkStatsForUid(context); - final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart); + final NetworkStats profilingDelta = profilingStop.subtract( + sActiveProfilingStart, false); sActiveProfilingStart = null; return profilingDelta; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java new file mode 100644 index 0000000000..d9c1f25b72 --- /dev/null +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -0,0 +1,403 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.SHUTDOWN; +import static android.Manifest.permission.UPDATE_DEVICE_STATS; +import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkStats.UID_ALL; + +import android.app.AlarmManager; +import android.app.IAlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.INetworkStatsService; +import android.net.LinkProperties; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.wifi.WifiManager; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.os.SystemClock; +import android.telephony.TelephonyManager; +import android.text.format.DateUtils; +import android.util.NtpTrustedTime; +import android.util.Slog; +import android.util.TrustedTime; + +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyIntents; +import com.google.android.collect.Maps; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.HashMap; + +/** + * Collect and persist detailed network statistics, and provide this data to + * other system services. + */ +public class NetworkStatsService extends INetworkStatsService.Stub { + private static final String TAG = "NetworkStatsService"; + private static final boolean LOGD = true; + + private final Context mContext; + private final INetworkManagementService mNetworkManager; + private final IAlarmManager mAlarmManager; + private final TrustedTime mTime; + + private static final String ACTION_NETWORK_STATS_POLL = + "com.android.server.action.NETWORK_STATS_POLL"; + + private PendingIntent mPollIntent; + + // TODO: move tweakable params to Settings.Secure + // TODO: listen for kernel push events through netd instead of polling + + private static final long KB_IN_BYTES = 1024; + + private static final long POLL_INTERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES; + private static final long SUMMARY_BUCKET_DURATION = 6 * DateUtils.HOUR_IN_MILLIS; + private static final long SUMMARY_MAX_HISTORY = 90 * DateUtils.DAY_IN_MILLIS; + + // TODO: remove these high-frequency testing values +// private static final long POLL_INTERVAL = 5 * DateUtils.SECOND_IN_MILLIS; +// private static final long SUMMARY_BUCKET_DURATION = 10 * DateUtils.SECOND_IN_MILLIS; +// private static final long SUMMARY_MAX_HISTORY = 2 * DateUtils.MINUTE_IN_MILLIS; + + /** Minimum delta required to persist to disk. */ + private static final long SUMMARY_PERSIST_THRESHOLD = 64 * KB_IN_BYTES; + + private static final long TIME_CACHE_MAX_AGE = DateUtils.DAY_IN_MILLIS; + + private final Object mStatsLock = new Object(); + + /** Set of active ifaces during this boot. */ + private HashMap mActiveIface = Maps.newHashMap(); + /** Set of historical stats for known ifaces. */ + private HashMap mIfaceStats = Maps.newHashMap(); + + private NetworkStats mLastPollStats; + private NetworkStats mLastPersistStats; + + private final HandlerThread mHandlerThread; + private final Handler mHandler; + + // TODO: collect detailed uid stats, storing tag-granularity data until next + // dropbox, and uid summary for a specific bucket count. + + // TODO: periodically compile statistics and send to dropbox. + + public NetworkStatsService( + Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { + // TODO: move to using cached NtpTrustedTime + this(context, networkManager, alarmManager, new NtpTrustedTime()); + } + + public NetworkStatsService(Context context, INetworkManagementService networkManager, + IAlarmManager alarmManager, TrustedTime time) { + mContext = checkNotNull(context, "missing Context"); + mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); + mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); + mTime = checkNotNull(time, "missing TrustedTime"); + + mHandlerThread = new HandlerThread(TAG); + mHandlerThread.start(); + mHandler = new Handler(mHandlerThread.getLooper()); + } + + public void systemReady() { + // read historical stats from disk + readStatsLocked(); + + // watch other system services that claim interfaces + // TODO: protect incoming broadcast with permissions check. + // TODO: consider migrating this to ConnectivityService, but it might + // cause a circular dependency. + final IntentFilter interfaceFilter = new IntentFilter(); + interfaceFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); + interfaceFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); + mContext.registerReceiver(mInterfaceReceiver, interfaceFilter); + + // listen for periodic polling events + final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); + mContext.registerReceiver(mPollReceiver, pollFilter, UPDATE_DEVICE_STATS, mHandler); + + // persist stats during clean shutdown + final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); + mContext.registerReceiver(mShutdownReceiver, shutdownFilter, SHUTDOWN, null); + + try { + registerPollAlarmLocked(); + } catch (RemoteException e) { + Slog.w(TAG, "unable to register poll alarm"); + } + } + + /** + * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and + * reschedule based on current {@link #POLL_INTERVAL} value. + */ + private void registerPollAlarmLocked() throws RemoteException { + if (mPollIntent != null) { + mAlarmManager.remove(mPollIntent); + } + + mPollIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating( + AlarmManager.ELAPSED_REALTIME, currentRealtime, POLL_INTERVAL, mPollIntent); + } + + @Override + public NetworkStatsHistory[] getNetworkStatsSummary(int networkType) { + // TODO: return history for requested types + return null; + } + + @Override + public NetworkStatsHistory getNetworkStatsUid(int uid) { + // TODO: return history for requested uid + return null; + } + + /** + * Receiver that watches for other system components that claim network + * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} + * with mobile interfaces. + */ + private BroadcastReceiver mInterfaceReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + if (TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED.equals(action)) { + final LinkProperties prop = intent.getParcelableExtra( + Phone.DATA_LINK_PROPERTIES_KEY); + final String iface = prop != null ? prop.getInterfaceName() : null; + if (iface != null) { + final TelephonyManager teleManager = (TelephonyManager) context + .getSystemService(Context.TELEPHONY_SERVICE); + final InterfaceInfo info = new InterfaceInfo( + iface, TYPE_MOBILE, teleManager.getSubscriberId()); + reportActiveInterface(info); + } + } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { + final LinkProperties prop = intent.getParcelableExtra( + WifiManager.EXTRA_LINK_PROPERTIES); + final String iface = prop != null ? prop.getInterfaceName() : null; + if (iface != null) { + final InterfaceInfo info = new InterfaceInfo(iface, TYPE_WIFI, null); + reportActiveInterface(info); + } + } + } + }; + + private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // already running on background handler, network/io is safe, and + // caller verified to have UPDATE_DEVICE_STATS permission above. + synchronized (mStatsLock) { + // TODO: acquire wakelock while performing poll + performPollLocked(); + } + } + }; + + private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // persist stats during clean shutdown + synchronized (mStatsLock) { + writeStatsLocked(); + } + } + }; + + private void performPollLocked() { + if (LOGD) Slog.v(TAG, "performPollLocked()"); + + // try refreshing time source when stale + if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { + mTime.forceRefresh(); + } + + // TODO: consider marking "untrusted" times in historical stats + final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() + : System.currentTimeMillis(); + + final NetworkStats current; + try { + current = mNetworkManager.getNetworkStatsSummary(); + } catch (RemoteException e) { + Slog.w(TAG, "problem reading network stats"); + return; + } + + // update historical usage with delta since last poll + final NetworkStats pollDelta = computeStatsDelta(mLastPollStats, current); + final long timeStart = currentTime - pollDelta.elapsedRealtime; + for (String iface : pollDelta.getKnownIfaces()) { + final InterfaceInfo info = mActiveIface.get(iface); + if (info == null) { + if (LOGD) Slog.w(TAG, "unknown interface " + iface + ", ignoring stats"); + continue; + } + + final int index = pollDelta.findIndex(iface, UID_ALL); + final long rx = pollDelta.rx[index]; + final long tx = pollDelta.tx[index]; + + final NetworkStatsHistory history = findOrCreateHistoryLocked(info); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - SUMMARY_MAX_HISTORY); + } + + mLastPollStats = current; + + // decide if enough has changed to trigger persist + final NetworkStats persistDelta = computeStatsDelta(mLastPersistStats, current); + for (String iface : persistDelta.getKnownIfaces()) { + final int index = persistDelta.findIndex(iface, UID_ALL); + if (persistDelta.rx[index] > SUMMARY_PERSIST_THRESHOLD + || persistDelta.tx[index] > SUMMARY_PERSIST_THRESHOLD) { + writeStatsLocked(); + mLastPersistStats = current; + break; + } + } + } + + private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceInfo info) { + NetworkStatsHistory stats = mIfaceStats.get(info); + if (stats == null) { + stats = new NetworkStatsHistory( + info.networkType, info.identity, UID_ALL, SUMMARY_BUCKET_DURATION); + mIfaceStats.put(info, stats); + } + return stats; + } + + private void readStatsLocked() { + if (LOGD) Slog.v(TAG, "readStatsLocked()"); + // TODO: read historical stats from disk using AtomicFile + } + + private void writeStatsLocked() { + if (LOGD) Slog.v(TAG, "writeStatsLocked()"); + // TODO: persist historical stats to disk using AtomicFile + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(DUMP, TAG); + + pw.println("Active interfaces:"); + for (InterfaceInfo info : mActiveIface.values()) { + info.dump(" ", pw); + } + + pw.println("Known historical stats:"); + for (NetworkStatsHistory stats : mIfaceStats.values()) { + stats.dump(" ", pw); + } + } + + /** + * Details for a well-known network interface, including its name, network + * type, and billing relationship identity (such as IMSI). + */ + private static class InterfaceInfo { + public final String iface; + public final int networkType; + public final String identity; + + public InterfaceInfo(String iface, int networkType, String identity) { + this.iface = iface; + this.networkType = networkType; + this.identity = identity; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((identity == null) ? 0 : identity.hashCode()); + result = prime * result + ((iface == null) ? 0 : iface.hashCode()); + result = prime * result + networkType; + return result; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof InterfaceInfo) { + final InterfaceInfo info = (InterfaceInfo) obj; + return equal(iface, info.iface) && networkType == info.networkType + && equal(identity, info.identity); + } + return false; + } + + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("InterfaceInfo: iface="); pw.print(iface); + pw.print(" networkType="); pw.print(networkType); + pw.print(" identity="); pw.println(identity); + } + } + + private void reportActiveInterface(InterfaceInfo info) { + synchronized (mStatsLock) { + // TODO: when interface redefined, port over historical stats + mActiveIface.put(info.iface, info); + } + } + + /** + * Return the delta between two {@link NetworkStats} snapshots, where {@code + * before} can be {@code null}. + */ + private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) { + if (before != null) { + return current.subtract(before, false); + } else { + return current; + } + } + + private static boolean equal(Object a, Object b) { + return a == b || (a != null && a.equals(b)); + } + + private static T checkNotNull(T value, String message) { + if (value == null) { + throw new NullPointerException(message); + } + return value; + } + +} From 1a3eb889f0f3e3c8698d5024055e3ec791c238df Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 28 May 2011 20:56:34 -0700 Subject: [PATCH 0035/1150] Map network identity using ConnectivityService. Instead of deriving network identity based on raw subsystem broadcasts, listen for updates from ConnectivityService. Added atomic view of all active NetworkState, and build map from "iface" to NetworkIdentity set for stats tracking. To avoid exposing internal complexity, INetworkStatsService calls use general templates. Added TelephonyManager mapping to classify network types using broad labels like "3G" or "4G", used to drive templates. Cleaned up Objects and Preconditions. Change-Id: I1d4c1403f0503bc3635a59bb378841ba42239a91 --- .../android/net/INetworkStatsService.aidl | 10 +- .../java/android/net/NetworkStatsHistory.java | 36 +-- core/java/android/net/TrafficStats.java | 36 +++ .../android/server/net/InterfaceIdentity.java | 73 ++++++ .../server/net/NetworkStatsService.java | 247 +++++++++--------- 5 files changed, 253 insertions(+), 149 deletions(-) create mode 100644 services/java/com/android/server/net/InterfaceIdentity.java diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 6d57036fbd..d38d16c4e7 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -16,12 +16,18 @@ package android.net; +import android.net.NetworkStats; import android.net.NetworkStatsHistory; /** {@hide} */ interface INetworkStatsService { - NetworkStatsHistory[] getNetworkStatsSummary(int networkType); - NetworkStatsHistory getNetworkStatsUid(int uid); + /** Return historical stats for traffic that matches template. */ + NetworkStatsHistory getHistoryForNetwork(int networkTemplate); + /** Return historical stats for specific UID traffic that matches template. */ + NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); + + /** Return usage summary per UID for traffic that matches template. */ + NetworkStats getSummaryPerUid(long start, long end, int networkTemplate); } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index b16101fae6..60af475de2 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -40,26 +40,17 @@ import java.util.Arrays; public class NetworkStatsHistory implements Parcelable { private static final int VERSION = 1; - /** {@link #uid} value when UID details unavailable. */ - public static final int UID_ALL = -1; - // TODO: teach about zigzag encoding to use less disk space // TODO: teach how to convert between bucket sizes - public final int networkType; - public final String identity; - public final int uid; public final long bucketDuration; - int bucketCount; - long[] bucketStart; - long[] rx; - long[] tx; + public int bucketCount; + public long[] bucketStart; + public long[] rx; + public long[] tx; - public NetworkStatsHistory(int networkType, String identity, int uid, long bucketDuration) { - this.networkType = networkType; - this.identity = identity; - this.uid = uid; + public NetworkStatsHistory(long bucketDuration) { this.bucketDuration = bucketDuration; bucketStart = new long[0]; rx = new long[0]; @@ -68,9 +59,6 @@ public class NetworkStatsHistory implements Parcelable { } public NetworkStatsHistory(Parcel in) { - networkType = in.readInt(); - identity = in.readString(); - uid = in.readInt(); bucketDuration = in.readLong(); bucketStart = readLongArray(in); rx = in.createLongArray(); @@ -80,9 +68,6 @@ public class NetworkStatsHistory implements Parcelable { /** {@inheritDoc} */ public void writeToParcel(Parcel out, int flags) { - out.writeInt(networkType); - out.writeString(identity); - out.writeInt(uid); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rx, bucketCount); @@ -91,9 +76,6 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(DataInputStream in) throws IOException { final int version = in.readInt(); - networkType = in.readInt(); - identity = in.readUTF(); - uid = in.readInt(); bucketDuration = in.readLong(); bucketStart = readLongArray(in); rx = readLongArray(in); @@ -103,9 +85,6 @@ public class NetworkStatsHistory implements Parcelable { public void writeToStream(DataOutputStream out) throws IOException { out.writeInt(VERSION); - out.writeInt(networkType); - out.writeUTF(identity); - out.writeInt(uid); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rx, bucketCount); @@ -214,11 +193,8 @@ public class NetworkStatsHistory implements Parcelable { } public void dump(String prefix, PrintWriter pw) { - // TODO: consider stripping identity when dumping pw.print(prefix); - pw.print("NetworkStatsHistory: networkType="); pw.print(networkType); - pw.print(" identity="); pw.print(identity); - pw.print(" uid="); pw.println(uid); + pw.println("NetworkStatsHistory:"); for (int i = 0; i < bucketCount; i++) { pw.print(prefix); pw.print(" timestamp="); pw.print(bucketStart[i]); diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 8ab64fabd2..a0738c1da2 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -41,6 +41,42 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; + // TODO: find better home for these template constants + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together. Only uses statistics for currently active IMSI. + * + * @hide + */ + public static final int TEMPLATE_MOBILE_ALL = 1; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that roughly meet a "3G" definition, or lower. Only + * uses statistics for currently active IMSI. + * + * @hide + */ + public static final int TEMPLATE_MOBILE_3G_LOWER = 2; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that meet a "4G" definition. Only uses statistics for + * currently active IMSI. + * + * @hide + */ + public static final int TEMPLATE_MOBILE_4G = 3; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style + * networks together. + * + * @hide + */ + public static final int TEMPLATE_WIFI = 4; + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. diff --git a/services/java/com/android/server/net/InterfaceIdentity.java b/services/java/com/android/server/net/InterfaceIdentity.java new file mode 100644 index 0000000000..ff86581eff --- /dev/null +++ b/services/java/com/android/server/net/InterfaceIdentity.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.ProtocolException; +import java.util.HashSet; + +/** + * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} + * active on that interface. + * + * @hide + */ +public class InterfaceIdentity extends HashSet { + private static final int VERSION_CURRENT = 1; + + public InterfaceIdentity() { + } + + public InterfaceIdentity(DataInputStream in) throws IOException { + final int version = in.readInt(); + switch (version) { + case VERSION_CURRENT: { + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + add(new NetworkIdentity(in)); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } + + public void writeToStream(DataOutputStream out) throws IOException { + out.writeInt(VERSION_CURRENT); + out.writeInt(size()); + for (NetworkIdentity ident : this) { + ident.writeToStream(out); + } + } + + /** + * Test if any {@link NetworkIdentity} on this interface matches the given + * template and IMEI. + */ + public boolean matchesTemplate(int networkTemplate, String subscriberId) { + for (NetworkIdentity ident : this) { + if (ident.matchesTemplate(networkTemplate, subscriberId)) { + return true; + } + } + return false; + } +} diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index d9c1f25b72..66d127447a 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,13 @@ package com.android.server.net; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; import static android.Manifest.permission.SHUTDOWN; import static android.Manifest.permission.UPDATE_DEVICE_STATS; -import static android.net.ConnectivityManager.TYPE_MOBILE; -import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.UID_ALL; +import static com.android.internal.util.Preconditions.checkNotNull; import android.app.AlarmManager; import android.app.IAlarmManager; @@ -30,11 +31,12 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.net.IConnectivityManager; import android.net.INetworkStatsService; -import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; -import android.net.wifi.WifiManager; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; @@ -46,12 +48,12 @@ import android.util.NtpTrustedTime; import android.util.Slog; import android.util.TrustedTime; -import com.android.internal.telephony.Phone; -import com.android.internal.telephony.TelephonyIntents; +import com.google.android.collect.Lists; import com.google.android.collect.Maps; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.HashMap; /** @@ -67,6 +69,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final IAlarmManager mAlarmManager; private final TrustedTime mTime; + private IConnectivityManager mConnManager; + private static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -94,9 +98,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); /** Set of active ifaces during this boot. */ - private HashMap mActiveIface = Maps.newHashMap(); + private HashMap mActiveIface = Maps.newHashMap(); /** Set of historical stats for known ifaces. */ - private HashMap mIfaceStats = Maps.newHashMap(); + private HashMap mStats = Maps.newHashMap(); private NetworkStats mLastPollStats; private NetworkStats mLastPersistStats; @@ -132,13 +136,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { readStatsLocked(); // watch other system services that claim interfaces - // TODO: protect incoming broadcast with permissions check. - // TODO: consider migrating this to ConnectivityService, but it might - // cause a circular dependency. - final IntentFilter interfaceFilter = new IntentFilter(); - interfaceFilter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - interfaceFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); - mContext.registerReceiver(mInterfaceReceiver, interfaceFilter); + final IntentFilter ifaceFilter = new IntentFilter(); + ifaceFilter.addAction(CONNECTIVITY_ACTION); + mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); @@ -155,6 +155,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + public void bindConnectivityManager(IConnectivityManager connManager) { + mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); + } + /** * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link #POLL_INTERVAL} value. @@ -173,45 +177,54 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory[] getNetworkStatsSummary(int networkType) { - // TODO: return history for requested types - return null; + public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) { + // TODO: create relaxed permission for reading stats + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + + synchronized (mStatsLock) { + // combine all interfaces that match template + final String subscriberId = getActiveSubscriberId(); + final NetworkStatsHistory combined = new NetworkStatsHistory(SUMMARY_BUCKET_DURATION); + for (InterfaceIdentity ident : mStats.keySet()) { + final NetworkStatsHistory history = mStats.get(ident); + if (ident.matchesTemplate(networkTemplate, subscriberId)) { + // TODO: combine all matching history data into a single history + } + } + return combined; + } } @Override - public NetworkStatsHistory getNetworkStatsUid(int uid) { + public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) { + // TODO: create relaxed permission for reading stats + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + // TODO: return history for requested uid return null; } + @Override + public NetworkStats getSummaryPerUid(long start, long end, int networkTemplate) { + // TODO: create relaxed permission for reading stats + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + + // TODO: total UID-granularity usage between time range + return null; + } + /** - * Receiver that watches for other system components that claim network + * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} * with mobile interfaces. */ - private BroadcastReceiver mInterfaceReceiver = new BroadcastReceiver() { + private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final String action = intent.getAction(); - if (TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED.equals(action)) { - final LinkProperties prop = intent.getParcelableExtra( - Phone.DATA_LINK_PROPERTIES_KEY); - final String iface = prop != null ? prop.getInterfaceName() : null; - if (iface != null) { - final TelephonyManager teleManager = (TelephonyManager) context - .getSystemService(Context.TELEPHONY_SERVICE); - final InterfaceInfo info = new InterfaceInfo( - iface, TYPE_MOBILE, teleManager.getSubscriberId()); - reportActiveInterface(info); - } - } else if (WifiManager.NETWORK_STATE_CHANGED_ACTION.equals(action)) { - final LinkProperties prop = intent.getParcelableExtra( - WifiManager.EXTRA_LINK_PROPERTIES); - final String iface = prop != null ? prop.getInterfaceName() : null; - if (iface != null) { - final InterfaceInfo info = new InterfaceInfo(iface, TYPE_WIFI, null); - reportActiveInterface(info); - } + // on background handler thread, and verified CONNECTIVITY_INTERNAL + // permission above. + synchronized (mStatsLock) { + updateIfacesLocked(); } } }; @@ -219,8 +232,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - // already running on background handler, network/io is safe, and - // caller verified to have UPDATE_DEVICE_STATS permission above. + // on background handler thread, and verified UPDATE_DEVICE_STATS + // permission above. synchronized (mStatsLock) { // TODO: acquire wakelock while performing poll performPollLocked(); @@ -231,13 +244,49 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - // persist stats during clean shutdown + // verified SHUTDOWN permission above. synchronized (mStatsLock) { writeStatsLocked(); } } }; + /** + * Inspect all current {@link NetworkState} to derive mapping from {@code + * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} + * are active on a single {@code iface}, they are combined under a single + * {@link InterfaceIdentity}. + */ + private void updateIfacesLocked() { + if (LOGD) Slog.v(TAG, "updateIfacesLocked()"); + + // take one last stats snapshot before updating iface mapping. this + // isn't perfect, since the kernel may already be counting traffic from + // the updated network. + // TODO: verify that we only poll summary stats, not uid details + performPollLocked(); + + final NetworkState[] states; + try { + states = mConnManager.getAllNetworkState(); + } catch (RemoteException e) { + Slog.w(TAG, "problem reading network state"); + return; + } + + // rebuild active interfaces based on connected networks + mActiveIface.clear(); + + for (NetworkState state : states) { + if (state.networkInfo.isConnected()) { + // collect networks under their parent interfaces + final String iface = state.linkProperties.getInterfaceName(); + final InterfaceIdentity ident = findOrCreateInterfaceLocked(iface); + ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); + } + } + } + private void performPollLocked() { if (LOGD) Slog.v(TAG, "performPollLocked()"); @@ -258,13 +307,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + final ArrayList unknownIface = Lists.newArrayList(); + // update historical usage with delta since last poll final NetworkStats pollDelta = computeStatsDelta(mLastPollStats, current); final long timeStart = currentTime - pollDelta.elapsedRealtime; for (String iface : pollDelta.getKnownIfaces()) { - final InterfaceInfo info = mActiveIface.get(iface); - if (info == null) { - if (LOGD) Slog.w(TAG, "unknown interface " + iface + ", ignoring stats"); + final InterfaceIdentity ident = mActiveIface.get(iface); + if (ident == null) { + unknownIface.add(iface); continue; } @@ -272,11 +323,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long rx = pollDelta.rx[index]; final long tx = pollDelta.tx[index]; - final NetworkStatsHistory history = findOrCreateHistoryLocked(info); + final NetworkStatsHistory history = findOrCreateHistoryLocked(ident); history.recordData(timeStart, currentTime, rx, tx); history.removeBucketsBefore(currentTime - SUMMARY_MAX_HISTORY); } + if (LOGD && unknownIface.size() > 0) { + Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); + } + mLastPollStats = current; // decide if enough has changed to trigger persist @@ -292,16 +347,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceInfo info) { - NetworkStatsHistory stats = mIfaceStats.get(info); + private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceIdentity ident) { + NetworkStatsHistory stats = mStats.get(ident); if (stats == null) { - stats = new NetworkStatsHistory( - info.networkType, info.identity, UID_ALL, SUMMARY_BUCKET_DURATION); - mIfaceStats.put(info, stats); + stats = new NetworkStatsHistory(SUMMARY_BUCKET_DURATION); + mStats.put(ident, stats); } return stats; } + private InterfaceIdentity findOrCreateInterfaceLocked(String iface) { + InterfaceIdentity ident = mActiveIface.get(iface); + if (ident == null) { + ident = new InterfaceIdentity(); + mActiveIface.put(iface, ident); + } + return ident; + } + private void readStatsLocked() { if (LOGD) Slog.v(TAG, "readStatsLocked()"); // TODO: read historical stats from disk using AtomicFile @@ -310,6 +373,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void writeStatsLocked() { if (LOGD) Slog.v(TAG, "writeStatsLocked()"); // TODO: persist historical stats to disk using AtomicFile + // TODO: consider duplicating stats and releasing lock while writing } @Override @@ -317,63 +381,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(DUMP, TAG); pw.println("Active interfaces:"); - for (InterfaceInfo info : mActiveIface.values()) { - info.dump(" ", pw); + for (String iface : mActiveIface.keySet()) { + final InterfaceIdentity ident = mActiveIface.get(iface); + pw.print(" iface="); pw.print(iface); + pw.print(" ident="); pw.println(ident.toString()); } pw.println("Known historical stats:"); - for (NetworkStatsHistory stats : mIfaceStats.values()) { - stats.dump(" ", pw); - } - } - - /** - * Details for a well-known network interface, including its name, network - * type, and billing relationship identity (such as IMSI). - */ - private static class InterfaceInfo { - public final String iface; - public final int networkType; - public final String identity; - - public InterfaceInfo(String iface, int networkType, String identity) { - this.iface = iface; - this.networkType = networkType; - this.identity = identity; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((identity == null) ? 0 : identity.hashCode()); - result = prime * result + ((iface == null) ? 0 : iface.hashCode()); - result = prime * result + networkType; - return result; - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof InterfaceInfo) { - final InterfaceInfo info = (InterfaceInfo) obj; - return equal(iface, info.iface) && networkType == info.networkType - && equal(identity, info.identity); - } - return false; - } - - public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); - pw.print("InterfaceInfo: iface="); pw.print(iface); - pw.print(" networkType="); pw.print(networkType); - pw.print(" identity="); pw.println(identity); - } - } - - private void reportActiveInterface(InterfaceInfo info) { - synchronized (mStatsLock) { - // TODO: when interface redefined, port over historical stats - mActiveIface.put(info.iface, info); + for (InterfaceIdentity ident : mStats.keySet()) { + final NetworkStatsHistory stats = mStats.get(ident); + pw.print(" ident="); pw.println(ident.toString()); + stats.dump(" ", pw); } } @@ -389,15 +407,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private static boolean equal(Object a, Object b) { - return a == b || (a != null && a.equals(b)); - } - - private static T checkNotNull(T value, String message) { - if (value == null) { - throw new NullPointerException(message); - } - return value; + private String getActiveSubscriberId() { + final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + return telephony.getSubscriberId(); } } From b06fe7ad729951d9d2ecac814115026ec47178ce Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 29 May 2011 22:50:42 -0700 Subject: [PATCH 0036/1150] UID network stats, secure settings, and random. Collect UID-granularity network stats during regular poll event. Add dumpsys argument to generate fake historical data for debugging, and move stats parameters to Settings.Secure. Change-Id: I09b36a2955dc10c697d4b9c3ff23dcb3ac37bd70 --- core/java/android/net/NetworkStats.java | 20 +- .../java/android/net/NetworkStatsHistory.java | 53 +++- .../server/net/NetworkStatsService.java | 253 +++++++++++++----- 3 files changed, 255 insertions(+), 71 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 588bf64b4a..ee415fa6bc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,6 +19,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.SparseBooleanArray; import java.io.CharArrayWriter; import java.io.PrintWriter; @@ -125,7 +126,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique interfaces known by this data structure. */ - public String[] getKnownIfaces() { + public String[] getUniqueIfaces() { final HashSet ifaces = new HashSet(); for (String iface : this.iface) { if (iface != IFACE_ALL) { @@ -135,6 +136,23 @@ public class NetworkStats implements Parcelable { return ifaces.toArray(new String[ifaces.size()]); } + /** + * Return list of unique UIDs known by this data structure. + */ + public int[] getUniqueUids() { + final SparseBooleanArray uids = new SparseBooleanArray(); + for (int uid : this.uid) { + uids.put(uid, true); + } + + final int size = uids.size(); + final int[] result = new int[size]; + for (int i = 0; i < size; i++) { + result[i] = uids.keyAt(i); + } + return result; + } + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 60af475de2..45d8e27645 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -24,7 +24,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.net.ProtocolException; import java.util.Arrays; +import java.util.Random; /** * Collection of historical network statistics, recorded into equally-sized @@ -38,7 +40,7 @@ import java.util.Arrays; * @hide */ public class NetworkStatsHistory implements Parcelable { - private static final int VERSION = 1; + private static final int VERSION_CURRENT = 1; // TODO: teach about zigzag encoding to use less disk space // TODO: teach how to convert between bucket sizes @@ -76,15 +78,23 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(DataInputStream in) throws IOException { final int version = in.readInt(); - bucketDuration = in.readLong(); - bucketStart = readLongArray(in); - rx = readLongArray(in); - tx = readLongArray(in); - bucketCount = bucketStart.length; + switch (version) { + case VERSION_CURRENT: { + bucketDuration = in.readLong(); + bucketStart = readLongArray(in); + rx = readLongArray(in); + tx = readLongArray(in); + bucketCount = bucketStart.length; + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION); + out.writeInt(VERSION_CURRENT); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rx, bucketCount); @@ -192,12 +202,37 @@ public class NetworkStatsHistory implements Parcelable { } } + /** + * @deprecated only for temporary testing + */ + @Deprecated + public void generateRandom(long start, long end, long rx, long tx) { + ensureBuckets(start, end); + + final Random r = new Random(); + while (rx > 1024 && tx > 1024) { + final long curStart = randomLong(r, start, end); + final long curEnd = randomLong(r, curStart, end); + final long curRx = randomLong(r, 0, rx); + final long curTx = randomLong(r, 0, tx); + + recordData(curStart, curEnd, curRx, curTx); + + rx -= curRx; + tx -= curTx; + } + } + + private static long randomLong(Random r, long start, long end) { + return (long) (start + (r.nextFloat() * (end - start))); + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); - pw.println("NetworkStatsHistory:"); + pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); for (int i = 0; i < bucketCount; i++) { pw.print(prefix); - pw.print(" timestamp="); pw.print(bucketStart[i]); + pw.print(" bucketStart="); pw.print(bucketStart[i]); pw.print(" rx="); pw.print(rx[i]); pw.print(" tx="); pw.println(tx[i]); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 66d127447a..967e491449 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -21,7 +21,17 @@ import static android.Manifest.permission.DUMP; import static android.Manifest.permission.SHUTDOWN; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.UID_ALL; +import static android.provider.Settings.Secure.NETSTATS_DETAIL_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_DETAIL_MAX_HISTORY; +import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; +import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; +import static android.provider.Settings.Secure.NETSTATS_SUMMARY_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_SUMMARY_MAX_HISTORY; +import static android.text.format.DateUtils.DAY_IN_MILLIS; +import static android.text.format.DateUtils.HOUR_IN_MILLIS; +import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import android.app.AlarmManager; @@ -31,6 +41,7 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; import android.net.INetworkStatsService; import android.net.NetworkInfo; @@ -42,10 +53,11 @@ import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.SystemClock; +import android.provider.Settings; import android.telephony.TelephonyManager; -import android.text.format.DateUtils; import android.util.NtpTrustedTime; import android.util.Slog; +import android.util.SparseArray; import android.util.TrustedTime; import com.google.android.collect.Lists; @@ -55,6 +67,7 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; /** * Collect and persist detailed network statistics, and provide this data to @@ -76,34 +89,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; - // TODO: move tweakable params to Settings.Secure // TODO: listen for kernel push events through netd instead of polling private static final long KB_IN_BYTES = 1024; + private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; + private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; - private static final long POLL_INTERVAL = AlarmManager.INTERVAL_FIFTEEN_MINUTES; - private static final long SUMMARY_BUCKET_DURATION = 6 * DateUtils.HOUR_IN_MILLIS; - private static final long SUMMARY_MAX_HISTORY = 90 * DateUtils.DAY_IN_MILLIS; + private LongSecureSetting mPollInterval = new LongSecureSetting( + NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); + private LongSecureSetting mPersistThreshold = new LongSecureSetting( + NETSTATS_PERSIST_THRESHOLD, 64 * KB_IN_BYTES); - // TODO: remove these high-frequency testing values -// private static final long POLL_INTERVAL = 5 * DateUtils.SECOND_IN_MILLIS; -// private static final long SUMMARY_BUCKET_DURATION = 10 * DateUtils.SECOND_IN_MILLIS; -// private static final long SUMMARY_MAX_HISTORY = 2 * DateUtils.MINUTE_IN_MILLIS; + private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting( + NETSTATS_SUMMARY_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting( + NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS); + private LongSecureSetting mDetailBucketDuration = new LongSecureSetting( + NETSTATS_DETAIL_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + private LongSecureSetting mDetailMaxHistory = new LongSecureSetting( + NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS); - /** Minimum delta required to persist to disk. */ - private static final long SUMMARY_PERSIST_THRESHOLD = 64 * KB_IN_BYTES; - - private static final long TIME_CACHE_MAX_AGE = DateUtils.DAY_IN_MILLIS; + private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; private final Object mStatsLock = new Object(); /** Set of active ifaces during this boot. */ private HashMap mActiveIface = Maps.newHashMap(); - /** Set of historical stats for known ifaces. */ - private HashMap mStats = Maps.newHashMap(); - private NetworkStats mLastPollStats; - private NetworkStats mLastPersistStats; + /** Set of historical stats for known ifaces. */ + private HashMap mSummaryStats = Maps.newHashMap(); + /** Set of historical stats for known UIDs. */ + private SparseArray mDetailStats = new SparseArray(); + + private NetworkStats mLastSummaryPoll; + private NetworkStats mLastSummaryPersist; + + private NetworkStats mLastDetailPoll; private final HandlerThread mHandlerThread; private final Handler mHandler; @@ -161,7 +182,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and - * reschedule based on current {@link #POLL_INTERVAL} value. + * reschedule based on current {@link #mPollInterval} value. */ private void registerPollAlarmLocked() throws RemoteException { if (mPollIntent != null) { @@ -173,7 +194,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentRealtime = SystemClock.elapsedRealtime(); mAlarmManager.setInexactRepeating( - AlarmManager.ELAPSED_REALTIME, currentRealtime, POLL_INTERVAL, mPollIntent); + AlarmManager.ELAPSED_REALTIME, currentRealtime, mPollInterval.get(), mPollIntent); } @Override @@ -184,9 +205,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { // combine all interfaces that match template final String subscriberId = getActiveSubscriberId(); - final NetworkStatsHistory combined = new NetworkStatsHistory(SUMMARY_BUCKET_DURATION); - for (InterfaceIdentity ident : mStats.keySet()) { - final NetworkStatsHistory history = mStats.get(ident); + final NetworkStatsHistory combined = new NetworkStatsHistory( + mSummaryBucketDuration.get()); + for (InterfaceIdentity ident : mSummaryStats.keySet()) { + final NetworkStatsHistory history = mSummaryStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { // TODO: combine all matching history data into a single history } @@ -299,59 +321,97 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats current; + final NetworkStats summary; + final NetworkStats detail; try { - current = mNetworkManager.getNetworkStatsSummary(); + summary = mNetworkManager.getNetworkStatsSummary(); + detail = mNetworkManager.getNetworkStatsDetail(); } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } + performSummaryPollLocked(summary, currentTime); + performDetailPollLocked(detail, currentTime); + + // decide if enough has changed to trigger persist + final NetworkStats persistDelta = computeStatsDelta(mLastSummaryPersist, summary); + final long persistThreshold = mPersistThreshold.get(); + for (String iface : persistDelta.getUniqueIfaces()) { + final int index = persistDelta.findIndex(iface, UID_ALL); + if (persistDelta.rx[index] > persistThreshold + || persistDelta.tx[index] > persistThreshold) { + writeStatsLocked(); + mLastSummaryPersist = summary; + break; + } + } + } + + /** + * Update {@link #mSummaryStats} historical usage. + */ + private void performSummaryPollLocked(NetworkStats summary, long currentTime) { final ArrayList unknownIface = Lists.newArrayList(); - // update historical usage with delta since last poll - final NetworkStats pollDelta = computeStatsDelta(mLastPollStats, current); - final long timeStart = currentTime - pollDelta.elapsedRealtime; - for (String iface : pollDelta.getKnownIfaces()) { + final NetworkStats delta = computeStatsDelta(mLastSummaryPoll, summary); + final long timeStart = currentTime - delta.elapsedRealtime; + final long maxHistory = mSummaryMaxHistory.get(); + for (String iface : delta.getUniqueIfaces()) { final InterfaceIdentity ident = mActiveIface.get(iface); if (ident == null) { unknownIface.add(iface); continue; } - final int index = pollDelta.findIndex(iface, UID_ALL); - final long rx = pollDelta.rx[index]; - final long tx = pollDelta.tx[index]; + final int index = delta.findIndex(iface, UID_ALL); + final long rx = delta.rx[index]; + final long tx = delta.tx[index]; - final NetworkStatsHistory history = findOrCreateHistoryLocked(ident); + final NetworkStatsHistory history = findOrCreateSummaryLocked(ident); history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - SUMMARY_MAX_HISTORY); + history.removeBucketsBefore(currentTime - maxHistory); } + mLastSummaryPoll = summary; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); } - - mLastPollStats = current; - - // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastPersistStats, current); - for (String iface : persistDelta.getKnownIfaces()) { - final int index = persistDelta.findIndex(iface, UID_ALL); - if (persistDelta.rx[index] > SUMMARY_PERSIST_THRESHOLD - || persistDelta.tx[index] > SUMMARY_PERSIST_THRESHOLD) { - writeStatsLocked(); - mLastPersistStats = current; - break; - } - } } - private NetworkStatsHistory findOrCreateHistoryLocked(InterfaceIdentity ident) { - NetworkStatsHistory stats = mStats.get(ident); + /** + * Update {@link #mDetailStats} historical usage. + */ + private void performDetailPollLocked(NetworkStats detail, long currentTime) { + final NetworkStats delta = computeStatsDelta(mLastDetailPoll, detail); + final long timeStart = currentTime - delta.elapsedRealtime; + final long maxHistory = mDetailMaxHistory.get(); + for (int uid : delta.getUniqueUids()) { + final int index = delta.findIndex(IFACE_ALL, uid); + final long rx = delta.rx[index]; + final long tx = delta.tx[index]; + + final NetworkStatsHistory history = findOrCreateDetailLocked(uid); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - maxHistory); + } + mLastDetailPoll = detail; + } + + private NetworkStatsHistory findOrCreateSummaryLocked(InterfaceIdentity ident) { + NetworkStatsHistory stats = mSummaryStats.get(ident); if (stats == null) { - stats = new NetworkStatsHistory(SUMMARY_BUCKET_DURATION); - mStats.put(ident, stats); + stats = new NetworkStatsHistory(mSummaryBucketDuration.get()); + mSummaryStats.put(ident, stats); + } + return stats; + } + + private NetworkStatsHistory findOrCreateDetailLocked(int uid) { + NetworkStatsHistory stats = mDetailStats.get(uid); + if (stats == null) { + stats = new NetworkStatsHistory(mDetailBucketDuration.get()); + mDetailStats.put(uid, stats); } return stats; } @@ -380,18 +440,89 @@ public class NetworkStatsService extends INetworkStatsService.Stub { protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); - pw.println("Active interfaces:"); - for (String iface : mActiveIface.keySet()) { - final InterfaceIdentity ident = mActiveIface.get(iface); - pw.print(" iface="); pw.print(iface); - pw.print(" ident="); pw.println(ident.toString()); + final HashSet argSet = new HashSet(); + for (String arg : args) { + argSet.add(arg); } - pw.println("Known historical stats:"); - for (InterfaceIdentity ident : mStats.keySet()) { - final NetworkStatsHistory stats = mStats.get(ident); - pw.print(" ident="); pw.println(ident.toString()); - stats.dump(" ", pw); + synchronized (mStatsLock) { + // TODO: remove this testing code, since it corrupts stats + if (argSet.contains("generate")) { + generateRandomLocked(); + pw.println("Generated stub stats"); + return; + } + + pw.println("Active interfaces:"); + for (String iface : mActiveIface.keySet()) { + final InterfaceIdentity ident = mActiveIface.get(iface); + pw.print(" iface="); pw.print(iface); + pw.print(" ident="); pw.println(ident.toString()); + } + + pw.println("Known historical stats:"); + for (InterfaceIdentity ident : mSummaryStats.keySet()) { + final NetworkStatsHistory stats = mSummaryStats.get(ident); + pw.print(" ident="); pw.println(ident.toString()); + stats.dump(" ", pw); + } + + if (argSet.contains("detail")) { + pw.println("Known detail stats:"); + for (int i = 0; i < mDetailStats.size(); i++) { + final int uid = mDetailStats.keyAt(i); + final NetworkStatsHistory stats = mDetailStats.valueAt(i); + pw.print(" UID="); pw.println(uid); + stats.dump(" ", pw); + } + } + } + } + + /** + * @deprecated only for temporary testing + */ + @Deprecated + private void generateRandomLocked() { + long end = System.currentTimeMillis(); + long start = end - mSummaryMaxHistory.get(); + long rx = 3 * GB_IN_BYTES; + long tx = 2 * GB_IN_BYTES; + + mSummaryStats.clear(); + for (InterfaceIdentity ident : mActiveIface.values()) { + final NetworkStatsHistory stats = findOrCreateSummaryLocked(ident); + stats.generateRandom(start, end, rx, tx); + } + + end = System.currentTimeMillis(); + start = end - mDetailMaxHistory.get(); + rx = 500 * MB_IN_BYTES; + tx = 100 * MB_IN_BYTES; + + mDetailStats.clear(); + for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) { + final int uid = info.uid; + final NetworkStatsHistory stats = findOrCreateDetailLocked(uid); + stats.generateRandom(start, end, rx, tx); + } + } + + private class LongSecureSetting { + private String mKey; + private long mDefaultValue; + + public LongSecureSetting(String key, long defaultValue) { + mKey = key; + mDefaultValue = defaultValue; + } + + public long get() { + if (mContext != null) { + return Settings.Secure.getLong(mContext.getContentResolver(), mKey, mDefaultValue); + } else { + return mDefaultValue; + } } } From 0b1cfc0d552a548cd232f2a60f18615b7accd170 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 2 Jun 2011 17:38:22 -0700 Subject: [PATCH 0037/1150] Compute range-based usage in NetworkStatsHistory. When given a start/end range, interpolate between buckets to return the total network usage. Used to summarize detailed UID stats. Method to combine NetworkStatsHistory regardless of bucket size. Used to combine all histories matching a template. Added tests for both methods. Change-Id: Ia463910c0ecf7cf08dcf97c658ad99742bd6b882 --- .../java/android/net/NetworkStatsHistory.java | 40 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 19 +++++++-- 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 45d8e27645..5edbf5830d 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -133,6 +133,18 @@ public class NetworkStatsHistory implements Parcelable { } } + /** + * Record an entire {@link NetworkStatsHistory} into this history. Usually + * for combining together stats for external reporting. + */ + public void recordEntireHistory(NetworkStatsHistory input) { + for (int i = 0; i < input.bucketCount; i++) { + final long start = input.bucketStart[i]; + final long end = start + input.bucketDuration; + recordData(start, end, input.rx[i], input.tx[i]); + } + } + /** * Ensure that buckets exist for given time range, creating as needed. */ @@ -202,6 +214,34 @@ public class NetworkStatsHistory implements Parcelable { } } + /** + * Return interpolated data usage across the requested range. Interpolates + * across buckets, so values may be rounded slightly. + */ + public void getTotalData(long start, long end, long[] outTotal) { + long rx = 0; + long tx = 0; + + for (int i = bucketCount - 1; i >= 0; i--) { + final long curStart = bucketStart[i]; + final long curEnd = curStart + bucketDuration; + + // bucket is older than record; we're finished + if (curEnd < start) break; + // bucket is newer than record; keep looking + if (curStart > end) continue; + + final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); + if (overlap > 0) { + rx += this.rx[i] * overlap / bucketDuration; + tx += this.tx[i] * overlap / bucketDuration; + } + } + + outTotal[0] = rx; + outTotal[1] = tx; + } + /** * @deprecated only for temporary testing */ diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 967e491449..3892de8131 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -210,7 +210,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (InterfaceIdentity ident : mSummaryStats.keySet()) { final NetworkStatsHistory history = mSummaryStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { - // TODO: combine all matching history data into a single history + combined.recordEntireHistory(history); } } return combined; @@ -231,8 +231,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: create relaxed permission for reading stats mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); - // TODO: total UID-granularity usage between time range - return null; + // TODO: apply networktemplate once granular uid stats are stored. + + synchronized (mStatsLock) { + final int size = mDetailStats.size(); + final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size); + + final long[] total = new long[2]; + for (int i = 0; i < size; i++) { + final int uid = mDetailStats.keyAt(i); + final NetworkStatsHistory history = mDetailStats.valueAt(i); + history.getTotalData(start, end, total); + stats.addEntry(IFACE_ALL, uid, total[0], total[1]); + } + return stats.build(); + } } /** From 98693eb89ac85901a30fd900669208cafc956ff6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 5 Jun 2011 17:42:53 -0700 Subject: [PATCH 0038/1150] Persist network stats using AtomicFile. Implements read/write of network stats using AtomicFile, along with magic number and versioning. Stores in "/data/system/netstats.bin" for now. Tests to verify that stats are persisted across a simulated reboot, and to verify that TEMPLATE_WIFI is working. Fixed bug where kernel counters rolling backwards would cause negative stats to be recorded; now we clamp deltas at 0. Change-Id: I53bce26fc8fd3f4ab1e34ce135d302edfa34db34 --- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 37 ++++- .../java/android/net/NetworkStatsHistory.java | 6 +- core/java/android/net/TrafficStats.java | 4 +- .../server/net/NetworkStatsService.java | 131 ++++++++++++++++-- 5 files changed, 160 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index d38d16c4e7..d05c9d3969 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -28,6 +28,6 @@ interface INetworkStatsService { NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryPerUid(long start, long end, int networkTemplate); + NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate); } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ee415fa6bc..6354e9a65e 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -153,6 +153,30 @@ public class NetworkStats implements Parcelable { return result; } + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + * + * @throws IllegalArgumentException when given {@link NetworkStats} is + * non-monotonic. + */ + public NetworkStats subtract(NetworkStats value) { + return subtract(value, true, false); + } + + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + *

+ * Instead of throwing when counters are non-monotonic, this variant clamps + * results to never be negative. + */ + public NetworkStats subtractClamped(NetworkStats value) { + return subtract(value, false, true); + } + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over @@ -160,8 +184,11 @@ public class NetworkStats implements Parcelable { * * @param enforceMonotonic Validate that incoming value is strictly * monotonic compared to this object. + * @param clampNegative Instead of throwing like {@code enforceMonotonic}, + * clamp resulting counters at 0 to prevent negative values. */ - public NetworkStats subtract(NetworkStats value, boolean enforceMonotonic) { + private NetworkStats subtract( + NetworkStats value, boolean enforceMonotonic, boolean clampNegative) { final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; if (enforceMonotonic && deltaRealtime < 0) { throw new IllegalArgumentException("found non-monotonic realtime"); @@ -181,11 +208,15 @@ public class NetworkStats implements Parcelable { result.addEntry(iface, uid, this.rx[i], this.tx[i]); } else { // existing row, subtract remote value - final long rx = this.rx[i] - value.rx[j]; - final long tx = this.tx[i] - value.tx[j]; + long rx = this.rx[i] - value.rx[j]; + long tx = this.tx[i] - value.tx[j]; if (enforceMonotonic && (rx < 0 || tx < 0)) { throw new IllegalArgumentException("found non-monotonic values"); } + if (clampNegative) { + rx = Math.max(0, rx); + tx = Math.max(0, tx); + } result.addEntry(iface, uid, rx, tx); } } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 5edbf5830d..a697e96989 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -218,7 +218,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ - public void getTotalData(long start, long end, long[] outTotal) { + public long[] getTotalData(long start, long end, long[] outTotal) { long rx = 0; long tx = 0; @@ -238,8 +238,12 @@ public class NetworkStatsHistory implements Parcelable { } } + if (outTotal == null || outTotal.length != 2) { + outTotal = new long[2]; + } outTotal[0] = rx; outTotal[1] = tx; + return outTotal; } /** diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a0738c1da2..8a688d55f7 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -177,8 +177,8 @@ public class TrafficStats { // subtract starting values and return delta final NetworkStats profilingStop = getNetworkStatsForUid(context); - final NetworkStats profilingDelta = profilingStop.subtract( - sActiveProfilingStart, false); + final NetworkStats profilingDelta = profilingStop.subtractClamped( + sActiveProfilingStart); sActiveProfilingStart = null; return profilingDelta; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 3892de8131..8db2839471 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -48,6 +48,7 @@ import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; @@ -60,15 +61,26 @@ import android.util.Slog; import android.util.SparseArray; import android.util.TrustedTime; +import com.android.internal.os.AtomicFile; import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; import java.io.PrintWriter; +import java.net.ProtocolException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import libcore.io.IoUtils; + /** * Collect and persist detailed network statistics, and provide this data to * other system services. @@ -77,6 +89,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStatsService"; private static final boolean LOGD = true; + /** File header magic number: "ANET" */ + private static final int FILE_MAGIC = 0x414E4554; + private static final int VERSION_CURRENT = 1; + private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -84,7 +100,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private IConnectivityManager mConnManager; - private static final String ACTION_NETWORK_STATS_POLL = + // @VisibleForTesting + public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; private PendingIntent mPollIntent; @@ -98,14 +115,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private LongSecureSetting mPollInterval = new LongSecureSetting( NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); private LongSecureSetting mPersistThreshold = new LongSecureSetting( - NETSTATS_PERSIST_THRESHOLD, 64 * KB_IN_BYTES); + NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); + // TODO: adjust these timings for production builds private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting( - NETSTATS_SUMMARY_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + NETSTATS_SUMMARY_BUCKET_DURATION, 1 * HOUR_IN_MILLIS); private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting( NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS); private LongSecureSetting mDetailBucketDuration = new LongSecureSetting( - NETSTATS_DETAIL_BUCKET_DURATION, 6 * HOUR_IN_MILLIS); + NETSTATS_DETAIL_BUCKET_DURATION, 2 * HOUR_IN_MILLIS); private LongSecureSetting mDetailMaxHistory = new LongSecureSetting( NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS); @@ -129,6 +147,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final HandlerThread mHandlerThread; private final Handler mHandler; + private final AtomicFile mSummaryFile; + // TODO: collect detailed uid stats, storing tag-granularity data until next // dropbox, and uid summary for a specific bucket count. @@ -137,11 +157,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { // TODO: move to using cached NtpTrustedTime - this(context, networkManager, alarmManager, new NtpTrustedTime()); + this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir()); + } + + private static File getSystemDir() { + return new File(Environment.getDataDirectory(), "system"); } public NetworkStatsService(Context context, INetworkManagementService networkManager, - IAlarmManager alarmManager, TrustedTime time) { + IAlarmManager alarmManager, TrustedTime time, File systemDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); @@ -150,11 +174,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); + + mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin")); } public void systemReady() { - // read historical stats from disk - readStatsLocked(); + synchronized (mStatsLock) { + // read historical stats from disk + readStatsLocked(); + } // watch other system services that claim interfaces final IntentFilter ifaceFilter = new IntentFilter(); @@ -180,6 +208,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); } + private void shutdownLocked() { + mContext.unregisterReceiver(mIfaceReceiver); + mContext.unregisterReceiver(mPollReceiver); + mContext.unregisterReceiver(mShutdownReceiver); + + writeStatsLocked(); + mSummaryStats.clear(); + mDetailStats.clear(); + } + /** * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link #mPollInterval} value. @@ -227,7 +265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStats getSummaryPerUid(long start, long end, int networkTemplate) { + public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) { // TODO: create relaxed permission for reading stats mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); @@ -281,7 +319,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // verified SHUTDOWN permission above. synchronized (mStatsLock) { - writeStatsLocked(); + shutdownLocked(); } } }; @@ -440,13 +478,74 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void readStatsLocked() { if (LOGD) Slog.v(TAG, "readStatsLocked()"); - // TODO: read historical stats from disk using AtomicFile + + // clear any existing stats and read from disk + mSummaryStats.clear(); + + FileInputStream fis = null; + try { + fis = mSummaryFile.openRead(); + final DataInputStream in = new DataInputStream(fis); + + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_CURRENT: { + // file format is pairs of interfaces and stats: + // summary := size *(InterfaceIdentity NetworkStatsHistory) + + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final InterfaceIdentity ident = new InterfaceIdentity(in); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + mSummaryStats.put(ident, history); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } catch (FileNotFoundException e) { + // missing stats is okay, probably first boot + } catch (IOException e) { + Slog.e(TAG, "problem reading network stats", e); + } finally { + IoUtils.closeQuietly(fis); + } } private void writeStatsLocked() { if (LOGD) Slog.v(TAG, "writeStatsLocked()"); - // TODO: persist historical stats to disk using AtomicFile + // TODO: consider duplicating stats and releasing lock while writing + + FileOutputStream fos = null; + try { + fos = mSummaryFile.startWrite(); + final DataOutputStream out = new DataOutputStream(fos); + + out.writeInt(FILE_MAGIC); + out.writeInt(VERSION_CURRENT); + + out.writeInt(mSummaryStats.size()); + for (InterfaceIdentity ident : mSummaryStats.keySet()) { + final NetworkStatsHistory history = mSummaryStats.get(ident); + ident.writeToStream(out); + history.writeToStream(out); + } + + mSummaryFile.finishWrite(fos); + } catch (IOException e) { + if (fos != null) { + mSummaryFile.failWrite(fos); + } + } } @Override @@ -466,6 +565,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + if (argSet.contains("poll")) { + performPollLocked(); + pw.println("Forced poll"); + return; + } + pw.println("Active interfaces:"); for (String iface : mActiveIface.keySet()) { final InterfaceIdentity ident = mActiveIface.get(iface); @@ -545,7 +650,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) { if (before != null) { - return current.subtract(before, false); + return current.subtractClamped(before); } else { return current; } From 9d12bd28735eca04da978bb6d268a39976d0c9a1 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 7 Jun 2011 12:26:43 -0700 Subject: [PATCH 0039/1150] Interface-level network policy, persist policies. Define NetworkPolicy as cycle-reset day and warning/limit values, and set/get through NetworkPolicyManager. Watch ConnectivityManager for network connection events, and apply quota rules based on matching interfaces. Policy service matches based on strong identity to support IMSI-specific policy values. Calculates remaining quota based on current stats recorded since the last reset cycle day. Tests to verify edge cases around February. Persist network and UID policies in XML, and restore on boot. Change-Id: Id40ba7d6eed6094fbd5e18e6331286c606880d80 --- .../android/net/INetworkStatsService.aidl | 2 + .../server/net/NetworkStatsService.java | 56 +++++++++++++------ 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index d05c9d3969..288112a25c 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -27,6 +27,8 @@ interface INetworkStatsService { /** Return historical stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); + /** Return usage summary for traffic that matches template. */ + NetworkStats getSummaryForNetwork(long start, long end, int networkTemplate, String subscriberId); /** Return usage summary per UID for traffic that matches template. */ NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 8db2839471..161c3937e6 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -18,8 +18,8 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.SHUTDOWN; -import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.UID_ALL; @@ -86,7 +86,7 @@ import libcore.io.IoUtils; * other system services. */ public class NetworkStatsService extends INetworkStatsService.Stub { - private static final String TAG = "NetworkStatsService"; + private static final String TAG = "NetworkStats"; private static final boolean LOGD = true; /** File header magic number: "ANET" */ @@ -178,20 +178,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin")); } + public void bindConnectivityManager(IConnectivityManager connManager) { + mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); + } + public void systemReady() { synchronized (mStatsLock) { // read historical stats from disk readStatsLocked(); } - // watch other system services that claim interfaces + // watch for network interfaces to be claimed final IntentFilter ifaceFilter = new IntentFilter(); ifaceFilter.addAction(CONNECTIVITY_ACTION); mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events + // TODO: switch to stronger internal permission final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); - mContext.registerReceiver(mPollReceiver, pollFilter, UPDATE_DEVICE_STATS, mHandler); + mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); // persist stats during clean shutdown final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); @@ -204,10 +209,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - private void shutdownLocked() { mContext.unregisterReceiver(mIfaceReceiver); mContext.unregisterReceiver(mPollReceiver); @@ -237,8 +238,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) { - // TODO: create relaxed permission for reading stats - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { // combine all interfaces that match template @@ -257,17 +257,41 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) { - // TODO: create relaxed permission for reading stats - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); // TODO: return history for requested uid return null; } + @Override + public NetworkStats getSummaryForNetwork( + long start, long end, int networkTemplate, String subscriberId) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + + synchronized (mStatsLock) { + long rx = 0; + long tx = 0; + long[] networkTotal = new long[2]; + + // combine total from all interfaces that match template + for (InterfaceIdentity ident : mSummaryStats.keySet()) { + final NetworkStatsHistory history = mSummaryStats.get(ident); + if (ident.matchesTemplate(networkTemplate, subscriberId)) { + networkTotal = history.getTotalData(start, end, networkTotal); + rx += networkTotal[0]; + tx += networkTotal[1]; + } + } + + final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, 1); + stats.addEntry(IFACE_ALL, UID_ALL, tx, tx); + return stats.build(); + } + } + @Override public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) { - // TODO: create relaxed permission for reading stats - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); // TODO: apply networktemplate once granular uid stats are stored. @@ -275,11 +299,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int size = mDetailStats.size(); final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size); - final long[] total = new long[2]; + long[] total = new long[2]; for (int i = 0; i < size; i++) { final int uid = mDetailStats.keyAt(i); final NetworkStatsHistory history = mDetailStats.valueAt(i); - history.getTotalData(start, end, total); + total = history.getTotalData(start, end, total); stats.addEntry(IFACE_ALL, uid, total[0], total[1]); } return stats.build(); From 6fc33809a73488164278f3f2a66ac8a43625e2be Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 11 Jun 2011 17:25:42 -0700 Subject: [PATCH 0040/1150] Persist UID stats, lazy loading, resize buckets. Persisting detailed UID stats in separate "netstats_detail.bin" file to enable different schedules for summary and detail polling. Only load detailed UID history on demand, since it's not needed during boot. Add test to verify UID stats are persisted across simulated reboot. Move external settings into well-named interface, which is still backed by Settings.Secure. During periodic poll events, resize any history to match current bucket duration setting. Test to verify. Change-Id: I6366f3583a591f8ba859b0e5987daf8cafa4e95a --- .../server/net/NetworkStatsService.java | 435 ++++++++++++------ 1 file changed, 298 insertions(+), 137 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 161c3937e6..f5d01d6c22 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -23,12 +23,12 @@ import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.UID_ALL; -import static android.provider.Settings.Secure.NETSTATS_DETAIL_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_DETAIL_MAX_HISTORY; +import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Secure.NETSTATS_SUMMARY_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_SUMMARY_MAX_HISTORY; +import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -38,6 +38,7 @@ import android.app.AlarmManager; import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -88,6 +89,7 @@ import libcore.io.IoUtils; public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStats"; private static final boolean LOGD = true; + private static final boolean LOGV = false; /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; @@ -97,6 +99,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; private final TrustedTime mTime; + private final NetworkStatsSettings mSettings; private IConnectivityManager mConnManager; @@ -112,22 +115,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; - private LongSecureSetting mPollInterval = new LongSecureSetting( - NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); - private LongSecureSetting mPersistThreshold = new LongSecureSetting( - NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); - - // TODO: adjust these timings for production builds - private LongSecureSetting mSummaryBucketDuration = new LongSecureSetting( - NETSTATS_SUMMARY_BUCKET_DURATION, 1 * HOUR_IN_MILLIS); - private LongSecureSetting mSummaryMaxHistory = new LongSecureSetting( - NETSTATS_SUMMARY_MAX_HISTORY, 90 * DAY_IN_MILLIS); - private LongSecureSetting mDetailBucketDuration = new LongSecureSetting( - NETSTATS_DETAIL_BUCKET_DURATION, 2 * HOUR_IN_MILLIS); - private LongSecureSetting mDetailMaxHistory = new LongSecureSetting( - NETSTATS_DETAIL_MAX_HISTORY, 90 * DAY_IN_MILLIS); - - private static final long TIME_CACHE_MAX_AGE = DAY_IN_MILLIS; + /** + * Settings that can be changed externally. + */ + public interface NetworkStatsSettings { + public long getPollInterval(); + public long getPersistThreshold(); + public long getNetworkBucketDuration(); + public long getNetworkMaxHistory(); + public long getUidBucketDuration(); + public long getUidMaxHistory(); + public long getTimeCacheMaxAge(); + } private final Object mStatsLock = new Object(); @@ -135,19 +134,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private HashMap mActiveIface = Maps.newHashMap(); /** Set of historical stats for known ifaces. */ - private HashMap mSummaryStats = Maps.newHashMap(); + private HashMap mNetworkStats = Maps.newHashMap(); /** Set of historical stats for known UIDs. */ - private SparseArray mDetailStats = new SparseArray(); + private SparseArray mUidStats = new SparseArray(); - private NetworkStats mLastSummaryPoll; - private NetworkStats mLastSummaryPersist; + /** Flag if {@link #mUidStats} have been loaded from disk. */ + private boolean mUidStatsLoaded = false; - private NetworkStats mLastDetailPoll; + private NetworkStats mLastNetworkPoll; + private NetworkStats mLastNetworkPersist; + + private NetworkStats mLastUidPoll; private final HandlerThread mHandlerThread; private final Handler mHandler; - private final AtomicFile mSummaryFile; + private final AtomicFile mNetworkFile; + private final AtomicFile mUidFile; // TODO: collect detailed uid stats, storing tag-granularity data until next // dropbox, and uid summary for a specific bucket count. @@ -157,7 +160,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { // TODO: move to using cached NtpTrustedTime - this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir()); + this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(), + new DefaultNetworkStatsSettings(context)); } private static File getSystemDir() { @@ -165,17 +169,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public NetworkStatsService(Context context, INetworkManagementService networkManager, - IAlarmManager alarmManager, TrustedTime time, File systemDir) { + IAlarmManager alarmManager, TrustedTime time, File systemDir, + NetworkStatsSettings settings) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); + mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); - mSummaryFile = new AtomicFile(new File(systemDir, "netstats.bin")); + mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin")); + mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin")); } public void bindConnectivityManager(IConnectivityManager connManager) { @@ -184,8 +191,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void systemReady() { synchronized (mStatsLock) { - // read historical stats from disk - readStatsLocked(); + // read historical network stats from disk, since policy service + // might need them right away. we delay loading detailed UID stats + // until actually needed. + readNetworkStatsLocked(); } // watch for network interfaces to be claimed @@ -214,14 +223,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mShutdownReceiver); - writeStatsLocked(); - mSummaryStats.clear(); - mDetailStats.clear(); + writeNetworkStatsLocked(); + writeUidStatsLocked(); + mNetworkStats.clear(); + mUidStats.clear(); + mUidStatsLoaded = false; } /** * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and - * reschedule based on current {@link #mPollInterval} value. + * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ private void registerPollAlarmLocked() throws RemoteException { if (mPollIntent != null) { @@ -232,8 +243,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating( - AlarmManager.ELAPSED_REALTIME, currentRealtime, mPollInterval.get(), mPollIntent); + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, + mSettings.getPollInterval(), mPollIntent); } @Override @@ -244,9 +255,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // combine all interfaces that match template final String subscriberId = getActiveSubscriberId(); final NetworkStatsHistory combined = new NetworkStatsHistory( - mSummaryBucketDuration.get()); - for (InterfaceIdentity ident : mSummaryStats.keySet()) { - final NetworkStatsHistory history = mSummaryStats.get(ident); + mSettings.getNetworkBucketDuration()); + for (InterfaceIdentity ident : mNetworkStats.keySet()) { + final NetworkStatsHistory history = mNetworkStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { combined.recordEntireHistory(history); } @@ -259,8 +270,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - // TODO: return history for requested uid - return null; + synchronized (mStatsLock) { + // TODO: combine based on template, if we store that granularity + ensureUidStatsLoadedLocked(); + return mUidStats.get(uid); + } } @Override @@ -274,8 +288,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { long[] networkTotal = new long[2]; // combine total from all interfaces that match template - for (InterfaceIdentity ident : mSummaryStats.keySet()) { - final NetworkStatsHistory history = mSummaryStats.get(ident); + for (InterfaceIdentity ident : mNetworkStats.keySet()) { + final NetworkStatsHistory history = mNetworkStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { networkTotal = history.getTotalData(start, end, networkTotal); rx += networkTotal[0]; @@ -296,13 +310,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: apply networktemplate once granular uid stats are stored. synchronized (mStatsLock) { - final int size = mDetailStats.size(); + ensureUidStatsLoadedLocked(); + + final int size = mUidStats.size(); final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size); long[] total = new long[2]; for (int i = 0; i < size; i++) { - final int uid = mDetailStats.keyAt(i); - final NetworkStatsHistory history = mDetailStats.valueAt(i); + final int uid = mUidStats.keyAt(i); + final NetworkStatsHistory history = mUidStats.valueAt(i); total = history.getTotalData(start, end, total); stats.addEntry(IFACE_ALL, uid, total[0], total[1]); } @@ -333,7 +349,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // permission above. synchronized (mStatsLock) { // TODO: acquire wakelock while performing poll - performPollLocked(); + performPollLocked(true); } } }; @@ -355,13 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link InterfaceIdentity}. */ private void updateIfacesLocked() { - if (LOGD) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from // the updated network. - // TODO: verify that we only poll summary stats, not uid details - performPollLocked(); + performPollLocked(false); final NetworkState[] states; try { @@ -384,11 +399,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void performPollLocked() { - if (LOGD) Slog.v(TAG, "performPollLocked()"); + /** + * Periodic poll operation, reading current statistics and recording into + * {@link NetworkStatsHistory}. + * + * @param detailedPoll Indicate if detailed UID stats should be collected + * during this poll operation. + */ + private void performPollLocked(boolean detailedPoll) { + if (LOGV) Slog.v(TAG, "performPollLocked()"); // try refreshing time source when stale - if (mTime.getCacheAge() > TIME_CACHE_MAX_AGE) { + if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { mTime.forceRefresh(); } @@ -396,42 +418,45 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats summary; - final NetworkStats detail; + final NetworkStats networkStats; + final NetworkStats uidStats; try { - summary = mNetworkManager.getNetworkStatsSummary(); - detail = mNetworkManager.getNetworkStatsDetail(); + networkStats = mNetworkManager.getNetworkStatsSummary(); + uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } - performSummaryPollLocked(summary, currentTime); - performDetailPollLocked(detail, currentTime); + performNetworkPollLocked(networkStats, currentTime); + if (detailedPoll) { + performUidPollLocked(uidStats, currentTime); + } // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastSummaryPersist, summary); - final long persistThreshold = mPersistThreshold.get(); + final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats); + final long persistThreshold = mSettings.getPersistThreshold(); for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL); if (persistDelta.rx[index] > persistThreshold || persistDelta.tx[index] > persistThreshold) { - writeStatsLocked(); - mLastSummaryPersist = summary; + writeNetworkStatsLocked(); + writeUidStatsLocked(); + mLastNetworkPersist = networkStats; break; } } } /** - * Update {@link #mSummaryStats} historical usage. + * Update {@link #mNetworkStats} historical usage. */ - private void performSummaryPollLocked(NetworkStats summary, long currentTime) { + private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) { final ArrayList unknownIface = Lists.newArrayList(); - final NetworkStats delta = computeStatsDelta(mLastSummaryPoll, summary); + final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mSummaryMaxHistory.get(); + final long maxHistory = mSettings.getNetworkMaxHistory(); for (String iface : delta.getUniqueIfaces()) { final InterfaceIdentity ident = mActiveIface.get(iface); if (ident == null) { @@ -443,11 +468,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long rx = delta.rx[index]; final long tx = delta.tx[index]; - final NetworkStatsHistory history = findOrCreateSummaryLocked(ident); + final NetworkStatsHistory history = findOrCreateNetworkLocked(ident); history.recordData(timeStart, currentTime, rx, tx); history.removeBucketsBefore(currentTime - maxHistory); } - mLastSummaryPoll = summary; + mLastNetworkPoll = networkStats; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); @@ -455,40 +480,69 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Update {@link #mDetailStats} historical usage. + * Update {@link #mUidStats} historical usage. */ - private void performDetailPollLocked(NetworkStats detail, long currentTime) { - final NetworkStats delta = computeStatsDelta(mLastDetailPoll, detail); + private void performUidPollLocked(NetworkStats uidStats, long currentTime) { + ensureUidStatsLoadedLocked(); + + final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mDetailMaxHistory.get(); + final long maxHistory = mSettings.getUidMaxHistory(); for (int uid : delta.getUniqueUids()) { + // TODO: traverse all ifaces once surfaced in stats final int index = delta.findIndex(IFACE_ALL, uid); - final long rx = delta.rx[index]; - final long tx = delta.tx[index]; + if (index != -1) { + final long rx = delta.rx[index]; + final long tx = delta.tx[index]; - final NetworkStatsHistory history = findOrCreateDetailLocked(uid); - history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - maxHistory); + final NetworkStatsHistory history = findOrCreateUidLocked(uid); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - maxHistory); + } } - mLastDetailPoll = detail; + mLastUidPoll = uidStats; } - private NetworkStatsHistory findOrCreateSummaryLocked(InterfaceIdentity ident) { - NetworkStatsHistory stats = mSummaryStats.get(ident); - if (stats == null) { - stats = new NetworkStatsHistory(mSummaryBucketDuration.get()); - mSummaryStats.put(ident, stats); + private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) { + final long bucketDuration = mSettings.getNetworkBucketDuration(); + final NetworkStatsHistory existing = mNetworkStats.get(ident); + + // update when no existing, or when bucket duration changed + NetworkStatsHistory updated = null; + if (existing == null) { + updated = new NetworkStatsHistory(bucketDuration); + } else if (existing.bucketDuration != bucketDuration) { + updated = new NetworkStatsHistory(bucketDuration); + updated.recordEntireHistory(existing); + } + + if (updated != null) { + mNetworkStats.put(ident, updated); + return updated; + } else { + return existing; } - return stats; } - private NetworkStatsHistory findOrCreateDetailLocked(int uid) { - NetworkStatsHistory stats = mDetailStats.get(uid); - if (stats == null) { - stats = new NetworkStatsHistory(mDetailBucketDuration.get()); - mDetailStats.put(uid, stats); + private NetworkStatsHistory findOrCreateUidLocked(int uid) { + final long bucketDuration = mSettings.getUidBucketDuration(); + final NetworkStatsHistory existing = mUidStats.get(uid); + + // update when no existing, or when bucket duration changed + NetworkStatsHistory updated = null; + if (existing == null) { + updated = new NetworkStatsHistory(bucketDuration); + } else if (existing.bucketDuration != bucketDuration) { + updated = new NetworkStatsHistory(bucketDuration); + updated.recordEntireHistory(existing); + } + + if (updated != null) { + mUidStats.put(uid, updated); + return updated; + } else { + return existing; } - return stats; } private InterfaceIdentity findOrCreateInterfaceLocked(String iface) { @@ -500,15 +554,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return ident; } - private void readStatsLocked() { - if (LOGD) Slog.v(TAG, "readStatsLocked()"); + private void readNetworkStatsLocked() { + if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()"); // clear any existing stats and read from disk - mSummaryStats.clear(); + mNetworkStats.clear(); FileInputStream fis = null; try { - fis = mSummaryFile.openRead(); + fis = mNetworkFile.openRead(); final DataInputStream in = new DataInputStream(fis); // verify file magic header intact @@ -521,13 +575,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { switch (version) { case VERSION_CURRENT: { // file format is pairs of interfaces and stats: - // summary := size *(InterfaceIdentity NetworkStatsHistory) + // network := size *(InterfaceIdentity NetworkStatsHistory) final int size = in.readInt(); for (int i = 0; i < size; i++) { final InterfaceIdentity ident = new InterfaceIdentity(in); final NetworkStatsHistory history = new NetworkStatsHistory(in); - mSummaryStats.put(ident, history); + + mNetworkStats.put(ident, history); } break; } @@ -544,30 +599,113 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void writeStatsLocked() { - if (LOGD) Slog.v(TAG, "writeStatsLocked()"); + private void ensureUidStatsLoadedLocked() { + if (!mUidStatsLoaded) { + readUidStatsLocked(); + mUidStatsLoaded = true; + } + } + + private void readUidStatsLocked() { + if (LOGV) Slog.v(TAG, "readUidStatsLocked()"); + + // clear any existing stats and read from disk + mUidStats.clear(); + + FileInputStream fis = null; + try { + fis = mUidFile.openRead(); + final DataInputStream in = new DataInputStream(fis); + + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_CURRENT: { + // file format is pairs of UIDs and stats: + // uid := size *(UID NetworkStatsHistory) + + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final int uid = in.readInt(); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + + mUidStats.put(uid, history); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } catch (FileNotFoundException e) { + // missing stats is okay, probably first boot + } catch (IOException e) { + Slog.e(TAG, "problem reading uid stats", e); + } finally { + IoUtils.closeQuietly(fis); + } + } + + private void writeNetworkStatsLocked() { + if (LOGV) Slog.v(TAG, "writeNetworkStatsLocked()"); // TODO: consider duplicating stats and releasing lock while writing FileOutputStream fos = null; try { - fos = mSummaryFile.startWrite(); + fos = mNetworkFile.startWrite(); final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); out.writeInt(VERSION_CURRENT); - out.writeInt(mSummaryStats.size()); - for (InterfaceIdentity ident : mSummaryStats.keySet()) { - final NetworkStatsHistory history = mSummaryStats.get(ident); + out.writeInt(mNetworkStats.size()); + for (InterfaceIdentity ident : mNetworkStats.keySet()) { + final NetworkStatsHistory history = mNetworkStats.get(ident); ident.writeToStream(out); history.writeToStream(out); } - mSummaryFile.finishWrite(fos); + mNetworkFile.finishWrite(fos); } catch (IOException e) { if (fos != null) { - mSummaryFile.failWrite(fos); + mNetworkFile.failWrite(fos); + } + } + } + + private void writeUidStatsLocked() { + if (LOGV) Slog.v(TAG, "writeUidStatsLocked()"); + + // TODO: consider duplicating stats and releasing lock while writing + + FileOutputStream fos = null; + try { + fos = mUidFile.startWrite(); + final DataOutputStream out = new DataOutputStream(fos); + + out.writeInt(FILE_MAGIC); + out.writeInt(VERSION_CURRENT); + + final int size = mUidStats.size(); + + out.writeInt(size); + for (int i = 0; i < size; i++) { + final int uid = mUidStats.keyAt(i); + final NetworkStatsHistory history = mUidStats.valueAt(i); + out.writeInt(uid); + history.writeToStream(out); + } + + mUidFile.finishWrite(fos); + } catch (IOException e) { + if (fos != null) { + mUidFile.failWrite(fos); } } } @@ -590,7 +728,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(); + performPollLocked(true); pw.println("Forced poll"); return; } @@ -603,17 +741,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } pw.println("Known historical stats:"); - for (InterfaceIdentity ident : mSummaryStats.keySet()) { - final NetworkStatsHistory stats = mSummaryStats.get(ident); + for (InterfaceIdentity ident : mNetworkStats.keySet()) { + final NetworkStatsHistory stats = mNetworkStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); stats.dump(" ", pw); } if (argSet.contains("detail")) { - pw.println("Known detail stats:"); - for (int i = 0; i < mDetailStats.size(); i++) { - final int uid = mDetailStats.keyAt(i); - final NetworkStatsHistory stats = mDetailStats.valueAt(i); + // since explicitly requested with argument, we're okay to load + // from disk if not already in memory. + ensureUidStatsLoadedLocked(); + pw.println("Known UID stats:"); + for (int i = 0; i < mUidStats.size(); i++) { + final int uid = mUidStats.keyAt(i); + final NetworkStatsHistory stats = mUidStats.valueAt(i); pw.print(" UID="); pw.println(uid); stats.dump(" ", pw); } @@ -627,47 +768,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Deprecated private void generateRandomLocked() { long end = System.currentTimeMillis(); - long start = end - mSummaryMaxHistory.get(); + long start = end - mSettings.getNetworkMaxHistory(); long rx = 3 * GB_IN_BYTES; long tx = 2 * GB_IN_BYTES; - mSummaryStats.clear(); + mNetworkStats.clear(); for (InterfaceIdentity ident : mActiveIface.values()) { - final NetworkStatsHistory stats = findOrCreateSummaryLocked(ident); + final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident); stats.generateRandom(start, end, rx, tx); } end = System.currentTimeMillis(); - start = end - mDetailMaxHistory.get(); + start = end - mSettings.getUidMaxHistory(); rx = 500 * MB_IN_BYTES; tx = 100 * MB_IN_BYTES; - mDetailStats.clear(); + mUidStats.clear(); for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) { final int uid = info.uid; - final NetworkStatsHistory stats = findOrCreateDetailLocked(uid); + final NetworkStatsHistory stats = findOrCreateUidLocked(uid); stats.generateRandom(start, end, rx, tx); } } - private class LongSecureSetting { - private String mKey; - private long mDefaultValue; - - public LongSecureSetting(String key, long defaultValue) { - mKey = key; - mDefaultValue = defaultValue; - } - - public long get() { - if (mContext != null) { - return Settings.Secure.getLong(mContext.getContentResolver(), mKey, mDefaultValue); - } else { - return mDefaultValue; - } - } - } - /** * Return the delta between two {@link NetworkStats} snapshots, where {@code * before} can be {@code null}. @@ -686,4 +809,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return telephony.getSubscriberId(); } + /** + * Default external settings that read from {@link Settings.Secure}. + */ + private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { + private final ContentResolver mResolver; + + public DefaultNetworkStatsSettings(Context context) { + mResolver = checkNotNull(context.getContentResolver()); + // TODO: adjust these timings for production builds + } + + private long getSecureLong(String name, long def) { + return Settings.Secure.getLong(mResolver, name, def); + } + + public long getPollInterval() { + return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); + } + public long getPersistThreshold() { + return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); + } + public long getNetworkBucketDuration() { + return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); + } + public long getNetworkMaxHistory() { + return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS); + } + public long getUidBucketDuration() { + return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS); + } + public long getUidMaxHistory() { + return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS); + } + public long getTimeCacheMaxAge() { + return DAY_IN_MILLIS; + } + } + } From 755000588f551684e713f2b57eb4e5fd9edd0152 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 11 Jun 2011 22:16:55 -0700 Subject: [PATCH 0041/1150] Growable NetworkStats object instead of builder. NetworkStats now grows in place with arraycopy() instead of callers needing to know record count a priori. Better growth calculation for both NetworkStats and NetworkStatsHistory; 50% each time. Better estimates of buckets needed in calling services. Change-Id: I3adbffa0b7407612cc6349d9135a8b4eb63cd440 --- core/java/android/net/NetworkStats.java | 79 ++++++++----------- .../java/android/net/NetworkStatsHistory.java | 16 ++-- .../server/net/NetworkStatsService.java | 32 +++++--- 3 files changed, 66 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6354e9a65e..60f740e80f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -23,6 +23,7 @@ import android.util.SparseBooleanArray; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashSet; /** @@ -48,74 +49,60 @@ public class NetworkStats implements Parcelable { * generated. */ public final long elapsedRealtime; - public final String[] iface; - public final int[] uid; - public final long[] rx; - public final long[] tx; + public int size; + public String[] iface; + public int[] uid; + public long[] rx; + public long[] tx; // TODO: add fg/bg stats once reported by kernel - private NetworkStats(long elapsedRealtime, String[] iface, int[] uid, long[] rx, long[] tx) { + public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; - this.iface = iface; - this.uid = uid; - this.rx = rx; - this.tx = tx; + this.size = 0; + this.iface = new String[initialSize]; + this.uid = new int[initialSize]; + this.rx = new long[initialSize]; + this.tx = new long[initialSize]; } public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); + size = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); rx = parcel.createLongArray(); tx = parcel.createLongArray(); } - public static class Builder { - private long mElapsedRealtime; - private final String[] mIface; - private final int[] mUid; - private final long[] mRx; - private final long[] mTx; - - private int mIndex = 0; - - public Builder(long elapsedRealtime, int size) { - mElapsedRealtime = elapsedRealtime; - mIface = new String[size]; - mUid = new int[size]; - mRx = new long[size]; - mTx = new long[size]; + public NetworkStats addEntry(String iface, int uid, long rx, long tx) { + if (size >= this.iface.length) { + final int newLength = Math.max(this.iface.length, 10) * 3 / 2; + this.iface = Arrays.copyOf(this.iface, newLength); + this.uid = Arrays.copyOf(this.uid, newLength); + this.rx = Arrays.copyOf(this.rx, newLength); + this.tx = Arrays.copyOf(this.tx, newLength); } - public Builder addEntry(String iface, int uid, long rx, long tx) { - mIface[mIndex] = iface; - mUid[mIndex] = uid; - mRx[mIndex] = rx; - mTx[mIndex] = tx; - mIndex++; - return this; - } + this.iface[size] = iface; + this.uid[size] = uid; + this.rx[size] = rx; + this.tx[size] = tx; + size++; - public NetworkStats build() { - if (mIndex != mIface.length) { - throw new IllegalArgumentException("unexpected number of entries"); - } - return new NetworkStats(mElapsedRealtime, mIface, mUid, mRx, mTx); - } + return this; } + @Deprecated public int length() { - // length is identical for all fields - return iface.length; + return size; } /** * Find first stats index that matches the requested parameters. */ public int findIndex(String iface, int uid) { - final int length = length(); - for (int i = 0; i < length; i++) { + for (int i = 0; i < size; i++) { if (equal(iface, this.iface[i]) && uid == this.uid[i]) { return i; } @@ -195,9 +182,8 @@ public class NetworkStats implements Parcelable { } // result will have our rows, and elapsed time between snapshots - final int length = length(); - final NetworkStats.Builder result = new NetworkStats.Builder(deltaRealtime, length); - for (int i = 0; i < length; i++) { + final NetworkStats result = new NetworkStats(deltaRealtime, size); + for (int i = 0; i < size; i++) { final String iface = this.iface[i]; final int uid = this.uid[i]; @@ -221,7 +207,7 @@ public class NetworkStats implements Parcelable { } } - return result.build(); + return result; } private static boolean equal(Object a, Object b) { @@ -255,6 +241,7 @@ public class NetworkStats implements Parcelable { /** {@inheritDoc} */ public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); + dest.writeInt(size); dest.writeStringArray(iface); dest.writeIntArray(uid); dest.writeLongArray(rx); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a697e96989..5fa8e21a0c 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -53,11 +53,15 @@ public class NetworkStatsHistory implements Parcelable { public long[] tx; public NetworkStatsHistory(long bucketDuration) { + this(bucketDuration, 10); + } + + public NetworkStatsHistory(long bucketDuration, int initialSize) { this.bucketDuration = bucketDuration; - bucketStart = new long[0]; - rx = new long[0]; - tx = new long[0]; - bucketCount = bucketStart.length; + bucketStart = new long[initialSize]; + rx = new long[initialSize]; + tx = new long[initialSize]; + bucketCount = 0; } public NetworkStatsHistory(Parcel in) { @@ -168,8 +172,8 @@ public class NetworkStatsHistory implements Parcelable { */ private void insertBucket(int index, long start) { // create more buckets when needed - if (bucketCount + 1 > bucketStart.length) { - final int newLength = bucketStart.length + 10; + if (bucketCount >= bucketStart.length) { + final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); rx = Arrays.copyOf(rx, newLength); tx = Arrays.copyOf(tx, newLength); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f5d01d6c22..de69849b7d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -255,7 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // combine all interfaces that match template final String subscriberId = getActiveSubscriberId(); final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getNetworkBucketDuration()); + mSettings.getNetworkBucketDuration(), estimateNetworkBuckets()); for (InterfaceIdentity ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); if (ident.matchesTemplate(networkTemplate, subscriberId)) { @@ -297,9 +297,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, 1); + final NetworkStats stats = new NetworkStats(end - start, 1); stats.addEntry(IFACE_ALL, UID_ALL, tx, tx); - return stats.build(); + return stats; } } @@ -313,7 +313,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final int size = mUidStats.size(); - final NetworkStats.Builder stats = new NetworkStats.Builder(end - start, size); + final NetworkStats stats = new NetworkStats(end - start, size); long[] total = new long[2]; for (int i = 0; i < size; i++) { @@ -322,7 +322,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { total = history.getTotalData(start, end, total); stats.addEntry(IFACE_ALL, uid, total[0], total[1]); } - return stats.build(); + return stats; } } @@ -510,9 +510,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory(bucketDuration, 10); } else if (existing.bucketDuration != bucketDuration) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory( + bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); } @@ -531,9 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory(bucketDuration, 10); } else if (existing.bucketDuration != bucketDuration) { - updated = new NetworkStatsHistory(bucketDuration); + updated = new NetworkStatsHistory( + bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); } @@ -809,6 +811,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return telephony.getSubscriberId(); } + private int estimateNetworkBuckets() { + return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); + } + + private int estimateUidBuckets() { + return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration()); + } + + private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) { + return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); + } + /** * Default external settings that read from {@link Settings.Secure}. */ From 709e40027d92f988d9e19cf1d05cdf99cc981013 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 12 Jun 2011 21:13:51 -0700 Subject: [PATCH 0042/1150] External mutation of full NetworkPolicy set. Instead of embedding complex template coexistence rules into policy service, rely on external editors to enforce, and offer atomic get/set operations for full policy sets. Generate default mobile policy when none exists, using default of 4GB warning and cycle reset of current day. Dispatch listener events through Handler when holding internal lock, and catch CLASS_UNKNOWN networks in 3G_LOWER template. Change-Id: I063cf1eaf330e32b75d0697b89fc04488e6dfaea --- core/java/android/net/TrafficStats.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 8a688d55f7..3725fa64eb 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -41,11 +41,9 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - // TODO: find better home for these template constants - /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together. Only uses statistics for currently active IMSI. + * networks together. Only uses statistics for requested IMSI. * * @hide */ @@ -54,7 +52,7 @@ public class TrafficStats { /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together that roughly meet a "3G" definition, or lower. Only - * uses statistics for currently active IMSI. + * uses statistics for requested IMSI. * * @hide */ @@ -63,7 +61,7 @@ public class TrafficStats { /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together that meet a "4G" definition. Only uses statistics for - * currently active IMSI. + * requested IMSI. * * @hide */ @@ -184,6 +182,17 @@ public class TrafficStats { } } + /** {@hide} */ + public static boolean isNetworkTemplateMobile(int networkTemplate) { + switch (networkTemplate) { + case TEMPLATE_MOBILE_3G_LOWER: + case TEMPLATE_MOBILE_4G: + case TEMPLATE_MOBILE_ALL: + return true; + } + return false; + } + /** * Get the total number of packets transmitted through the mobile interface. * From 3ce93600fd8213e439082fbf104db877cab5f3ec Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 14 Jun 2011 17:27:29 -0700 Subject: [PATCH 0043/1150] Data usage warning and limit notifications. Watch for network statistics to cross NetworkPolicy warning or limit, and show notifications to user as needed. Currently checks during any statistics update, but will eventually move to event registration through netd when kernel supports. Fixed accounting bug in getSummaryForNetwork(). Only apply UID policy to applications; applying to system processes could break critical services like RIL. Change-Id: Iac0f20e910e205f3cbc54ec96395ff268b1aa379 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index de69849b7d..f762123a87 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -106,6 +106,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; + public static final String ACTION_NETWORK_STATS_UPDATED = + "com.android.server.action.NETWORK_STATS_UPDATED"; private PendingIntent mPollIntent; @@ -203,7 +205,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events - // TODO: switch to stronger internal permission final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); @@ -298,7 +299,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(IFACE_ALL, UID_ALL, tx, tx); + stats.addEntry(IFACE_ALL, UID_ALL, rx, tx); return stats; } } @@ -446,6 +447,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { break; } } + + // finally, dispatch updated event to any listeners + final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); + updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY); } /** From dbffe5a999a33d0c059d4e962719f244c0d03ebb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 17 Jun 2011 11:18:27 -0700 Subject: [PATCH 0044/1150] Avoid clobbering UID stats when not yet loaded. Bug: 4690822 Change-Id: Ia6c9e8f89e89739cf3380c4b98b9da6f52db48fa --- .../java/com/android/server/net/NetworkStatsService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f762123a87..0a84bc7372 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -225,7 +225,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mShutdownReceiver); writeNetworkStatsLocked(); - writeUidStatsLocked(); + if (mUidStatsLoaded) { + writeUidStatsLocked(); + } mNetworkStats.clear(); mUidStats.clear(); mUidStatsLoaded = false; @@ -442,7 +444,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (persistDelta.rx[index] > persistThreshold || persistDelta.tx[index] > persistThreshold) { writeNetworkStatsLocked(); - writeUidStatsLocked(); + if (mUidStatsLoaded) { + writeUidStatsLocked(); + } mLastNetworkPersist = networkStats; break; } From 0d5baa3f21fdd1272932fdb7d2f46d036f5e25fb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 18 Jun 2011 18:34:16 -0700 Subject: [PATCH 0045/1150] Read "qtaguid" network stats, refactor templates. Teach NMS to read qtaguid stats from kernel, but fall back to older stats when kernel doesn't support. Add "tags" to NetworkStats entries to support qtaguid. To work around double-reporting bug, subtract tagged stats from TAG_NONE entry. Flesh out stronger NetworkTemplate. All NetworkStatsService requests now require a template, and moved matching logic into template. Record UID stats keyed on complete NetworkIdentitySet definition, similar to how interface stats are stored. Since previous UID stats didn't have iface breakdown, discard during file format upgrade. Change-Id: I0447b5e7d205d73d28e71c889c568e536e91b8e4 --- .../android/net/INetworkStatsService.aidl | 9 +- core/java/android/net/NetworkIdentity.java | 107 ++++++ core/java/android/net/NetworkStats.java | 48 ++- .../java/android/net/NetworkStatsHistory.java | 14 +- core/java/android/net/NetworkTemplate.aidl | 19 + core/java/android/net/NetworkTemplate.java | 217 ++++++++++++ core/java/android/net/TrafficStats.java | 45 --- ...eIdentity.java => NetworkIdentitySet.java} | 49 ++- .../server/net/NetworkStatsService.java | 331 +++++++++++------- 9 files changed, 618 insertions(+), 221 deletions(-) create mode 100644 core/java/android/net/NetworkIdentity.java create mode 100644 core/java/android/net/NetworkTemplate.aidl create mode 100644 core/java/android/net/NetworkTemplate.java rename services/java/com/android/server/net/{InterfaceIdentity.java => NetworkIdentitySet.java} (53%) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 288112a25c..6371500f81 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -18,18 +18,19 @@ package android.net; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; /** {@hide} */ interface INetworkStatsService { /** Return historical stats for traffic that matches template. */ - NetworkStatsHistory getHistoryForNetwork(int networkTemplate); + NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); /** Return historical stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid); /** Return usage summary for traffic that matches template. */ - NetworkStats getSummaryForNetwork(long start, long end, int networkTemplate, String subscriberId); + NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate); + NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end); } diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java new file mode 100644 index 0000000000..f82d922f91 --- /dev/null +++ b/core/java/android/net/NetworkIdentity.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.ConnectivityManager.isNetworkTypeMobile; + +import android.content.Context; +import android.telephony.TelephonyManager; + +import com.android.internal.util.Objects; + +/** + * Network definition that includes strong identity. Analogous to combining + * {@link NetworkInfo} and an IMSI. + * + * @hide + */ +public class NetworkIdentity { + final int mType; + final int mSubType; + final String mSubscriberId; + + public NetworkIdentity(int type, int subType, String subscriberId) { + this.mType = type; + this.mSubType = subType; + this.mSubscriberId = subscriberId; + } + + @Override + public int hashCode() { + return Objects.hashCode(mType, mSubType, mSubscriberId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NetworkIdentity) { + final NetworkIdentity ident = (NetworkIdentity) obj; + return mType == ident.mType && mSubType == ident.mSubType + && Objects.equal(mSubscriberId, ident.mSubscriberId); + } + return false; + } + + @Override + public String toString() { + final String typeName = ConnectivityManager.getNetworkTypeName(mType); + final String subTypeName; + if (ConnectivityManager.isNetworkTypeMobile(mType)) { + subTypeName = TelephonyManager.getNetworkTypeName(mSubType); + } else { + subTypeName = Integer.toString(mSubType); + } + + final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId=" + + scrubSubscriberId + "]"; + } + + public int getType() { + return mType; + } + + public int getSubType() { + return mSubType; + } + + public String getSubscriberId() { + return mSubscriberId; + } + + /** + * Build a {@link NetworkIdentity} from the given {@link NetworkState}, + * assuming that any mobile networks are using the current IMSI. + */ + public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) { + final int type = state.networkInfo.getType(); + final int subType = state.networkInfo.getSubtype(); + + // TODO: consider moving subscriberId over to LinkCapabilities, so it + // comes from an authoritative source. + + final String subscriberId; + if (isNetworkTypeMobile(type)) { + final TelephonyManager telephony = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + subscriberId = telephony.getSubscriberId(); + } else { + subscriberId = null; + } + return new NetworkIdentity(type, subType, subscriberId); + } + +} diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 60f740e80f..9d40c42a39 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -40,9 +40,8 @@ public class NetworkStats implements Parcelable { public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; - - // NOTE: data should only be accounted for once in this structure; if data - // is broken out, the summarized version should not be included. + /** {@link #tag} value for without tag. */ + public static final int TAG_NONE = 0; /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was @@ -52,16 +51,16 @@ public class NetworkStats implements Parcelable { public int size; public String[] iface; public int[] uid; + public int[] tag; public long[] rx; public long[] tx; - // TODO: add fg/bg stats once reported by kernel - public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; this.iface = new String[initialSize]; this.uid = new int[initialSize]; + this.tag = new int[initialSize]; this.rx = new long[initialSize]; this.tx = new long[initialSize]; } @@ -71,21 +70,27 @@ public class NetworkStats implements Parcelable { size = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); + tag = parcel.createIntArray(); rx = parcel.createLongArray(); tx = parcel.createLongArray(); } - public NetworkStats addEntry(String iface, int uid, long rx, long tx) { + /** + * Add new stats entry with given values. + */ + public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) { if (size >= this.iface.length) { final int newLength = Math.max(this.iface.length, 10) * 3 / 2; this.iface = Arrays.copyOf(this.iface, newLength); this.uid = Arrays.copyOf(this.uid, newLength); + this.tag = Arrays.copyOf(this.tag, newLength); this.rx = Arrays.copyOf(this.rx, newLength); this.tx = Arrays.copyOf(this.tx, newLength); } this.iface[size] = iface; this.uid[size] = uid; + this.tag[size] = tag; this.rx[size] = rx; this.tx[size] = tx; size++; @@ -93,17 +98,29 @@ public class NetworkStats implements Parcelable { return this; } - @Deprecated - public int length() { - return size; + /** + * Combine given values with an existing row, or create a new row if + * {@link #findIndex(String, int, int)} is unable to find match. Can also be + * used to subtract values from existing rows. + */ + public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) { + final int i = findIndex(iface, uid, tag); + if (i == -1) { + // only create new entry when positive contribution + addEntry(iface, uid, tag, rx, tx); + } else { + this.rx[i] += rx; + this.tx[i] += tx; + } + return this; } /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid) { + public int findIndex(String iface, int uid, int tag) { for (int i = 0; i < size; i++) { - if (equal(iface, this.iface[i]) && uid == this.uid[i]) { + if (equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) { return i; } } @@ -186,12 +203,13 @@ public class NetworkStats implements Parcelable { for (int i = 0; i < size; i++) { final String iface = this.iface[i]; final int uid = this.uid[i]; + final int tag = this.tag[i]; // find remote row that matches, and subtract - final int j = value.findIndex(iface, uid); + final int j = value.findIndex(iface, uid, tag); if (j == -1) { // newly appearing row, return entire value - result.addEntry(iface, uid, this.rx[i], this.tx[i]); + result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]); } else { // existing row, subtract remote value long rx = this.rx[i] - value.rx[j]; @@ -203,7 +221,7 @@ public class NetworkStats implements Parcelable { rx = Math.max(0, rx); tx = Math.max(0, tx); } - result.addEntry(iface, uid, rx, tx); + result.addEntry(iface, uid, tag, rx, tx); } } @@ -221,6 +239,7 @@ public class NetworkStats implements Parcelable { pw.print(prefix); pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); + pw.print(" tag="); pw.print(tag[i]); pw.print(" rx="); pw.print(rx[i]); pw.print(" tx="); pw.println(tx[i]); } @@ -244,6 +263,7 @@ public class NetworkStats implements Parcelable { dest.writeInt(size); dest.writeStringArray(iface); dest.writeIntArray(uid); + dest.writeIntArray(tag); dest.writeLongArray(rx); dest.writeLongArray(tx); } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 5fa8e21a0c..ff6e220cac 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -40,10 +40,9 @@ import java.util.Random; * @hide */ public class NetworkStatsHistory implements Parcelable { - private static final int VERSION_CURRENT = 1; + private static final int VERSION_INIT = 1; - // TODO: teach about zigzag encoding to use less disk space - // TODO: teach how to convert between bucket sizes + // TODO: teach about varint encoding to use less disk space public final long bucketDuration; @@ -83,7 +82,7 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { + case VERSION_INIT: { bucketDuration = in.readLong(); bucketStart = readLongArray(in); rx = readLongArray(in); @@ -98,7 +97,7 @@ public class NetworkStatsHistory implements Parcelable { } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_INIT); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rx, bucketCount); @@ -115,6 +114,11 @@ public class NetworkStatsHistory implements Parcelable { * distribute across internal buckets, creating new buckets as needed. */ public void recordData(long start, long end, long rx, long tx) { + if (rx < 0 || tx < 0) { + throw new IllegalArgumentException( + "tried recording negative data: rx=" + rx + ", tx=" + tx); + } + // create any buckets needed by this range ensureBuckets(start, end); diff --git a/core/java/android/net/NetworkTemplate.aidl b/core/java/android/net/NetworkTemplate.aidl new file mode 100644 index 0000000000..3d37488d98 --- /dev/null +++ b/core/java/android/net/NetworkTemplate.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable NetworkTemplate; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java new file mode 100644 index 0000000000..9381f1dec3 --- /dev/null +++ b/core/java/android/net/NetworkTemplate.java @@ -0,0 +1,217 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; +import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; +import static android.telephony.TelephonyManager.getNetworkClass; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.Objects; + +/** + * Template definition used to generically match {@link NetworkIdentity}, + * usually when collecting statistics. + * + * @hide + */ +public class NetworkTemplate implements Parcelable { + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together. Only uses statistics for requested IMSI. + */ + public static final int MATCH_MOBILE_ALL = 1; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that roughly meet a "3G" definition, or lower. Only + * uses statistics for requested IMSI. + */ + public static final int MATCH_MOBILE_3G_LOWER = 2; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style + * networks together that meet a "4G" definition. Only uses statistics for + * requested IMSI. + */ + public static final int MATCH_MOBILE_4G = 3; + + /** + * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style + * networks together. + */ + public static final int MATCH_WIFI = 4; + + final int mMatchRule; + final String mSubscriberId; + + public NetworkTemplate(int matchRule, String subscriberId) { + this.mMatchRule = matchRule; + this.mSubscriberId = subscriberId; + } + + public NetworkTemplate(Parcel in) { + mMatchRule = in.readInt(); + mSubscriberId = in.readString(); + } + + /** {@inheritDoc} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mMatchRule); + dest.writeString(mSubscriberId); + } + + /** {@inheritDoc} */ + public int describeContents() { + return 0; + } + + @Override + public String toString() { + final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId=" + + scrubSubscriberId; + } + + @Override + public int hashCode() { + return Objects.hashCode(mMatchRule, mSubscriberId); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof NetworkTemplate) { + final NetworkTemplate other = (NetworkTemplate) obj; + return mMatchRule == other.mMatchRule + && Objects.equal(mSubscriberId, other.mSubscriberId); + } + return false; + } + + public int getMatchRule() { + return mMatchRule; + } + + public String getSubscriberId() { + return mSubscriberId; + } + + /** + * Test if this network matches the given template and IMEI. + */ + public boolean matches(NetworkIdentity ident) { + switch (mMatchRule) { + case MATCH_MOBILE_ALL: + return matchesMobile(ident); + case MATCH_MOBILE_3G_LOWER: + return matchesMobile3gLower(ident); + case MATCH_MOBILE_4G: + return matchesMobile4g(ident); + case MATCH_WIFI: + return matchesWifi(ident); + default: + throw new IllegalArgumentException("unknown network template"); + } + } + + /** + * Check if mobile network with matching IMEI. Also matches + * {@link #TYPE_WIMAX}. + */ + private boolean matchesMobile(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + return true; + } else if (ident.mType == TYPE_WIMAX) { + return true; + } + return false; + } + + /** + * Check if mobile network classified 3G or lower with matching IMEI. + */ + private boolean matchesMobile3gLower(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + switch (getNetworkClass(ident.mSubType)) { + case NETWORK_CLASS_UNKNOWN: + case NETWORK_CLASS_2_G: + case NETWORK_CLASS_3_G: + return true; + } + } + return false; + } + + /** + * Check if mobile network classified 4G with matching IMEI. Also matches + * {@link #TYPE_WIMAX}. + */ + private boolean matchesMobile4g(NetworkIdentity ident) { + if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + switch (getNetworkClass(ident.mSubType)) { + case NETWORK_CLASS_4_G: + return true; + } + } else if (ident.mType == TYPE_WIMAX) { + return true; + } + return false; + } + + /** + * Check if matches Wi-Fi network template. + */ + private boolean matchesWifi(NetworkIdentity ident) { + if (ident.mType == TYPE_WIFI) { + return true; + } + return false; + } + + public static String getMatchRuleName(int matchRule) { + switch (matchRule) { + case MATCH_MOBILE_3G_LOWER: + return "MOBILE_3G_LOWER"; + case MATCH_MOBILE_4G: + return "MOBILE_4G"; + case MATCH_MOBILE_ALL: + return "MOBILE_ALL"; + case MATCH_WIFI: + return "WIFI"; + default: + return "UNKNOWN"; + } + } + + public static final Creator CREATOR = new Creator() { + public NetworkTemplate createFromParcel(Parcel in) { + return new NetworkTemplate(in); + } + + public NetworkTemplate[] newArray(int size) { + return new NetworkTemplate[size]; + } + }; +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 3725fa64eb..e163abfebb 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -41,40 +41,6 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together. Only uses statistics for requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_ALL = 1; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that roughly meet a "3G" definition, or lower. Only - * uses statistics for requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_3G_LOWER = 2; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that meet a "4G" definition. Only uses statistics for - * requested IMSI. - * - * @hide - */ - public static final int TEMPLATE_MOBILE_4G = 3; - - /** - * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style - * networks together. - * - * @hide - */ - public static final int TEMPLATE_WIFI = 4; - /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -182,17 +148,6 @@ public class TrafficStats { } } - /** {@hide} */ - public static boolean isNetworkTemplateMobile(int networkTemplate) { - switch (networkTemplate) { - case TEMPLATE_MOBILE_3G_LOWER: - case TEMPLATE_MOBILE_4G: - case TEMPLATE_MOBILE_ALL: - return true; - } - return false; - } - /** * Get the total number of packets transmitted through the mobile interface. * diff --git a/services/java/com/android/server/net/InterfaceIdentity.java b/services/java/com/android/server/net/NetworkIdentitySet.java similarity index 53% rename from services/java/com/android/server/net/InterfaceIdentity.java rename to services/java/com/android/server/net/NetworkIdentitySet.java index ff86581eff..757d3bc92f 100644 --- a/services/java/com/android/server/net/InterfaceIdentity.java +++ b/services/java/com/android/server/net/NetworkIdentitySet.java @@ -16,6 +16,8 @@ package com.android.server.net; +import android.net.NetworkIdentity; + import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; @@ -28,19 +30,23 @@ import java.util.HashSet; * * @hide */ -public class InterfaceIdentity extends HashSet { - private static final int VERSION_CURRENT = 1; +public class NetworkIdentitySet extends HashSet { + private static final int VERSION_INIT = 1; - public InterfaceIdentity() { + public NetworkIdentitySet() { } - public InterfaceIdentity(DataInputStream in) throws IOException { + public NetworkIdentitySet(DataInputStream in) throws IOException { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { + case VERSION_INIT: { final int size = in.readInt(); for (int i = 0; i < size; i++) { - add(new NetworkIdentity(in)); + final int ignoredVersion = in.readInt(); + final int type = in.readInt(); + final int subType = in.readInt(); + final String subscriberId = readOptionalString(in); + add(new NetworkIdentity(type, subType, subscriberId)); } break; } @@ -51,23 +57,30 @@ public class InterfaceIdentity extends HashSet { } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_INIT); out.writeInt(size()); for (NetworkIdentity ident : this) { - ident.writeToStream(out); + out.writeInt(VERSION_INIT); + out.writeInt(ident.getType()); + out.writeInt(ident.getSubType()); + writeOptionalString(out, ident.getSubscriberId()); } } - /** - * Test if any {@link NetworkIdentity} on this interface matches the given - * template and IMEI. - */ - public boolean matchesTemplate(int networkTemplate, String subscriberId) { - for (NetworkIdentity ident : this) { - if (ident.matchesTemplate(networkTemplate, subscriberId)) { - return true; - } + private static void writeOptionalString(DataOutputStream out, String value) throws IOException { + if (value != null) { + out.writeByte(1); + out.writeUTF(value); + } else { + out.writeByte(0); + } + } + + private static String readOptionalString(DataInputStream in) throws IOException { + if (in.readByte() != 0) { + return in.readUTF(); + } else { + return null; } - return false; } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0a84bc7372..54a806a02d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -22,6 +22,7 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.SHUTDOWN; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; @@ -45,10 +46,12 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; import android.net.INetworkStatsService; +import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -63,8 +66,8 @@ import android.util.SparseArray; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; -import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import com.google.android.collect.Sets; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -76,9 +79,9 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.ProtocolException; -import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; +import java.util.List; import libcore.io.IoUtils; @@ -93,7 +96,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; - private static final int VERSION_CURRENT = 1; + private static final int VERSION_NETWORK_INIT = 1; + private static final int VERSION_UID_INIT = 1; + private static final int VERSION_UID_WITH_IDENT = 2; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -112,6 +117,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; // TODO: listen for kernel push events through netd instead of polling + // TODO: watch for UID uninstall, and transfer stats into single bucket private static final long KB_IN_BYTES = 1024; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; @@ -132,13 +138,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); - /** Set of active ifaces during this boot. */ - private HashMap mActiveIface = Maps.newHashMap(); - - /** Set of historical stats for known ifaces. */ - private HashMap mNetworkStats = Maps.newHashMap(); + /** Set of currently active ifaces. */ + private HashMap mActiveIfaces = Maps.newHashMap(); + /** Set of historical stats for known networks. */ + private HashMap mNetworkStats = Maps.newHashMap(); /** Set of historical stats for known UIDs. */ - private SparseArray mUidStats = new SparseArray(); + private HashMap> mUidStats = + Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; @@ -251,17 +257,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForNetwork(int networkTemplate) { + public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { // combine all interfaces that match template - final String subscriberId = getActiveSubscriberId(); final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getNetworkBucketDuration(), estimateNetworkBuckets()); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); - if (ident.matchesTemplate(networkTemplate, subscriberId)) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mNetworkStats.get(ident); combined.recordEntireHistory(history); } } @@ -270,19 +275,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForUid(int uid, int networkTemplate) { + public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { - // TODO: combine based on template, if we store that granularity ensureUidStatsLoadedLocked(); - return mUidStats.get(uid); + + // combine all interfaces that match template + final NetworkStatsHistory combined = new NetworkStatsHistory( + mSettings.getUidBucketDuration(), estimateUidBuckets()); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mUidStats.get(ident).get(uid); + if (history != null) { + combined.recordEntireHistory(history); + } + } + } + return combined; } } @Override - public NetworkStats getSummaryForNetwork( - long start, long end, int networkTemplate, String subscriberId) { + public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { @@ -291,9 +306,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { long[] networkTotal = new long[2]; // combine total from all interfaces that match template - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); - if (ident.matchesTemplate(networkTemplate, subscriberId)) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = mNetworkStats.get(ident); networkTotal = history.getTotalData(start, end, networkTotal); rx += networkTotal[0]; tx += networkTotal[1]; @@ -301,30 +316,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(IFACE_ALL, UID_ALL, rx, tx); + stats.addEntry(IFACE_ALL, UID_ALL, TAG_NONE, rx, tx); return stats; } } @Override - public NetworkStats getSummaryForAllUid(long start, long end, int networkTemplate) { + public NetworkStats getSummaryForAllUid(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - // TODO: apply networktemplate once granular uid stats are stored. - synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); - final int size = mUidStats.size(); - final NetworkStats stats = new NetworkStats(end - start, size); - + final NetworkStats stats = new NetworkStats(end - start, 24); long[] total = new long[2]; - for (int i = 0; i < size; i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory history = mUidStats.valueAt(i); - total = history.getTotalData(start, end, total); - stats.addEntry(IFACE_ALL, uid, total[0], total[1]); + + for (NetworkIdentitySet ident : mUidStats.keySet()) { + if (templateMatches(template, ident)) { + final SparseArray uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + total = history.getTotalData(start, end, total); + stats.combineEntry(IFACE_ALL, uid, TAG_NONE, total[0], total[1]); + } + } } + return stats; } } @@ -352,7 +370,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // permission above. synchronized (mStatsLock) { // TODO: acquire wakelock while performing poll - performPollLocked(true); + performPollLocked(true, false); } } }; @@ -371,7 +389,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} * are active on a single {@code iface}, they are combined under a single - * {@link InterfaceIdentity}. + * {@link NetworkIdentitySet}. */ private void updateIfacesLocked() { if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -379,7 +397,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from // the updated network. - performPollLocked(false); + performPollLocked(false, false); final NetworkState[] states; try { @@ -390,13 +408,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // rebuild active interfaces based on connected networks - mActiveIface.clear(); + mActiveIfaces.clear(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { // collect networks under their parent interfaces final String iface = state.linkProperties.getInterfaceName(); - final InterfaceIdentity ident = findOrCreateInterfaceLocked(iface); + + NetworkIdentitySet ident = mActiveIfaces.get(iface); + if (ident == null) { + ident = new NetworkIdentitySet(); + mActiveIfaces.put(iface, ident); + } + ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); } } @@ -409,7 +433,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * @param detailedPoll Indicate if detailed UID stats should be collected * during this poll operation. */ - private void performPollLocked(boolean detailedPoll) { + private void performPollLocked(boolean detailedPoll, boolean forcePersist) { if (LOGV) Slog.v(TAG, "performPollLocked()"); // try refreshing time source when stale @@ -421,33 +445,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats networkStats; + final NetworkStats ifaceStats; final NetworkStats uidStats; try { - networkStats = mNetworkManager.getNetworkStatsSummary(); + ifaceStats = mNetworkManager.getNetworkStatsSummary(); uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } - performNetworkPollLocked(networkStats, currentTime); + performNetworkPollLocked(ifaceStats, currentTime); if (detailedPoll) { performUidPollLocked(uidStats, currentTime); } // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, networkStats); + final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, ifaceStats); final long persistThreshold = mSettings.getPersistThreshold(); for (String iface : persistDelta.getUniqueIfaces()) { - final int index = persistDelta.findIndex(iface, UID_ALL); - if (persistDelta.rx[index] > persistThreshold + final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); + if (forcePersist || persistDelta.rx[index] > persistThreshold || persistDelta.tx[index] > persistThreshold) { writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); } - mLastNetworkPersist = networkStats; + mLastNetworkPersist = ifaceStats; break; } } @@ -462,23 +486,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Update {@link #mNetworkStats} historical usage. */ private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) { - final ArrayList unknownIface = Lists.newArrayList(); + final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats); final long timeStart = currentTime - delta.elapsedRealtime; final long maxHistory = mSettings.getNetworkMaxHistory(); - for (String iface : delta.getUniqueIfaces()) { - final InterfaceIdentity ident = mActiveIface.get(iface); + for (int i = 0; i < delta.size; i++) { + final String iface = delta.iface[i]; + final NetworkIdentitySet ident = mActiveIfaces.get(iface); if (ident == null) { unknownIface.add(iface); continue; } - final int index = delta.findIndex(iface, UID_ALL); - final long rx = delta.rx[index]; - final long tx = delta.tx[index]; + final long rx = delta.rx[i]; + final long tx = delta.tx[i]; - final NetworkStatsHistory history = findOrCreateNetworkLocked(ident); + final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); history.recordData(timeStart, currentTime, rx, tx); history.removeBucketsBefore(currentTime - maxHistory); } @@ -498,22 +522,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); final long timeStart = currentTime - delta.elapsedRealtime; final long maxHistory = mSettings.getUidMaxHistory(); - for (int uid : delta.getUniqueUids()) { - // TODO: traverse all ifaces once surfaced in stats - final int index = delta.findIndex(IFACE_ALL, uid); - if (index != -1) { - final long rx = delta.rx[index]; - final long tx = delta.tx[index]; - final NetworkStatsHistory history = findOrCreateUidLocked(uid); - history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - maxHistory); + // NOTE: historical UID stats ignore tags, and simply records all stats + // entries into a single UID bucket. + + for (int i = 0; i < delta.size; i++) { + final String iface = delta.iface[i]; + final NetworkIdentitySet ident = mActiveIfaces.get(iface); + if (ident == null) { + continue; } + + final int uid = delta.uid[i]; + final long rx = delta.rx[i]; + final long tx = delta.tx[i]; + + final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid); + history.recordData(timeStart, currentTime, rx, tx); + history.removeBucketsBefore(currentTime - maxHistory); } + mLastUidPoll = uidStats; } - private NetworkStatsHistory findOrCreateNetworkLocked(InterfaceIdentity ident) { + private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { final long bucketDuration = mSettings.getNetworkBucketDuration(); final NetworkStatsHistory existing = mNetworkStats.get(ident); @@ -535,9 +567,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStatsHistory findOrCreateUidLocked(int uid) { + private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) { + // find bucket for identity first, then find uid + SparseArray uidStats = mUidStats.get(ident); + if (uidStats == null) { + uidStats = new SparseArray(); + mUidStats.put(ident, uidStats); + } + final long bucketDuration = mSettings.getUidBucketDuration(); - final NetworkStatsHistory existing = mUidStats.get(uid); + final NetworkStatsHistory existing = uidStats.get(uid); // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; @@ -550,22 +589,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - mUidStats.put(uid, updated); + uidStats.put(uid, updated); return updated; } else { return existing; } } - private InterfaceIdentity findOrCreateInterfaceLocked(String iface) { - InterfaceIdentity ident = mActiveIface.get(iface); - if (ident == null) { - ident = new InterfaceIdentity(); - mActiveIface.put(iface, ident); - } - return ident; - } - private void readNetworkStatsLocked() { if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()"); @@ -585,15 +615,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { - // file format is pairs of interfaces and stats: - // network := size *(InterfaceIdentity NetworkStatsHistory) - + case VERSION_NETWORK_INIT: { + // network := size *(NetworkIdentitySet NetworkStatsHistory) final int size = in.readInt(); for (int i = 0; i < size; i++) { - final InterfaceIdentity ident = new InterfaceIdentity(in); + final NetworkIdentitySet ident = new NetworkIdentitySet(in); final NetworkStatsHistory history = new NetworkStatsHistory(in); - mNetworkStats.put(ident, history); } break; @@ -637,16 +664,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int version = in.readInt(); switch (version) { - case VERSION_CURRENT: { - // file format is pairs of UIDs and stats: + case VERSION_UID_INIT: { // uid := size *(UID NetworkStatsHistory) - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int uid = in.readInt(); - final NetworkStatsHistory history = new NetworkStatsHistory(in); + // drop this data version, since we don't have a good + // mapping into NetworkIdentitySet. + break; + } + case VERSION_UID_WITH_IDENT: { + // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) + final int ifaceSize = in.readInt(); + for (int i = 0; i < ifaceSize; i++) { + final NetworkIdentitySet ident = new NetworkIdentitySet(in); - mUidStats.put(uid, history); + final int uidSize = in.readInt(); + final SparseArray uidStats = new SparseArray< + NetworkStatsHistory>(uidSize); + for (int j = 0; j < uidSize; j++) { + final int uid = in.readInt(); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + uidStats.put(uid, history); + } + + mUidStats.put(ident, uidStats); } break; } @@ -674,10 +714,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_NETWORK_INIT); out.writeInt(mNetworkStats.size()); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); ident.writeToStream(out); history.writeToStream(out); @@ -702,16 +742,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_CURRENT); + out.writeInt(VERSION_UID_WITH_IDENT); - final int size = mUidStats.size(); + out.writeInt(mUidStats.size()); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + final SparseArray uidStats = mUidStats.get(ident); + ident.writeToStream(out); - out.writeInt(size); - for (int i = 0; i < size; i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory history = mUidStats.valueAt(i); - out.writeInt(uid); - history.writeToStream(out); + final int size = uidStats.size(); + out.writeInt(size); + for (int i = 0; i < size; i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + out.writeInt(uid); + history.writeToStream(out); + } } mUidFile.finishWrite(fos); @@ -740,35 +785,41 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(true); + performPollLocked(true, true); pw.println("Forced poll"); return; } pw.println("Active interfaces:"); - for (String iface : mActiveIface.keySet()) { - final InterfaceIdentity ident = mActiveIface.get(iface); + for (String iface : mActiveIfaces.keySet()) { + final NetworkIdentitySet ident = mActiveIfaces.get(iface); pw.print(" iface="); pw.print(iface); pw.print(" ident="); pw.println(ident.toString()); } pw.println("Known historical stats:"); - for (InterfaceIdentity ident : mNetworkStats.keySet()) { - final NetworkStatsHistory stats = mNetworkStats.get(ident); + for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + final NetworkStatsHistory history = mNetworkStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); - stats.dump(" ", pw); + history.dump(" ", pw); } if (argSet.contains("detail")) { // since explicitly requested with argument, we're okay to load // from disk if not already in memory. ensureUidStatsLoadedLocked(); - pw.println("Known UID stats:"); - for (int i = 0; i < mUidStats.size(); i++) { - final int uid = mUidStats.keyAt(i); - final NetworkStatsHistory stats = mUidStats.valueAt(i); - pw.print(" UID="); pw.println(uid); - stats.dump(" ", pw); + + pw.println("Detailed UID stats:"); + for (NetworkIdentitySet ident : mUidStats.keySet()) { + pw.print(" ident="); pw.println(ident.toString()); + + final SparseArray uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final int uid = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + pw.print(" UID="); pw.println(uid); + history.dump(" ", pw); + } } } } @@ -779,27 +830,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @Deprecated private void generateRandomLocked() { - long end = System.currentTimeMillis(); - long start = end - mSettings.getNetworkMaxHistory(); - long rx = 3 * GB_IN_BYTES; - long tx = 2 * GB_IN_BYTES; + long networkEnd = System.currentTimeMillis(); + long networkStart = networkEnd - mSettings.getNetworkMaxHistory(); + long networkRx = 3 * GB_IN_BYTES; + long networkTx = 2 * GB_IN_BYTES; + + long uidEnd = System.currentTimeMillis(); + long uidStart = uidEnd - mSettings.getUidMaxHistory(); + long uidRx = 500 * MB_IN_BYTES; + long uidTx = 100 * MB_IN_BYTES; + + final List installedApps = mContext + .getPackageManager().getInstalledApplications(0); mNetworkStats.clear(); - for (InterfaceIdentity ident : mActiveIface.values()) { - final NetworkStatsHistory stats = findOrCreateNetworkLocked(ident); - stats.generateRandom(start, end, rx, tx); - } - - end = System.currentTimeMillis(); - start = end - mSettings.getUidMaxHistory(); - rx = 500 * MB_IN_BYTES; - tx = 100 * MB_IN_BYTES; - mUidStats.clear(); - for (ApplicationInfo info : mContext.getPackageManager().getInstalledApplications(0)) { - final int uid = info.uid; - final NetworkStatsHistory stats = findOrCreateUidLocked(uid); - stats.generateRandom(start, end, rx, tx); + for (NetworkIdentitySet ident : mActiveIfaces.values()) { + findOrCreateNetworkStatsLocked(ident).generateRandom( + networkStart, networkEnd, networkRx, networkTx); + + for (ApplicationInfo info : installedApps) { + final int uid = info.uid; + findOrCreateUidStatsLocked(ident, uid).generateRandom( + uidStart, uidEnd, uidRx, uidTx); + } } } @@ -815,12 +869,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private String getActiveSubscriberId() { - final TelephonyManager telephony = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - return telephony.getSubscriberId(); - } - private int estimateNetworkBuckets() { return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); } @@ -833,6 +881,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); } + /** + * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} + * in the given {@link NetworkIdentitySet}. + */ + private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { + for (NetworkIdentity ident : identSet) { + if (template.matches(ident)) { + return true; + } + } + return false; + } + /** * Default external settings that read from {@link Settings.Secure}. */ From c04cda602cea3516023cce0541085807569e244e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 19 Jun 2011 01:08:12 -0700 Subject: [PATCH 0046/1150] Handle removed UIDs in network stats and policy. When UID_REMOVED, clean up any existing UID network policy so it doesn't linger for future apps. Also move any NetworkStatsHistory to special UID_REMOVED tracking bucket. Tests for new removal code. Also test detailed UID stats, including network changes to verify template matching logic. Bug: 4584212 Change-Id: I9faadf6b6f3830eb45d86c7f1980a27cdbcdb11e --- core/java/android/net/NetworkIdentity.java | 10 ++- core/java/android/net/TrafficStats.java | 8 +++ .../server/net/NetworkStatsService.java | 69 ++++++++++++++++--- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index f82d922f91..23ebbab659 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -95,9 +95,13 @@ public class NetworkIdentity { final String subscriberId; if (isNetworkTypeMobile(type)) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - subscriberId = telephony.getSubscriberId(); + if (state.subscriberId != null) { + subscriberId = state.subscriberId; + } else { + final TelephonyManager telephony = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + subscriberId = telephony.getSubscriberId(); + } } else { subscriberId = null; } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e163abfebb..cb47193a6e 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -41,6 +41,14 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; + /** + * Special UID value used when collecting {@link NetworkStatsHistory} for + * removed applications. + * + * @hide + */ + public static final int UID_REMOVED = -4; + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 54a806a02d..79612e33d6 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -19,11 +19,14 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; -import static android.Manifest.permission.SHUTDOWN; +import static android.content.Intent.ACTION_SHUTDOWN; +import static android.content.Intent.ACTION_UID_REMOVED; +import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.TrafficStats.UID_REMOVED; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -206,17 +209,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // watch for network interfaces to be claimed - final IntentFilter ifaceFilter = new IntentFilter(); - ifaceFilter.addAction(CONNECTIVITY_ACTION); - mContext.registerReceiver(mIfaceReceiver, ifaceFilter, CONNECTIVITY_INTERNAL, mHandler); + final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); + mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); + // listen for uid removal to clean stats + final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); + mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); + // persist stats during clean shutdown - final IntentFilter shutdownFilter = new IntentFilter(Intent.ACTION_SHUTDOWN); - mContext.registerReceiver(mShutdownReceiver, shutdownFilter, SHUTDOWN, null); + final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); + mContext.registerReceiver(mShutdownReceiver, shutdownFilter); try { registerPollAlarmLocked(); @@ -226,8 +232,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void shutdownLocked() { - mContext.unregisterReceiver(mIfaceReceiver); + mContext.unregisterReceiver(mConnReceiver); mContext.unregisterReceiver(mPollReceiver); + mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); writeNetworkStatsLocked(); @@ -352,7 +359,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} * with mobile interfaces. */ - private BroadcastReceiver mIfaceReceiver = new BroadcastReceiver() { + private BroadcastReceiver mConnReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL @@ -375,10 +382,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + private BroadcastReceiver mRemovedReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // on background handler thread, and UID_REMOVED is protected + // broadcast. + final int uid = intent.getIntExtra(EXTRA_UID, 0); + synchronized (mStatsLock) { + removeUidLocked(uid); + } + } + }; + private BroadcastReceiver mShutdownReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - // verified SHUTDOWN permission above. + // SHUTDOWN is protected broadcast. synchronized (mStatsLock) { shutdownLocked(); } @@ -545,6 +564,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastUidPoll = uidStats; } + /** + * Clean up {@link #mUidStats} after UID is removed. + */ + private void removeUidLocked(int uid) { + ensureUidStatsLoadedLocked(); + + // migrate all UID stats into special "removed" bucket + for (NetworkIdentitySet ident : mUidStats.keySet()) { + final SparseArray uidStats = mUidStats.get(ident); + final NetworkStatsHistory uidHistory = uidStats.get(uid); + if (uidHistory != null) { + final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( + ident, UID_REMOVED); + removedHistory.recordEntireHistory(uidHistory); + uidStats.remove(uid); + } + } + + // TODO: push kernel event to wipe stats for UID, otherwise we risk + // picking them up again during next poll. + + // since this was radical rewrite, push to disk + writeUidStatsLocked(); + } + private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { final long bucketDuration = mSettings.getNetworkBucketDuration(); final NetworkStatsHistory existing = mNetworkStats.get(ident); @@ -568,6 +612,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) { + ensureUidStatsLoadedLocked(); + // find bucket for identity first, then find uid SparseArray uidStats = mUidStats.get(ident); if (uidStats == null) { @@ -734,6 +780,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void writeUidStatsLocked() { if (LOGV) Slog.v(TAG, "writeUidStatsLocked()"); + if (!mUidStatsLoaded) { + Slog.w(TAG, "asked to write UID stats when not loaded; skipping"); + return; + } + // TODO: consider duplicating stats and releasing lock while writing FileOutputStream fos = null; From b590477065fae953a6ae48d07d2a4c9735352b6e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 19 Jun 2011 20:55:09 -0700 Subject: [PATCH 0047/1150] Persist "tagged" network stats along with UIDs. Now stores tags other than TAG_NONE (0x0), which are useful for app debugging. Combine UID and tag together into single long key, and expose tag data through AIDL when requested. Change NMS to track TAG_NONE as total UID traffic, matching the kernel definition. Added TAG_MAX_HISTORY to control how long tag-granularity statistics are stored; overall UID usage is still kept for UID_MAX_HISTORY. Fix bug to trim NetworkStatsHistory outside normal polling loops to catch non-active networks and UIDs. Test to verify UID and tag packing, and to verify that UID traffic on two networks are combined to match MOBILE_ALL template. Change-Id: If0e039416d9e7f63b1a39e04cddfb1133b5a78ee --- .../android/net/INetworkStatsService.aidl | 4 +- .../server/net/NetworkStatsService.java | 215 ++++++++++++------ 2 files changed, 151 insertions(+), 68 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 6371500f81..ae9aa05e0b 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -26,11 +26,11 @@ interface INetworkStatsService { /** Return historical stats for traffic that matches template. */ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); /** Return historical stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag); /** Return usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end); + NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 79612e33d6..043a581c88 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -31,6 +31,7 @@ import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; +import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; import static android.text.format.DateUtils.DAY_IN_MILLIS; @@ -63,9 +64,9 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; +import android.util.LongSparseArray; import android.util.NtpTrustedTime; import android.util.Slog; -import android.util.SparseArray; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; @@ -102,6 +103,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_NETWORK_INIT = 1; private static final int VERSION_UID_INIT = 1; private static final int VERSION_UID_WITH_IDENT = 2; + private static final int VERSION_UID_WITH_TAG = 3; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -122,6 +124,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: listen for kernel push events through netd instead of polling // TODO: watch for UID uninstall, and transfer stats into single bucket + // TODO: trim empty history objects entirely + private static final long KB_IN_BYTES = 1024; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; @@ -136,6 +140,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getNetworkMaxHistory(); public long getUidBucketDuration(); public long getUidMaxHistory(); + public long getTagMaxHistory(); public long getTimeCacheMaxAge(); } @@ -146,16 +151,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of historical stats for known networks. */ private HashMap mNetworkStats = Maps.newHashMap(); /** Set of historical stats for known UIDs. */ - private HashMap> mUidStats = + private HashMap> mUidStats = Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; - private NetworkStats mLastNetworkPoll; - private NetworkStats mLastNetworkPersist; + private NetworkStats mLastNetworkSnapshot; + private NetworkStats mLastPersistNetworkSnapshot; - private NetworkStats mLastUidPoll; + private NetworkStats mLastUidSnapshot; private final HandlerThread mHandlerThread; private final Handler mHandler; @@ -274,7 +279,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); - combined.recordEntireHistory(history); + if (history != null) { + combined.recordEntireHistory(history); + } } } return combined; @@ -282,18 +289,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid) { + public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); + final long packed = packUidAndTag(uid, tag); // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getUidBucketDuration(), estimateUidBuckets()); for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { - final NetworkStatsHistory history = mUidStats.get(ident).get(uid); + final NetworkStatsHistory history = mUidStats.get(ident).get(packed); if (history != null) { combined.recordEntireHistory(history); } @@ -329,7 +337,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStats getSummaryForAllUid(NetworkTemplate template, long start, long end) { + public NetworkStats getSummaryForAllUid( + NetworkTemplate template, long start, long end, boolean includeTags) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { @@ -340,12 +349,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { - final SparseArray uidStats = mUidStats.get(ident); + final LongSparseArray uidStats = mUidStats.get(ident); for (int i = 0; i < uidStats.size(); i++) { - final int uid = uidStats.keyAt(i); - final NetworkStatsHistory history = uidStats.valueAt(i); - total = history.getTotalData(start, end, total); - stats.combineEntry(IFACE_ALL, uid, TAG_NONE, total[0], total[1]); + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); + + // always include summary under TAG_NONE, and include + // other tags when requested. + if (tag == TAG_NONE || includeTags) { + final NetworkStatsHistory history = uidStats.valueAt(i); + total = history.getTotalData(start, end, total); + final long rx = total[0]; + final long tx = total[1]; + if (rx > 0 || tx > 0) { + stats.combineEntry(IFACE_ALL, uid, tag, rx, tx); + } + } } } } @@ -464,23 +484,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final NetworkStats ifaceStats; - final NetworkStats uidStats; + final NetworkStats networkSnapshot; + final NetworkStats uidSnapshot; try { - ifaceStats = mNetworkManager.getNetworkStatsSummary(); - uidStats = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; + networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; } catch (RemoteException e) { Slog.w(TAG, "problem reading network stats"); return; } - performNetworkPollLocked(ifaceStats, currentTime); + performNetworkPollLocked(networkSnapshot, currentTime); if (detailedPoll) { - performUidPollLocked(uidStats, currentTime); + performUidPollLocked(uidSnapshot, currentTime); } // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta(mLastNetworkPersist, ifaceStats); + final NetworkStats persistDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot); final long persistThreshold = mSettings.getPersistThreshold(); for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); @@ -490,7 +511,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (mUidStatsLoaded) { writeUidStatsLocked(); } - mLastNetworkPersist = ifaceStats; + mLastPersistNetworkSnapshot = networkSnapshot; break; } } @@ -504,12 +525,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Update {@link #mNetworkStats} historical usage. */ - private void performNetworkPollLocked(NetworkStats networkStats, long currentTime) { + private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet unknownIface = Sets.newHashSet(); - final NetworkStats delta = computeStatsDelta(mLastNetworkPoll, networkStats); + final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mSettings.getNetworkMaxHistory(); for (int i = 0; i < delta.size; i++) { final String iface = delta.iface[i]; final NetworkIdentitySet ident = mActiveIfaces.get(iface); @@ -523,9 +543,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); history.recordData(timeStart, currentTime, rx, tx); + } + + // trim any history beyond max + final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : mNetworkStats.values()) { history.removeBucketsBefore(currentTime - maxHistory); } - mLastNetworkPoll = networkStats; + + mLastNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); @@ -535,15 +561,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Update {@link #mUidStats} historical usage. */ - private void performUidPollLocked(NetworkStats uidStats, long currentTime) { + private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastUidPoll, uidStats); + final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot); final long timeStart = currentTime - delta.elapsedRealtime; - final long maxHistory = mSettings.getUidMaxHistory(); - - // NOTE: historical UID stats ignore tags, and simply records all stats - // entries into a single UID bucket. for (int i = 0; i < delta.size; i++) { final String iface = delta.iface[i]; @@ -553,15 +575,32 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final int uid = delta.uid[i]; + final int tag = delta.tag[i]; final long rx = delta.rx[i]; final long tx = delta.tx[i]; - final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid); + final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid, tag); history.recordData(timeStart, currentTime, rx, tx); - history.removeBucketsBefore(currentTime - maxHistory); } - mLastUidPoll = uidStats; + // trim any history beyond max + final long maxUidHistory = mSettings.getUidMaxHistory(); + final long maxTagHistory = mSettings.getTagMaxHistory(); + for (LongSparseArray uidStats : mUidStats.values()) { + for (int i = 0; i < uidStats.size(); i++) { + final long packed = uidStats.keyAt(i); + final NetworkStatsHistory history = uidStats.valueAt(i); + + // detailed tags are trimmed sooner than summary in TAG_NONE + if (unpackTag(packed) == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); + } + } + } + + mLastUidSnapshot = uidSnapshot; } /** @@ -572,13 +611,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // migrate all UID stats into special "removed" bucket for (NetworkIdentitySet ident : mUidStats.keySet()) { - final SparseArray uidStats = mUidStats.get(ident); - final NetworkStatsHistory uidHistory = uidStats.get(uid); - if (uidHistory != null) { - final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( - ident, UID_REMOVED); - removedHistory.recordEntireHistory(uidHistory); - uidStats.remove(uid); + final LongSparseArray uidStats = mUidStats.get(ident); + for (int i = 0; i < uidStats.size(); i++) { + final long packed = uidStats.keyAt(i); + if (unpackUid(packed) == uid) { + // only migrate combined TAG_NONE history + if (unpackTag(packed) == TAG_NONE) { + final NetworkStatsHistory uidHistory = uidStats.valueAt(i); + final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( + ident, UID_REMOVED, TAG_NONE); + removedHistory.recordEntireHistory(uidHistory); + } + uidStats.remove(packed); + } } } @@ -590,10 +635,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { - final long bucketDuration = mSettings.getNetworkBucketDuration(); final NetworkStatsHistory existing = mNetworkStats.get(ident); // update when no existing, or when bucket duration changed + final long bucketDuration = mSettings.getNetworkBucketDuration(); NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); @@ -611,20 +656,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStatsHistory findOrCreateUidStatsLocked(NetworkIdentitySet ident, int uid) { + private NetworkStatsHistory findOrCreateUidStatsLocked( + NetworkIdentitySet ident, int uid, int tag) { ensureUidStatsLoadedLocked(); - // find bucket for identity first, then find uid - SparseArray uidStats = mUidStats.get(ident); + LongSparseArray uidStats = mUidStats.get(ident); if (uidStats == null) { - uidStats = new SparseArray(); + uidStats = new LongSparseArray(); mUidStats.put(ident, uidStats); } - final long bucketDuration = mSettings.getUidBucketDuration(); - final NetworkStatsHistory existing = uidStats.get(uid); + final long packed = packUidAndTag(uid, tag); + final NetworkStatsHistory existing = uidStats.get(packed); // update when no existing, or when bucket duration changed + final long bucketDuration = mSettings.getUidBucketDuration(); NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); @@ -635,7 +681,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - uidStats.put(uid, updated); + uidStats.put(packed, updated); return updated; } else { return existing; @@ -719,17 +765,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } case VERSION_UID_WITH_IDENT: { // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) + + // drop this data version, since this version only existed + // for a short time. + break; + } + case VERSION_UID_WITH_TAG: { + // uid := size *(NetworkIdentitySet size *(UID tag NetworkStatsHistory)) final int ifaceSize = in.readInt(); for (int i = 0; i < ifaceSize; i++) { final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final int uidSize = in.readInt(); - final SparseArray uidStats = new SparseArray< - NetworkStatsHistory>(uidSize); - for (int j = 0; j < uidSize; j++) { + final int childSize = in.readInt(); + final LongSparseArray uidStats = new LongSparseArray< + NetworkStatsHistory>(childSize); + for (int j = 0; j < childSize; j++) { final int uid = in.readInt(); + final int tag = in.readInt(); + final long packed = packUidAndTag(uid, tag); + final NetworkStatsHistory history = new NetworkStatsHistory(in); - uidStats.put(uid, history); + uidStats.put(packed, history); } mUidStats.put(ident, uidStats); @@ -793,19 +849,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final DataOutputStream out = new DataOutputStream(fos); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UID_WITH_IDENT); + out.writeInt(VERSION_UID_WITH_TAG); - out.writeInt(mUidStats.size()); + final int size = mUidStats.size(); + out.writeInt(size); for (NetworkIdentitySet ident : mUidStats.keySet()) { - final SparseArray uidStats = mUidStats.get(ident); + final LongSparseArray uidStats = mUidStats.get(ident); ident.writeToStream(out); - final int size = uidStats.size(); - out.writeInt(size); - for (int i = 0; i < size; i++) { - final int uid = uidStats.keyAt(i); + final int childSize = uidStats.size(); + out.writeInt(childSize); + for (int i = 0; i < childSize; i++) { + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); final NetworkStatsHistory history = uidStats.valueAt(i); out.writeInt(uid); + out.writeInt(tag); history.writeToStream(out); } } @@ -864,11 +924,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mUidStats.keySet()) { pw.print(" ident="); pw.println(ident.toString()); - final SparseArray uidStats = mUidStats.get(ident); + final LongSparseArray uidStats = mUidStats.get(ident); for (int i = 0; i < uidStats.size(); i++) { - final int uid = uidStats.keyAt(i); + final long packed = uidStats.keyAt(i); + final int uid = unpackUid(packed); + final int tag = unpackTag(packed); final NetworkStatsHistory history = uidStats.valueAt(i); - pw.print(" UID="); pw.println(uid); + pw.print(" UID="); pw.print(uid); + pw.print(" tag="); pw.println(tag); history.dump(" ", pw); } } @@ -902,7 +965,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (ApplicationInfo info : installedApps) { final int uid = info.uid; - findOrCreateUidStatsLocked(ident, uid).generateRandom( + findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom( uidStart, uidEnd, uidRx, uidTx); } } @@ -932,6 +995,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); } + // @VisibleForTesting + public static long packUidAndTag(int uid, int tag) { + final long uidLong = uid; + final long tagLong = tag; + return (uidLong << 32) | (tagLong & 0xFFFFFFFFL); + } + + // @VisibleForTesting + public static int unpackUid(long packed) { + return (int) (packed >> 32); + } + + // @VisibleForTesting + public static int unpackTag(long packed) { + return (int) (packed & 0xFFFFFFFFL); + } + /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. @@ -978,6 +1058,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory() { return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS); } + public long getTagMaxHistory() { + return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS); + } public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } From 3bc842e4c34168749bc4e7b2eff9a313760997a1 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 19 Jun 2011 22:21:05 -0700 Subject: [PATCH 0048/1150] Teach NetworkIdentity about roaming. And correctly upgrade NetworkIdentitySet written to disk, assuming that old values aren't roaming. Bug: 4724762 Change-Id: Ic25897ebbaf43be2390174d8e5fd08386bc8a345 --- core/java/android/net/NetworkIdentity.java | 23 ++++++++++++++----- .../server/net/NetworkIdentitySet.java | 18 ++++++++++++--- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 23ebbab659..ccef122c0a 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -33,11 +33,13 @@ public class NetworkIdentity { final int mType; final int mSubType; final String mSubscriberId; + final boolean mRoaming; - public NetworkIdentity(int type, int subType, String subscriberId) { + public NetworkIdentity(int type, int subType, String subscriberId, boolean roaming) { this.mType = type; this.mSubType = subType; this.mSubscriberId = subscriberId; + this.mRoaming = roaming; } @Override @@ -50,7 +52,8 @@ public class NetworkIdentity { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType - && Objects.equal(mSubscriberId, ident.mSubscriberId); + && Objects.equal(mSubscriberId, ident.mSubscriberId) + && mRoaming == ident.mRoaming; } return false; } @@ -66,8 +69,9 @@ public class NetworkIdentity { } final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + final String roaming = mRoaming ? ", ROAMING" : ""; return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId=" - + scrubSubscriberId + "]"; + + scrubSubscriberId + roaming + "]"; } public int getType() { @@ -82,6 +86,10 @@ public class NetworkIdentity { return mSubscriberId; } + public boolean getRoaming() { + return mRoaming; + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. @@ -94,18 +102,21 @@ public class NetworkIdentity { // comes from an authoritative source. final String subscriberId; + final boolean roaming; if (isNetworkTypeMobile(type)) { + final TelephonyManager telephony = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + roaming = telephony.isNetworkRoaming(); if (state.subscriberId != null) { subscriberId = state.subscriberId; } else { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); subscriberId = telephony.getSubscriberId(); } } else { subscriberId = null; + roaming = false; } - return new NetworkIdentity(type, subType, subscriberId); + return new NetworkIdentity(type, subType, subscriberId, roaming); } } diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/java/com/android/server/net/NetworkIdentitySet.java index 757d3bc92f..af03fb3182 100644 --- a/services/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/java/com/android/server/net/NetworkIdentitySet.java @@ -32,6 +32,7 @@ import java.util.HashSet; */ public class NetworkIdentitySet extends HashSet { private static final int VERSION_INIT = 1; + private static final int VERSION_ADD_ROAMING = 2; public NetworkIdentitySet() { } @@ -46,7 +47,18 @@ public class NetworkIdentitySet extends HashSet { final int type = in.readInt(); final int subType = in.readInt(); final String subscriberId = readOptionalString(in); - add(new NetworkIdentity(type, subType, subscriberId)); + add(new NetworkIdentity(type, subType, subscriberId, false)); + } + break; + } + case VERSION_ADD_ROAMING: { + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final int type = in.readInt(); + final int subType = in.readInt(); + final String subscriberId = readOptionalString(in); + final boolean roaming = in.readBoolean(); + add(new NetworkIdentity(type, subType, subscriberId, roaming)); } break; } @@ -57,13 +69,13 @@ public class NetworkIdentitySet extends HashSet { } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_INIT); + out.writeInt(VERSION_ADD_ROAMING); out.writeInt(size()); for (NetworkIdentity ident : this) { - out.writeInt(VERSION_INIT); out.writeInt(ident.getType()); out.writeInt(ident.getSubType()); writeOptionalString(out, ident.getSubscriberId()); + out.writeBoolean(ident.getRoaming()); } } From 2e546ddbde3f98b52b72ff7cb4643468e7e23f1b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 22 Jun 2011 16:32:41 -0700 Subject: [PATCH 0049/1150] Enable bandwidth module from stats service. During systemReady(), tell netd to enable bandwidth tracking module, which is used to provide detailed stats and controls. Change-Id: Iecfd8b17a3b90f5a817d731fbe1c71777681ed6e --- .../android/server/net/NetworkStatsService.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 043a581c88..a80bc043a4 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; +import static android.provider.Settings.Secure.NETSTATS_ENABLED; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -134,6 +135,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { + public boolean getEnabled(); public long getPollInterval(); public long getPersistThreshold(); public long getNetworkBucketDuration(); @@ -206,6 +208,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { + if (mSettings.getEnabled()) { + try { + // enable low-level bandwidth stats and control + // TODO: consider shipping with this enabled by default + mNetworkManager.setBandwidthControlEnabled(true); + } catch (RemoteException e) { + Slog.e(TAG, "problem enabling bandwidth controls", e); + } + } else { + Slog.w(TAG, "detailed network stats disabled"); + } + synchronized (mStatsLock) { // read historical network stats from disk, since policy service // might need them right away. we delay loading detailed UID stats @@ -1040,6 +1054,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return Settings.Secure.getLong(mResolver, name, def); } + public boolean getEnabled() { + return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 1) != 0; + } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); } From 27cb1fa96b4cc19270502468475a8de09fc46079 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Thu, 23 Jun 2011 14:13:28 -0700 Subject: [PATCH 0050/1150] NetworkStatsService: check kernel bandwidth support before enabling And catch the actual errors reported by the other side of NetworkManager. Change-Id: I9a9393b659d6f896ee1bf40a8deaca7853ef8f94 Signed-off-by: JP Abgrall --- .../java/com/android/server/net/NetworkStatsService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index a80bc043a4..524dd40905 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -71,6 +71,7 @@ import android.util.Slog; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; +import com.android.server.NativeDaemonConnectorException; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -214,7 +215,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider shipping with this enabled by default mNetworkManager.setBandwidthControlEnabled(true); } catch (RemoteException e) { - Slog.e(TAG, "problem enabling bandwidth controls", e); + Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e); + } catch (NativeDaemonConnectorException ndce) { + Slog.e(TAG, "problem enabling bandwidth controls", ndce); } } else { Slog.w(TAG, "detailed network stats disabled"); @@ -1055,6 +1058,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public boolean getEnabled() { + if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) { + Slog.w(TAG, "kernel does not support bandwidth control"); + return false; + } return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 1) != 0; } public long getPollInterval() { From f6cc17c9d1176d2bd04ac230258f8ee1da0c06cc Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Thu, 23 Jun 2011 14:13:28 -0700 Subject: [PATCH 0051/1150] NetworkStatsService: check kernel bandwidth support before enabling And catch the actual errors reported by the other side of NetworkManager. Change-Id: I9a9393b659d6f896ee1bf40a8deaca7853ef8f94 Signed-off-by: JP Abgrall --- .../java/com/android/server/net/NetworkStatsService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index a80bc043a4..524dd40905 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -71,6 +71,7 @@ import android.util.Slog; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; +import com.android.server.NativeDaemonConnectorException; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -214,7 +215,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider shipping with this enabled by default mNetworkManager.setBandwidthControlEnabled(true); } catch (RemoteException e) { - Slog.e(TAG, "problem enabling bandwidth controls", e); + Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e); + } catch (NativeDaemonConnectorException ndce) { + Slog.e(TAG, "problem enabling bandwidth controls", ndce); } } else { Slog.w(TAG, "detailed network stats disabled"); @@ -1055,6 +1058,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public boolean getEnabled() { + if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) { + Slog.w(TAG, "kernel does not support bandwidth control"); + return false; + } return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 1) != 0; } public long getPollInterval() { From 2778a1ea732f6a3888c81c15eecab1d90c4c3b87 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Mon, 27 Jun 2011 22:16:04 -0700 Subject: [PATCH 0052/1150] NetworkStatsService: disabled by default For now, there is still too much breakage around the kernel's new qtaguid netfilter. So no netstats up front. But enable on the device until wiped: ./vendor/google/tools/override-gservices secure:netstats_enabled=1 adb reboot Bug: 4903513 Change-Id: I230bd2d4efab85cac5c9abaa7d638c94f5e0c7d6 Signed-off-by: JP Abgrall --- services/java/com/android/server/net/NetworkStatsService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 524dd40905..4a79d17ad8 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1062,7 +1062,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Slog.w(TAG, "kernel does not support bandwidth control"); return false; } - return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 1) != 0; + // TODO: once things stabilize, enable by default. + // For now: ./vendor/google/tools/override-gservices secure:netstats_enabled=1 + return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 0) != 0; } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); From 9279006a00b6574a9cec0ce4db319ca5df061009 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 24 Jun 2011 17:05:24 -0700 Subject: [PATCH 0053/1150] Better network stats parsing, integer tags, async. Change NMS parsing to handle extended /proc/ stats formats by pairing values with header keys. Move TrafficStats to integer tags to match kernel internals, and offer well-known tags for system services. Async policy event dispatch from NPMS, and update tests to block for event dispatch. Narrow app policy to exclude apps signed with system key, which are usually critical. Bug: 4948913, 4903489, 4585280 Change-Id: Idb357227ccaa617906411f309371cea18d7bc519 --- core/java/android/net/TrafficStats.java | 38 +++++++++++++++++-- .../server/net/NetworkStatsService.java | 7 ++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index cb47193a6e..040489e664 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,7 +16,10 @@ package android.net; +import android.app.DownloadManager; +import android.app.backup.BackupManager; import android.content.Context; +import android.media.MediaPlayer; import android.os.IBinder; import android.os.INetworkManagementService; import android.os.RemoteException; @@ -49,6 +52,27 @@ public class TrafficStats { */ public static final int UID_REMOVED = -4; + /** + * Default tag value for {@link DownloadManager} traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFF0001; + + /** + * Default tag value for {@link MediaPlayer} traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_MEDIA = 0xFFFF0002; + + /** + * Default tag value for {@link BackupManager} traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_BACKUP = 0xFFFF0003; + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -67,12 +91,20 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - public static void setThreadStatsTag(String tag) { + public static void setThreadStatsTag(int tag) { BlockGuard.setThreadSocketStatsTag(tag); } + /** + * @deprecated unsupported, will eventually be removed + */ + @Deprecated + public static void setThreadStatsTag(String tag) { + setThreadStatsTag(tag.hashCode()); + } + public static void clearThreadStatsTag() { - BlockGuard.setThreadSocketStatsTag(null); + BlockGuard.setThreadSocketStatsTag(-1); } /** @@ -103,7 +135,7 @@ public class TrafficStats { * parameters. When finished, call {@link #untagSocket(Socket)} to remove * statistics parameters. * - * @see #setThreadStatsTag(String) + * @see #setThreadStatsTag(int) * @see #setThreadStatsUid(int) */ public static void tagSocket(Socket socket) throws SocketException { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 4a79d17ad8..7610a1181d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -124,8 +124,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; // TODO: listen for kernel push events through netd instead of polling - // TODO: watch for UID uninstall, and transfer stats into single bucket - // TODO: trim empty history objects entirely private static final long KB_IN_BYTES = 1024; @@ -506,8 +504,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { try { networkSnapshot = mNetworkManager.getNetworkStatsSummary(); uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; + } catch (IllegalStateException e) { + Slog.w(TAG, "problem reading network stats: " + e); + return; } catch (RemoteException e) { - Slog.w(TAG, "problem reading network stats"); + Slog.w(TAG, "problem reading network stats: " + e); return; } From b05f41c97f70f466e5303ca0f29d48136d638e5d Mon Sep 17 00:00:00 2001 From: Jesse Wilson Date: Tue, 28 Jun 2011 19:06:31 -0700 Subject: [PATCH 0054/1150] Move socket tagging from libcore. Change-Id: I7515896936c5bbd212c88e2801b831914219a925 --- core/java/android/net/TrafficStats.java | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 040489e664..2b59dba15c 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -25,8 +25,9 @@ import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceManager; -import dalvik.system.BlockGuard; +import com.android.server.NetworkManagementSocketTagger; +import dalvik.system.SocketTagger; import java.net.Socket; import java.net.SocketException; @@ -92,7 +93,7 @@ public class TrafficStats { * {@link #tagSocket(Socket)}. */ public static void setThreadStatsTag(int tag) { - BlockGuard.setThreadSocketStatsTag(tag); + NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); } /** @@ -104,7 +105,7 @@ public class TrafficStats { } public static void clearThreadStatsTag() { - BlockGuard.setThreadSocketStatsTag(-1); + NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); } /** @@ -121,12 +122,12 @@ public class TrafficStats { * {@hide} */ public static void setThreadStatsUid(int uid) { - BlockGuard.setThreadSocketStatsUid(uid); + NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } /** {@hide} */ public static void clearThreadStatsUid() { - BlockGuard.setThreadSocketStatsUid(-1); + NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } /** @@ -139,14 +140,14 @@ public class TrafficStats { * @see #setThreadStatsUid(int) */ public static void tagSocket(Socket socket) throws SocketException { - BlockGuard.tagSocketFd(socket.getFileDescriptor$()); + SocketTagger.get().tag(socket); } /** * Remove any statistics parameters from the given {@link Socket}. */ public static void untagSocket(Socket socket) throws SocketException { - BlockGuard.untagSocketFd(socket.getFileDescriptor$()); + SocketTagger.get().untag(socket); } /** From 830d546f6b311db489f4b8009fc3fbbaa4c743b2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 29 Jun 2011 10:45:16 -0700 Subject: [PATCH 0055/1150] Migrate bandwidth control to NMS, omit history. Both stats and policy make NMS calls that depend on bandwidth control being enabled, so move enable/disable into NMS and drop calls when disabled. This avoids throwing heavy ISE exceptions when disabled. Only include recent data when writing NetworkStatsHistory as part of dumpsys call. Introduce manual poll event for Settings UI. Bug: 4982115, 4770435, 4515856 Change-Id: I257820b057af2f0f99c736fb4f61e55b9fdc3e66 --- .../android/net/INetworkStatsService.aidl | 3 ++ .../java/android/net/NetworkStatsHistory.java | 13 +++++-- .../server/net/NetworkStatsService.java | 39 +++++++------------ 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index ae9aa05e0b..054825024b 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -33,4 +33,7 @@ interface INetworkStatsService { /** Return usage summary per UID for traffic that matches template. */ NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + /** Force update of statistics. */ + void forceUpdate(); + } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index ff6e220cac..dd2945ca18 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -279,10 +279,17 @@ public class NetworkStatsHistory implements Parcelable { return (long) (start + (r.nextFloat() * (end - start))); } - public void dump(String prefix, PrintWriter pw) { + public void dump(String prefix, PrintWriter pw, boolean fullHistory) { pw.print(prefix); pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); - for (int i = 0; i < bucketCount; i++) { + + final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); + if (start > 0) { + pw.print(prefix); + pw.print(" (omitting "); pw.print(start); pw.println(" buckets)"); + } + + for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); pw.print(" rx="); pw.print(rx[i]); @@ -293,7 +300,7 @@ public class NetworkStatsHistory implements Parcelable { @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); - dump("", new PrintWriter(writer)); + dump("", new PrintWriter(writer), false); return writer.toString(); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 7610a1181d..b4bd176906 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -134,7 +134,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public boolean getEnabled(); public long getPollInterval(); public long getPersistThreshold(); public long getNetworkBucketDuration(); @@ -207,20 +206,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { - if (mSettings.getEnabled()) { - try { - // enable low-level bandwidth stats and control - // TODO: consider shipping with this enabled by default - mNetworkManager.setBandwidthControlEnabled(true); - } catch (RemoteException e) { - Slog.e(TAG, "problem talking to netd while enabling bandwidth controls", e); - } catch (NativeDaemonConnectorException ndce) { - Slog.e(TAG, "problem enabling bandwidth controls", ndce); - } - } else { - Slog.w(TAG, "detailed network stats disabled"); - } - synchronized (mStatsLock) { // read historical network stats from disk, since policy service // might need them right away. we delay loading detailed UID stats @@ -389,6 +374,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public void forceUpdate() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + + synchronized (mStatsLock) { + performPollLocked(true, false); + } + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} @@ -905,6 +899,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { argSet.add(arg); } + final boolean fullHistory = argSet.contains("full"); + synchronized (mStatsLock) { // TODO: remove this testing code, since it corrupts stats if (argSet.contains("generate")) { @@ -930,7 +926,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkIdentitySet ident : mNetworkStats.keySet()) { final NetworkStatsHistory history = mNetworkStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); - history.dump(" ", pw); + history.dump(" ", pw, fullHistory); } if (argSet.contains("detail")) { @@ -950,7 +946,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory history = uidStats.valueAt(i); pw.print(" UID="); pw.print(uid); pw.print(" tag="); pw.println(tag); - history.dump(" ", pw); + history.dump(" ", pw, fullHistory); } } } @@ -1058,15 +1054,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return Settings.Secure.getLong(mResolver, name, def); } - public boolean getEnabled() { - if (!new File("/proc/net/xt_qtaguid/ctrl").exists()) { - Slog.w(TAG, "kernel does not support bandwidth control"); - return false; - } - // TODO: once things stabilize, enable by default. - // For now: ./vendor/google/tools/override-gservices secure:netstats_enabled=1 - return Settings.Secure.getInt(mResolver, NETSTATS_ENABLED, 0) != 0; - } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); } From 3d49d486c0c1a90669364ff0a0d80b9affc331ce Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Thu, 16 Jun 2011 17:40:23 +0200 Subject: [PATCH 0056/1150] NativeDaemonConnector: Fix SDCard mounting bug in the emulator. This patch fixes a really annoying bug that prevented the emulator from properly mounting the SD Card. The issue was that mOutputStream was not initialized when the onDaemonConnected callbacks are called, just after the daemon's socket connection is established. In one specific case (MountService a.k.a. VoldConnector), the corresponding callback function immediately tried to perform a doCommandList() call on the connector object. The request failed because mOutputStream was still defined as null when it happened. By moving the initialization of the variable just before the callback is invoked, we ensure that things work properly. Change-Id: I46726a50ef69eaafe70081ff4eda1244b744beba --- services/java/com/android/server/NativeDaemonConnector.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index cf87a9d393..88af1b264d 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -97,10 +97,11 @@ final class NativeDaemonConnector implements Runnable { LocalSocketAddress.Namespace.RESERVED); socket.connect(address); + + mOutputStream = socket.getOutputStream(); mCallbacks.onDaemonConnected(); InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; From 1c69b987342c908b6b47a3d442b8a83486a43d5e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 10 Jul 2011 14:20:41 -0700 Subject: [PATCH 0057/1150] Cached NTP time for system services. Uses NTP server and timeout from secure settings, or fallback to defaults in resources. Update various system services to use cached NTP time when fresh enough, or force updates as needed. Bug: 4517273 Change-Id: Ie1c4c4883836013d02ca0bbd850cf8949f93b34b --- .../java/com/android/server/net/NetworkStatsService.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index b4bd176906..b6834f6634 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -27,7 +27,6 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; -import static android.provider.Settings.Secure.NETSTATS_ENABLED; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -71,7 +70,6 @@ import android.util.Slog; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; -import com.android.server.NativeDaemonConnectorException; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -175,9 +173,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { - // TODO: move to using cached NtpTrustedTime - this(context, networkManager, alarmManager, new NtpTrustedTime(), getSystemDir(), - new DefaultNetworkStatsSettings(context)); + this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), + getSystemDir(), new DefaultNetworkStatsSettings(context)); } private static File getSystemDir() { From 8bfb6a160c5c6ae344e462c75425fc58492efa53 Mon Sep 17 00:00:00 2001 From: Kazuhiro Ondo Date: Tue, 5 Jul 2011 16:12:10 -0500 Subject: [PATCH 0058/1150] Concurrent multi-PDP support in TrafficStats Quick fix to enable concurrent multiple PDP support in TrafficStats. Just updated the list of hard-coded mobile interfaces for now. Bug: 4553527 Change-Id: I44ce73f3000542d6457f353bb561a2275684af6b --- core/jni/android_net_TrafficStats.cpp | 51 ++++++++++++++++++--------- 1 file changed, 34 insertions(+), 17 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 0c84f1138e..12150b4e7d 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -66,10 +66,35 @@ static jlong readNumber(char const* filename) { #endif } -// Return the number from the first file which exists and contains data -static jlong tryBoth(char const* a, char const* b) { - jlong num = readNumber(a); - return num >= 0 ? num : readNumber(b); +static const char* mobile_iface_list[] = { + "rmnet0", + "rmnet1", + "rmnet2", + "rmnet3", + "ppp0", + 0 +}; + +static jlong getAll(const char** iface_list, const char* what) { + + char filename[80]; + int idx = 0; + bool supported = false; + jlong total = 0; + while (iface_list[idx] != 0) { + + snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", + iface_list[idx], what); + jlong number = readNumber(filename); + if (number >= 0) { + supported = true; + total += number; + } + idx++; + } + if (supported) return total; + + return -1; } // Returns the sum of numbers from the specified path under /sys/class/net/*, @@ -107,30 +132,22 @@ static jlong readTotal(char const* suffix) { // each file every time (rather than caching which ones exist). static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) { - return tryBoth( - "/sys/class/net/rmnet0/statistics/tx_packets", - "/sys/class/net/ppp0/statistics/tx_packets"); + return getAll(mobile_iface_list, "tx_packets"); } static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { - return tryBoth( - "/sys/class/net/rmnet0/statistics/rx_packets", - "/sys/class/net/ppp0/statistics/rx_packets"); + return getAll(mobile_iface_list, "rx_packets"); } static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { - return tryBoth( - "/sys/class/net/rmnet0/statistics/tx_bytes", - "/sys/class/net/ppp0/statistics/tx_bytes"); + return getAll(mobile_iface_list, "tx_bytes"); } static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { - return tryBoth( - "/sys/class/net/rmnet0/statistics/rx_bytes", - "/sys/class/net/ppp0/statistics/rx_bytes"); + return getAll(mobile_iface_list, "rx_bytes"); } -static jlong getData(JNIEnv* env, char *what, jstring interface) { +static jlong getData(JNIEnv* env, const char *what, jstring interface) { char filename[80]; jboolean isCopy; From 21b9c72ad71b00d5ebb42b8559c0fd9f15cf0a86 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 11 Jul 2011 14:36:15 -0700 Subject: [PATCH 0059/1150] Return stats from inactive ifaces, packet counts. When an iface goes inactive, xt_qtaguid maintains historical counters instead of discarding. Now reading and returning those values in NetworkManagementService summary calls. Tests to verify stats are returned. Modify NetworkStats to include rxPackets and txPackets values, and move to Entry to eventually hide internal storage details. Bug: 4984539 Change-Id: I1ba0bb5580c62e946d9dff2cc2a6f64aff403efc --- core/java/android/net/NetworkStats.java | 135 +++++++++++++++++++----- 1 file changed, 110 insertions(+), 25 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9d40c42a39..a4c66e4f64 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -43,17 +43,41 @@ public class NetworkStats implements Parcelable { /** {@link #tag} value for without tag. */ public static final int TAG_NONE = 0; + // TODO: move public fields to Entry accessors, then undeprecate + // TODO: refactor rx/tx to rxBytes/txBytes + /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. */ + @Deprecated public final long elapsedRealtime; + @Deprecated public int size; + @Deprecated public String[] iface; + @Deprecated public int[] uid; + @Deprecated public int[] tag; + @Deprecated public long[] rx; + @Deprecated + public long[] rxPackets; + @Deprecated public long[] tx; + @Deprecated + public long[] txPackets; + + public static class Entry { + public String iface; + public int uid; + public int tag; + public long rxBytes; + public long rxPackets; + public long txBytes; + public long txPackets; + } public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; @@ -62,7 +86,9 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.tag = new int[initialSize]; this.rx = new long[initialSize]; + this.rxPackets = new long[initialSize]; this.tx = new long[initialSize]; + this.txPackets = new long[initialSize]; } public NetworkStats(Parcel parcel) { @@ -72,38 +98,82 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); tag = parcel.createIntArray(); rx = parcel.createLongArray(); + rxPackets = parcel.createLongArray(); tx = parcel.createLongArray(); + txPackets = parcel.createLongArray(); } /** * Add new stats entry with given values. */ public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) { + final Entry entry = new Entry(); + entry.iface = iface; + entry.uid = uid; + entry.tag = tag; + entry.rxBytes = rx; + entry.txBytes = tx; + return addValues(entry); + } + + /** + * Add new stats entry, copying from given {@link Entry}. The {@link Entry} + * object can be recycled across multiple calls. + */ + public NetworkStats addValues(Entry entry) { if (size >= this.iface.length) { - final int newLength = Math.max(this.iface.length, 10) * 3 / 2; - this.iface = Arrays.copyOf(this.iface, newLength); - this.uid = Arrays.copyOf(this.uid, newLength); - this.tag = Arrays.copyOf(this.tag, newLength); - this.rx = Arrays.copyOf(this.rx, newLength); - this.tx = Arrays.copyOf(this.tx, newLength); + final int newLength = Math.max(iface.length, 10) * 3 / 2; + iface = Arrays.copyOf(iface, newLength); + uid = Arrays.copyOf(uid, newLength); + tag = Arrays.copyOf(tag, newLength); + rx = Arrays.copyOf(rx, newLength); + rxPackets = Arrays.copyOf(rxPackets, newLength); + tx = Arrays.copyOf(tx, newLength); + txPackets = Arrays.copyOf(txPackets, newLength); } - this.iface[size] = iface; - this.uid[size] = uid; - this.tag[size] = tag; - this.rx[size] = rx; - this.tx[size] = tx; + iface[size] = entry.iface; + uid[size] = entry.uid; + tag[size] = entry.tag; + rx[size] = entry.rxBytes; + rxPackets[size] = entry.rxPackets; + tx[size] = entry.txBytes; + txPackets[size] = entry.txPackets; size++; return this; } + /** + * Return specific stats entry. + */ + public Entry getValues(int i, Entry recycle) { + final Entry entry = recycle != null ? recycle : new Entry(); + entry.iface = iface[i]; + entry.uid = uid[i]; + entry.tag = tag[i]; + entry.rxBytes = rx[i]; + entry.rxPackets = rxPackets[i]; + entry.txBytes = tx[i]; + entry.txPackets = txPackets[i]; + return entry; + } + + public long getElapsedRealtime() { + return elapsedRealtime; + } + + public int size() { + return size; + } + /** * Combine given values with an existing row, or create a new row if * {@link #findIndex(String, int, int)} is unable to find match. Can also be * used to subtract values from existing rows. */ public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) { + // TODO: extent to accept rxPackets/txPackets final int i = findIndex(iface, uid, tag); if (i == -1) { // only create new entry when positive contribution @@ -199,30 +269,41 @@ public class NetworkStats implements Parcelable { } // result will have our rows, and elapsed time between snapshots + final Entry entry = new Entry(); final NetworkStats result = new NetworkStats(deltaRealtime, size); for (int i = 0; i < size; i++) { - final String iface = this.iface[i]; - final int uid = this.uid[i]; - final int tag = this.tag[i]; + entry.iface = iface[i]; + entry.uid = uid[i]; + entry.tag = tag[i]; // find remote row that matches, and subtract - final int j = value.findIndex(iface, uid, tag); + final int j = value.findIndex(entry.iface, entry.uid, entry.tag); if (j == -1) { // newly appearing row, return entire value - result.addEntry(iface, uid, tag, this.rx[i], this.tx[i]); + entry.rxBytes = rx[i]; + entry.rxPackets = rxPackets[i]; + entry.txBytes = tx[i]; + entry.txPackets = txPackets[i]; } else { // existing row, subtract remote value - long rx = this.rx[i] - value.rx[j]; - long tx = this.tx[i] - value.tx[j]; - if (enforceMonotonic && (rx < 0 || tx < 0)) { + entry.rxBytes = rx[i] - value.rx[j]; + entry.rxPackets = rxPackets[i] - value.rxPackets[j]; + entry.txBytes = tx[i] - value.tx[j]; + entry.txPackets = txPackets[i] - value.txPackets[j]; + if (enforceMonotonic + && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 + || entry.txPackets < 0)) { throw new IllegalArgumentException("found non-monotonic values"); } if (clampNegative) { - rx = Math.max(0, rx); - tx = Math.max(0, tx); + entry.rxBytes = Math.max(0, entry.rxBytes); + entry.rxPackets = Math.max(0, entry.rxPackets); + entry.txBytes = Math.max(0, entry.txBytes); + entry.txPackets = Math.max(0, entry.txPackets); } - result.addEntry(iface, uid, tag, rx, tx); } + + result.addValues(entry); } return result; @@ -235,13 +316,15 @@ public class NetworkStats implements Parcelable { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); - for (int i = 0; i < iface.length; i++) { + for (int i = 0; i < size; i++) { pw.print(prefix); pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); pw.print(" tag="); pw.print(tag[i]); - pw.print(" rx="); pw.print(rx[i]); - pw.print(" tx="); pw.println(tx[i]); + pw.print(" rxBytes="); pw.print(rx[i]); + pw.print(" rxPackets="); pw.print(rxPackets[i]); + pw.print(" txBytes="); pw.print(tx[i]); + pw.print(" txPackets="); pw.println(txPackets[i]); } } @@ -265,7 +348,9 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(tag); dest.writeLongArray(rx); + dest.writeLongArray(rxPackets); dest.writeLongArray(tx); + dest.writeLongArray(txPackets); } public static final Creator CREATOR = new Creator() { From 188480b216491a79e96355e7ca3af3512fc81df9 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Jul 2011 13:57:00 -0700 Subject: [PATCH 0060/1150] Hide NetworkStatsHistory internals. Instead of exposing internal storage details, offer getValues() accessor which populates values into a recycled structure. Change-Id: I5228d7099a8f61b2018a435a813435a67dae49b4 --- core/java/android/net/NetworkStats.java | 117 +++++++++--------- .../java/android/net/NetworkStatsHistory.java | 87 ++++++++----- .../server/net/NetworkStatsService.java | 83 +++++++------ 3 files changed, 164 insertions(+), 123 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index a4c66e4f64..fbff7d89fc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -43,31 +43,19 @@ public class NetworkStats implements Parcelable { /** {@link #tag} value for without tag. */ public static final int TAG_NONE = 0; - // TODO: move public fields to Entry accessors, then undeprecate - // TODO: refactor rx/tx to rxBytes/txBytes - /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. */ - @Deprecated - public final long elapsedRealtime; - @Deprecated - public int size; - @Deprecated - public String[] iface; - @Deprecated - public int[] uid; - @Deprecated - public int[] tag; - @Deprecated - public long[] rx; - @Deprecated - public long[] rxPackets; - @Deprecated - public long[] tx; - @Deprecated - public long[] txPackets; + private final long elapsedRealtime; + private int size; + private String[] iface; + private int[] uid; + private int[] tag; + private long[] rxBytes; + private long[] rxPackets; + private long[] txBytes; + private long[] txPackets; public static class Entry { public String iface; @@ -77,6 +65,20 @@ public class NetworkStats implements Parcelable { public long rxPackets; public long txBytes; public long txPackets; + + public Entry() { + } + + public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, + long txPackets) { + this.iface = iface; + this.uid = uid; + this.tag = tag; + this.rxBytes = rxBytes; + this.rxPackets = rxPackets; + this.txBytes = txBytes; + this.txPackets = txPackets; + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -85,9 +87,9 @@ public class NetworkStats implements Parcelable { this.iface = new String[initialSize]; this.uid = new int[initialSize]; this.tag = new int[initialSize]; - this.rx = new long[initialSize]; + this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; - this.tx = new long[initialSize]; + this.txBytes = new long[initialSize]; this.txPackets = new long[initialSize]; } @@ -97,23 +99,15 @@ public class NetworkStats implements Parcelable { iface = parcel.createStringArray(); uid = parcel.createIntArray(); tag = parcel.createIntArray(); - rx = parcel.createLongArray(); + rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); - tx = parcel.createLongArray(); + txBytes = parcel.createLongArray(); txPackets = parcel.createLongArray(); } - /** - * Add new stats entry with given values. - */ - public NetworkStats addEntry(String iface, int uid, int tag, long rx, long tx) { - final Entry entry = new Entry(); - entry.iface = iface; - entry.uid = uid; - entry.tag = tag; - entry.rxBytes = rx; - entry.txBytes = tx; - return addValues(entry); + public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets) { + return addValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets)); } /** @@ -126,18 +120,18 @@ public class NetworkStats implements Parcelable { iface = Arrays.copyOf(iface, newLength); uid = Arrays.copyOf(uid, newLength); tag = Arrays.copyOf(tag, newLength); - rx = Arrays.copyOf(rx, newLength); + rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); - tx = Arrays.copyOf(tx, newLength); + txBytes = Arrays.copyOf(txBytes, newLength); txPackets = Arrays.copyOf(txPackets, newLength); } iface[size] = entry.iface; uid[size] = entry.uid; tag[size] = entry.tag; - rx[size] = entry.rxBytes; + rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; - tx[size] = entry.txBytes; + txBytes[size] = entry.txBytes; txPackets[size] = entry.txPackets; size++; @@ -152,9 +146,9 @@ public class NetworkStats implements Parcelable { entry.iface = iface[i]; entry.uid = uid[i]; entry.tag = tag[i]; - entry.rxBytes = rx[i]; + entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; - entry.txBytes = tx[i]; + entry.txBytes = txBytes[i]; entry.txPackets = txPackets[i]; return entry; } @@ -167,20 +161,31 @@ public class NetworkStats implements Parcelable { return size; } + // @VisibleForTesting + public int internalSize() { + return iface.length; + } + + public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets) { + return combineValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets)); + } + /** * Combine given values with an existing row, or create a new row if * {@link #findIndex(String, int, int)} is unable to find match. Can also be * used to subtract values from existing rows. */ - public NetworkStats combineEntry(String iface, int uid, int tag, long rx, long tx) { - // TODO: extent to accept rxPackets/txPackets - final int i = findIndex(iface, uid, tag); + public NetworkStats combineValues(Entry entry) { + final int i = findIndex(entry.iface, entry.uid, entry.tag); if (i == -1) { // only create new entry when positive contribution - addEntry(iface, uid, tag, rx, tx); + addValues(entry); } else { - this.rx[i] += rx; - this.tx[i] += tx; + rxBytes[i] += entry.rxBytes; + rxPackets[i] += entry.rxPackets; + txBytes[i] += entry.txBytes; + txPackets[i] += entry.txPackets; } return this; } @@ -280,15 +285,15 @@ public class NetworkStats implements Parcelable { final int j = value.findIndex(entry.iface, entry.uid, entry.tag); if (j == -1) { // newly appearing row, return entire value - entry.rxBytes = rx[i]; + entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; - entry.txBytes = tx[i]; + entry.txBytes = txBytes[i]; entry.txPackets = txPackets[i]; } else { // existing row, subtract remote value - entry.rxBytes = rx[i] - value.rx[j]; + entry.rxBytes = rxBytes[i] - value.rxBytes[j]; entry.rxPackets = rxPackets[i] - value.rxPackets[j]; - entry.txBytes = tx[i] - value.tx[j]; + entry.txBytes = txBytes[i] - value.txBytes[j]; entry.txPackets = txPackets[i] - value.txPackets[j]; if (enforceMonotonic && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 @@ -321,9 +326,9 @@ public class NetworkStats implements Parcelable { pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); pw.print(" tag="); pw.print(tag[i]); - pw.print(" rxBytes="); pw.print(rx[i]); + pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); - pw.print(" txBytes="); pw.print(tx[i]); + pw.print(" txBytes="); pw.print(txBytes[i]); pw.print(" txPackets="); pw.println(txPackets[i]); } } @@ -347,9 +352,9 @@ public class NetworkStats implements Parcelable { dest.writeStringArray(iface); dest.writeIntArray(uid); dest.writeIntArray(tag); - dest.writeLongArray(rx); + dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); - dest.writeLongArray(tx); + dest.writeLongArray(txBytes); dest.writeLongArray(txPackets); } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index dd2945ca18..b0930b2ae2 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -43,13 +43,20 @@ public class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; // TODO: teach about varint encoding to use less disk space + // TODO: extend to record rxPackets/txPackets - public final long bucketDuration; + private final long bucketDuration; + private int bucketCount; + private long[] bucketStart; + private long[] rxBytes; + private long[] txBytes; - public int bucketCount; - public long[] bucketStart; - public long[] rx; - public long[] tx; + public static class Entry { + public long bucketStart; + public long bucketDuration; + public long rxBytes; + public long txBytes; + } public NetworkStatsHistory(long bucketDuration) { this(bucketDuration, 10); @@ -58,16 +65,16 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(long bucketDuration, int initialSize) { this.bucketDuration = bucketDuration; bucketStart = new long[initialSize]; - rx = new long[initialSize]; - tx = new long[initialSize]; + rxBytes = new long[initialSize]; + txBytes = new long[initialSize]; bucketCount = 0; } public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); - rx = in.createLongArray(); - tx = in.createLongArray(); + rxBytes = in.createLongArray(); + txBytes = in.createLongArray(); bucketCount = bucketStart.length; } @@ -75,8 +82,8 @@ public class NetworkStatsHistory implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); - writeLongArray(out, rx, bucketCount); - writeLongArray(out, tx, bucketCount); + writeLongArray(out, rxBytes, bucketCount); + writeLongArray(out, txBytes, bucketCount); } public NetworkStatsHistory(DataInputStream in) throws IOException { @@ -85,8 +92,8 @@ public class NetworkStatsHistory implements Parcelable { case VERSION_INIT: { bucketDuration = in.readLong(); bucketStart = readLongArray(in); - rx = readLongArray(in); - tx = readLongArray(in); + rxBytes = readLongArray(in); + txBytes = readLongArray(in); bucketCount = bucketStart.length; break; } @@ -100,8 +107,8 @@ public class NetworkStatsHistory implements Parcelable { out.writeInt(VERSION_INIT); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); - writeLongArray(out, rx, bucketCount); - writeLongArray(out, tx, bucketCount); + writeLongArray(out, rxBytes, bucketCount); + writeLongArray(out, txBytes, bucketCount); } /** {@inheritDoc} */ @@ -109,6 +116,26 @@ public class NetworkStatsHistory implements Parcelable { return 0; } + public int size() { + return bucketCount; + } + + public long getBucketDuration() { + return bucketDuration; + } + + /** + * Return specific stats entry. + */ + public Entry getValues(int i, Entry recycle) { + final Entry entry = recycle != null ? recycle : new Entry(); + entry.bucketStart = bucketStart[i]; + entry.bucketDuration = bucketDuration; + entry.rxBytes = rxBytes[i]; + entry.txBytes = txBytes[i]; + return entry; + } + /** * Record that data traffic occurred in the given time range. Will * distribute across internal buckets, creating new buckets as needed. @@ -135,8 +162,8 @@ public class NetworkStatsHistory implements Parcelable { final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); if (overlap > 0) { - this.rx[i] += rx * overlap / duration; - this.tx[i] += tx * overlap / duration; + this.rxBytes[i] += rx * overlap / duration; + this.txBytes[i] += tx * overlap / duration; } } } @@ -149,7 +176,7 @@ public class NetworkStatsHistory implements Parcelable { for (int i = 0; i < input.bucketCount; i++) { final long start = input.bucketStart[i]; final long end = start + input.bucketDuration; - recordData(start, end, input.rx[i], input.tx[i]); + recordData(start, end, input.rxBytes[i], input.txBytes[i]); } } @@ -179,8 +206,8 @@ public class NetworkStatsHistory implements Parcelable { if (bucketCount >= bucketStart.length) { final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); - rx = Arrays.copyOf(rx, newLength); - tx = Arrays.copyOf(tx, newLength); + rxBytes = Arrays.copyOf(rxBytes, newLength); + txBytes = Arrays.copyOf(txBytes, newLength); } // create gap when inserting bucket in middle @@ -189,13 +216,13 @@ public class NetworkStatsHistory implements Parcelable { final int length = bucketCount - index; System.arraycopy(bucketStart, index, bucketStart, dstPos, length); - System.arraycopy(rx, index, rx, dstPos, length); - System.arraycopy(tx, index, tx, dstPos, length); + System.arraycopy(rxBytes, index, rxBytes, dstPos, length); + System.arraycopy(txBytes, index, txBytes, dstPos, length); } bucketStart[index] = start; - rx[index] = 0; - tx[index] = 0; + rxBytes[index] = 0; + txBytes[index] = 0; bucketCount++; } @@ -216,8 +243,8 @@ public class NetworkStatsHistory implements Parcelable { if (i > 0) { final int length = bucketStart.length; bucketStart = Arrays.copyOfRange(bucketStart, i, length); - rx = Arrays.copyOfRange(rx, i, length); - tx = Arrays.copyOfRange(tx, i, length); + rxBytes = Arrays.copyOfRange(rxBytes, i, length); + txBytes = Arrays.copyOfRange(txBytes, i, length); bucketCount -= i; } } @@ -241,8 +268,8 @@ public class NetworkStatsHistory implements Parcelable { final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); if (overlap > 0) { - rx += this.rx[i] * overlap / bucketDuration; - tx += this.tx[i] * overlap / bucketDuration; + rx += this.rxBytes[i] * overlap / bucketDuration; + tx += this.txBytes[i] * overlap / bucketDuration; } } @@ -292,8 +319,8 @@ public class NetworkStatsHistory implements Parcelable { for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); - pw.print(" rx="); pw.print(rx[i]); - pw.print(" tx="); pw.println(tx[i]); + pw.print(" rxBytes="); pw.print(rxBytes[i]); + pw.print(" txBytes="); pw.println(txBytes[i]); } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index b6834f6634..872438c5e5 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -313,22 +313,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { - long rx = 0; - long tx = 0; - long[] networkTotal = new long[2]; + final NetworkStats stats = new NetworkStats(end - start, 1); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + long[] total = new long[2]; // combine total from all interfaces that match template for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); - networkTotal = history.getTotalData(start, end, networkTotal); - rx += networkTotal[0]; - tx += networkTotal[1]; + total = history.getTotalData(start, end, total); + + entry.iface = IFACE_ALL; + entry.uid = UID_ALL; + entry.tag = TAG_NONE; + entry.rxBytes = total[0]; + entry.txBytes = total[1]; + + stats.combineValues(entry); } } - final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(IFACE_ALL, UID_ALL, TAG_NONE, rx, tx); return stats; } } @@ -342,6 +346,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final NetworkStats stats = new NetworkStats(end - start, 24); + final NetworkStats.Entry entry = new NetworkStats.Entry(); long[] total = new long[2]; for (NetworkIdentitySet ident : mUidStats.keySet()) { @@ -357,10 +362,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (tag == TAG_NONE || includeTags) { final NetworkStatsHistory history = uidStats.valueAt(i); total = history.getTotalData(start, end, total); - final long rx = total[0]; - final long tx = total[1]; - if (rx > 0 || tx > 0) { - stats.combineEntry(IFACE_ALL, uid, tag, rx, tx); + + entry.iface = IFACE_ALL; + entry.uid = uid; + entry.tag = tag; + entry.rxBytes = total[0]; + entry.txBytes = total[1]; + + if (entry.rxBytes > 0 || entry.txBytes > 0) { + stats.combineValues(entry); } } } @@ -512,10 +522,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats persistDelta = computeStatsDelta( mLastPersistNetworkSnapshot, networkSnapshot); final long persistThreshold = mSettings.getPersistThreshold(); + + NetworkStats.Entry entry = null; for (String iface : persistDelta.getUniqueIfaces()) { final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); - if (forcePersist || persistDelta.rx[index] > persistThreshold - || persistDelta.tx[index] > persistThreshold) { + entry = persistDelta.getValues(index, entry); + if (forcePersist || entry.rxBytes > persistThreshold + || entry.txBytes > persistThreshold) { writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); @@ -538,20 +551,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot); - final long timeStart = currentTime - delta.elapsedRealtime; - for (int i = 0; i < delta.size; i++) { - final String iface = delta.iface[i]; - final NetworkIdentitySet ident = mActiveIfaces.get(iface); + final long timeStart = currentTime - delta.getElapsedRealtime(); + + NetworkStats.Entry entry = null; + for (int i = 0; i < delta.size(); i++) { + entry = delta.getValues(i, entry); + final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); if (ident == null) { - unknownIface.add(iface); + unknownIface.add(entry.iface); continue; } - final long rx = delta.rx[i]; - final long tx = delta.tx[i]; - final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); - history.recordData(timeStart, currentTime, rx, tx); + history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes); } // trim any history beyond max @@ -574,22 +586,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot); - final long timeStart = currentTime - delta.elapsedRealtime; + final long timeStart = currentTime - delta.getElapsedRealtime(); - for (int i = 0; i < delta.size; i++) { - final String iface = delta.iface[i]; - final NetworkIdentitySet ident = mActiveIfaces.get(iface); + NetworkStats.Entry entry = null; + for (int i = 0; i < delta.size(); i++) { + entry = delta.getValues(i, entry); + final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); if (ident == null) { continue; } - final int uid = delta.uid[i]; - final int tag = delta.tag[i]; - final long rx = delta.rx[i]; - final long tx = delta.tx[i]; - - final NetworkStatsHistory history = findOrCreateUidStatsLocked(ident, uid, tag); - history.recordData(timeStart, currentTime, rx, tx); + final NetworkStatsHistory history = findOrCreateUidStatsLocked( + ident, entry.uid, entry.tag); + history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes); } // trim any history beyond max @@ -651,7 +660,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); - } else if (existing.bucketDuration != bucketDuration) { + } else if (existing.getBucketDuration() != bucketDuration) { updated = new NetworkStatsHistory( bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); @@ -683,7 +692,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsHistory updated = null; if (existing == null) { updated = new NetworkStatsHistory(bucketDuration, 10); - } else if (existing.bucketDuration != bucketDuration) { + } else if (existing.getBucketDuration() != bucketDuration) { updated = new NetworkStatsHistory( bucketDuration, estimateResizeBuckets(existing, bucketDuration)); updated.recordEntireHistory(existing); @@ -1003,7 +1012,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) { - return (int) (existing.bucketCount * existing.bucketDuration / newBucketDuration); + return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration); } // @VisibleForTesting From 3a0b70f80c46fc56d75ca4e783e7ea53ec140cf6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Jul 2011 20:20:56 -0700 Subject: [PATCH 0061/1150] Include full network history around current time. When requesting historical values with time ranges, always include full values for buckets that span current time. (It doesn't make sense to interpolate partial data.) Move getTotalData() to return full Entry objects to prepare for packet counts. Bug: 4691901 Change-Id: I717bd721be9f1d4a47c4121e46e07a56cb15bbf1 --- .../java/android/net/NetworkStatsHistory.java | 51 ++++++++++++++----- .../server/net/NetworkStatsService.java | 23 ++++++--- 2 files changed, 54 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index b0930b2ae2..8bd1738937 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -124,6 +124,22 @@ public class NetworkStatsHistory implements Parcelable { return bucketDuration; } + public long getStart() { + if (bucketCount > 0) { + return bucketStart[0]; + } else { + return Long.MAX_VALUE; + } + } + + public long getEnd() { + if (bucketCount > 0) { + return bucketStart[bucketCount - 1] + bucketDuration; + } else { + return Long.MIN_VALUE; + } + } + /** * Return specific stats entry. */ @@ -253,9 +269,20 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ - public long[] getTotalData(long start, long end, long[] outTotal) { - long rx = 0; - long tx = 0; + public Entry getValues(long start, long end, Entry recycle) { + return getValues(start, end, Long.MAX_VALUE, recycle); + } + + /** + * Return interpolated data usage across the requested range. Interpolates + * across buckets, so values may be rounded slightly. + */ + public Entry getValues(long start, long end, long now, Entry recycle) { + final Entry entry = recycle != null ? recycle : new Entry(); + entry.bucketStart = start; + entry.bucketDuration = end - start; + entry.rxBytes = 0; + entry.txBytes = 0; for (int i = bucketCount - 1; i >= 0; i--) { final long curStart = bucketStart[i]; @@ -266,19 +293,19 @@ public class NetworkStatsHistory implements Parcelable { // bucket is newer than record; keep looking if (curStart > end) continue; + // include full value for active buckets, otherwise only fractional + final boolean activeBucket = curStart < now && curEnd > now; final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (overlap > 0) { - rx += this.rxBytes[i] * overlap / bucketDuration; - tx += this.txBytes[i] * overlap / bucketDuration; + if (activeBucket || overlap == bucketDuration) { + entry.rxBytes += rxBytes[i]; + entry.txBytes += txBytes[i]; + } else if (overlap > 0) { + entry.rxBytes += rxBytes[i] * overlap / bucketDuration; + entry.txBytes += txBytes[i] * overlap / bucketDuration; } } - if (outTotal == null || outTotal.length != 2) { - outTotal = new long[2]; - } - outTotal[0] = rx; - outTotal[1] = tx; - return outTotal; + return entry; } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 872438c5e5..54e94db073 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -313,21 +313,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { + // use system clock to be externally consistent + final long now = System.currentTimeMillis(); + final NetworkStats stats = new NetworkStats(end - start, 1); final NetworkStats.Entry entry = new NetworkStats.Entry(); - long[] total = new long[2]; + NetworkStatsHistory.Entry historyEntry = null; // combine total from all interfaces that match template for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); - total = history.getTotalData(start, end, total); + historyEntry = history.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; entry.uid = UID_ALL; entry.tag = TAG_NONE; - entry.rxBytes = total[0]; - entry.txBytes = total[1]; + entry.rxBytes = historyEntry.rxBytes; + entry.txBytes = historyEntry.txBytes; stats.combineValues(entry); } @@ -345,9 +348,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); + // use system clock to be externally consistent + final long now = System.currentTimeMillis(); + final NetworkStats stats = new NetworkStats(end - start, 24); final NetworkStats.Entry entry = new NetworkStats.Entry(); - long[] total = new long[2]; + NetworkStatsHistory.Entry historyEntry = null; for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { @@ -361,13 +367,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // other tags when requested. if (tag == TAG_NONE || includeTags) { final NetworkStatsHistory history = uidStats.valueAt(i); - total = history.getTotalData(start, end, total); + historyEntry = history.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; entry.uid = uid; entry.tag = tag; - entry.rxBytes = total[0]; - entry.txBytes = total[1]; + entry.rxBytes = historyEntry.rxBytes; + entry.txBytes = historyEntry.txBytes; if (entry.rxBytes > 0 || entry.txBytes > 0) { stats.combineValues(entry); @@ -425,6 +431,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // broadcast. final int uid = intent.getIntExtra(EXTRA_UID, 0); synchronized (mStatsLock) { + // TODO: perform one last stats poll for UID removeUidLocked(uid); } } From 9a3b109182d677bde8b05854d427a17f14afeb81 Mon Sep 17 00:00:00 2001 From: Mike Lockwood Date: Wed, 13 Jul 2011 11:06:57 -0400 Subject: [PATCH 0062/1150] Remove some #ifdef HAVE_ANDROID_OS that were needed for the simulator build Change-Id: I13d9f251f86c05ae5405f37adbf6b8e9660935ba Signed-off-by: Mike Lockwood --- core/jni/android_net_TrafficStats.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index d54981e18d..c22b07138c 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -44,7 +44,6 @@ enum Tcp_Udp { // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { -#ifdef HAVE_ANDROID_OS char buf[80]; int fd = open(filename, O_RDONLY); if (fd < 0) { @@ -62,9 +61,6 @@ static jlong readNumber(char const* filename) { close(fd); buf[len] = '\0'; return atoll(buf); -#else // Simulator - return -1; -#endif } static const char* mobile_iface_list[] = { @@ -101,7 +97,6 @@ static jlong getAll(const char** iface_list, const char* what) { // Returns the sum of numbers from the specified path under /sys/class/net/*, // -1 if no such file exists. static jlong readTotal(char const* suffix) { -#ifdef HAVE_ANDROID_OS char filename[PATH_MAX] = "/sys/class/net/"; DIR *dir = opendir(filename); if (dir == NULL) { @@ -123,9 +118,6 @@ static jlong readTotal(char const* suffix) { closedir(dir); return total; -#else // Simulator - return -1; -#endif } // Mobile stats get accessed a lot more often than total stats. From 1bb88919c73705cb58cb56e38f3155b3ccf3c261 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 14 Jul 2011 20:37:37 -0700 Subject: [PATCH 0063/1150] Hide NetworkTemplate details, buffered stats I/O. Move template matching to builder methods instead of exposing the internal constants. Also rule to match Ethernet usage. Buffer reading and writing of network stats, making operations 5x faster. Change-Id: Iedb2d0ab3b26a976811c050f84a164e909eb74b6 --- core/java/android/net/NetworkTemplate.java | 61 ++++++++++++++++--- .../server/net/NetworkStatsService.java | 23 +++---- 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 9381f1dec3..1ef0d9d077 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -38,41 +39,69 @@ import com.android.internal.util.Objects; */ public class NetworkTemplate implements Parcelable { + /** {@hide} */ + public static final int MATCH_MOBILE_ALL = 1; + /** {@hide} */ + public static final int MATCH_MOBILE_3G_LOWER = 2; + /** {@hide} */ + public static final int MATCH_MOBILE_4G = 3; + /** {@hide} */ + public static final int MATCH_WIFI = 4; + /** {@hide} */ + public static final int MATCH_ETHERNET = 5; + /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together. Only uses statistics for requested IMSI. */ - public static final int MATCH_MOBILE_ALL = 1; + public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { + return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId); + } /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together that roughly meet a "3G" definition, or lower. Only * uses statistics for requested IMSI. */ - public static final int MATCH_MOBILE_3G_LOWER = 2; + public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { + return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId); + } /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together that meet a "4G" definition. Only uses statistics for * requested IMSI. */ - public static final int MATCH_MOBILE_4G = 3; + public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { + return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId); + } /** * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style * networks together. */ - public static final int MATCH_WIFI = 4; + public static NetworkTemplate buildTemplateWifi() { + return new NetworkTemplate(MATCH_WIFI, null); + } - final int mMatchRule; - final String mSubscriberId; + /** + * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style + * networks together. + */ + public static NetworkTemplate buildTemplateEthernet() { + return new NetworkTemplate(MATCH_ETHERNET, null); + } + private final int mMatchRule; + private final String mSubscriberId; + + /** {@hide} */ public NetworkTemplate(int matchRule, String subscriberId) { this.mMatchRule = matchRule; this.mSubscriberId = subscriberId; } - public NetworkTemplate(Parcel in) { + private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); mSubscriberId = in.readString(); } @@ -110,10 +139,12 @@ public class NetworkTemplate implements Parcelable { return false; } + /** {@hide} */ public int getMatchRule() { return mMatchRule; } + /** {@hide} */ public String getSubscriberId() { return mSubscriberId; } @@ -131,6 +162,8 @@ public class NetworkTemplate implements Parcelable { return matchesMobile4g(ident); case MATCH_WIFI: return matchesWifi(ident); + case MATCH_ETHERNET: + return matchesEthernet(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -190,7 +223,17 @@ public class NetworkTemplate implements Parcelable { return false; } - public static String getMatchRuleName(int matchRule) { + /** + * Check if matches Ethernet network template. + */ + private boolean matchesEthernet(NetworkIdentity ident) { + if (ident.mType == TYPE_ETHERNET) { + return true; + } + return false; + } + + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: return "MOBILE_3G_LOWER"; @@ -200,6 +243,8 @@ public class NetworkTemplate implements Parcelable { return "MOBILE_ALL"; case MATCH_WIFI: return "WIFI"; + case MATCH_ETHERNET: + return "ETHERNET"; default: return "UNKNOWN"; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 54e94db073..7ec6b81dec 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -73,11 +73,12 @@ import com.android.internal.os.AtomicFile; import com.google.android.collect.Maps; import com.google.android.collect.Sets; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; @@ -719,10 +720,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // clear any existing stats and read from disk mNetworkStats.clear(); - FileInputStream fis = null; + DataInputStream in = null; try { - fis = mNetworkFile.openRead(); - final DataInputStream in = new DataInputStream(fis); + in = new DataInputStream(new BufferedInputStream(mNetworkFile.openRead())); // verify file magic header intact final int magic = in.readInt(); @@ -751,7 +751,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (IOException e) { Slog.e(TAG, "problem reading network stats", e); } finally { - IoUtils.closeQuietly(fis); + IoUtils.closeQuietly(in); } } @@ -768,10 +768,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // clear any existing stats and read from disk mUidStats.clear(); - FileInputStream fis = null; + DataInputStream in = null; try { - fis = mUidFile.openRead(); - final DataInputStream in = new DataInputStream(fis); + in = new DataInputStream(new BufferedInputStream(mUidFile.openRead())); // verify file magic header intact final int magic = in.readInt(); @@ -826,7 +825,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (IOException e) { Slog.e(TAG, "problem reading uid stats", e); } finally { - IoUtils.closeQuietly(fis); + IoUtils.closeQuietly(in); } } @@ -838,7 +837,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { FileOutputStream fos = null; try { fos = mNetworkFile.startWrite(); - final DataOutputStream out = new DataOutputStream(fos); + final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); out.writeInt(FILE_MAGIC); out.writeInt(VERSION_NETWORK_INIT); @@ -850,6 +849,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.writeToStream(out); } + out.flush(); mNetworkFile.finishWrite(fos); } catch (IOException e) { if (fos != null) { @@ -871,7 +871,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { FileOutputStream fos = null; try { fos = mUidFile.startWrite(); - final DataOutputStream out = new DataOutputStream(fos); + final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); out.writeInt(FILE_MAGIC); out.writeInt(VERSION_UID_WITH_TAG); @@ -895,6 +895,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + out.flush(); mUidFile.finishWrite(fos); } catch (IOException e) { if (fos != null) { From 2f60c2d402e6e2392fb7dbe8bf3c160b5de7a997 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 17 Jul 2011 12:53:28 -0700 Subject: [PATCH 0064/1150] Acquire wakelock during network stats collection. Bug: 4517275 Change-Id: I01dfe3b13d7aca84605446e9e9927d0648623552 --- .../server/net/NetworkStatsService.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 7ec6b81dec..6cc01f40d9 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -60,6 +60,7 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; +import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; @@ -112,6 +113,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final TrustedTime mTime; private final NetworkStatsSettings mSettings; + private final PowerManager.WakeLock mWakeLock; + private IConnectivityManager mConnManager; // @VisibleForTesting @@ -191,6 +194,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mTime = checkNotNull(time, "missing TrustedTime"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); + final PowerManager powerManager = (PowerManager) context.getSystemService( + Context.POWER_SERVICE); + mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper()); @@ -408,7 +415,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. synchronized (mStatsLock) { - updateIfacesLocked(); + mWakeLock.acquire(); + try { + updateIfacesLocked(); + } finally { + mWakeLock.release(); + } } } }; @@ -419,8 +431,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. synchronized (mStatsLock) { - // TODO: acquire wakelock while performing poll - performPollLocked(true, false); + mWakeLock.acquire(); + try { + performPollLocked(true, false); + } finally { + mWakeLock.release(); + } } } }; @@ -433,7 +449,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int uid = intent.getIntExtra(EXTRA_UID, 0); synchronized (mStatsLock) { // TODO: perform one last stats poll for UID - removeUidLocked(uid); + mWakeLock.acquire(); + try { + removeUidLocked(uid); + } finally { + mWakeLock.release(); + } } } }; From 861849e10e1f54907ecb98a86f72e5ee668e8c20 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 17 Jul 2011 15:53:33 -0700 Subject: [PATCH 0065/1150] Data usage notifs, newly installed apps, defaults. Only show warning/limit notifications for active networks, since they aren't actionable for inactive IMSI. Include IMSI in debug output on engineering builds. Move default policy warning to be configured through overlay. Watch for newly installed packages to enforce global policy. Bug: 5038729, 5038541, 4979026, 5023634 Change-Id: I8fc8ab4c23c440a3091504ea16133ed6ababf58e --- core/java/android/net/NetworkIdentity.java | 14 +++++++++++++- core/java/android/net/NetworkTemplate.java | 13 +++++++------ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index ccef122c0a..aa6400bbf5 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -19,6 +19,7 @@ package android.net; import static android.net.ConnectivityManager.isNetworkTypeMobile; import android.content.Context; +import android.os.Build; import android.telephony.TelephonyManager; import com.android.internal.util.Objects; @@ -68,7 +69,7 @@ public class NetworkIdentity { subTypeName = Integer.toString(mSubType); } - final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + final String scrubSubscriberId = scrubSubscriberId(mSubscriberId); final String roaming = mRoaming ? ", ROAMING" : ""; return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId=" + scrubSubscriberId + roaming + "]"; @@ -90,6 +91,17 @@ public class NetworkIdentity { return mRoaming; } + /** + * Scrub given IMSI on production builds. + */ + public static String scrubSubscriberId(String subscriberId) { + if ("eng".equals(Build.TYPE)) { + return subscriberId; + } else { + return subscriberId != null ? "valid" : "null"; + } + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 1ef0d9d077..cd4902308b 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -16,10 +16,11 @@ package android.net; +import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkIdentity.scrubSubscriberId; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; @@ -119,7 +120,7 @@ public class NetworkTemplate implements Parcelable { @Override public String toString() { - final String scrubSubscriberId = mSubscriberId != null ? "valid" : "null"; + final String scrubSubscriberId = scrubSubscriberId(mSubscriberId); return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId=" + scrubSubscriberId; } @@ -150,7 +151,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Test if this network matches the given template and IMEI. + * Test if this network matches the given template and IMSI. */ public boolean matches(NetworkIdentity ident) { switch (mMatchRule) { @@ -170,7 +171,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Check if mobile network with matching IMEI. Also matches + * Check if mobile network with matching IMSI. Also matches * {@link #TYPE_WIMAX}. */ private boolean matchesMobile(NetworkIdentity ident) { @@ -183,7 +184,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Check if mobile network classified 3G or lower with matching IMEI. + * Check if mobile network classified 3G or lower with matching IMSI. */ private boolean matchesMobile3gLower(NetworkIdentity ident) { if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { @@ -198,7 +199,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Check if mobile network classified 4G with matching IMEI. Also matches + * Check if mobile network classified 4G with matching IMSI. Also matches * {@link #TYPE_WIMAX}. */ private boolean matchesMobile4g(NetworkIdentity ident) { From 2c295f0c6d28324b610788ede2839716dc5a0a71 Mon Sep 17 00:00:00 2001 From: Alon Albert Date: Tue, 19 Jul 2011 11:16:09 +0300 Subject: [PATCH 0066/1150] Add a getter for the active tag Change-Id: I597e041867fba7efae41feea63fa196bc10e4aa2 --- core/java/android/net/TrafficStats.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 2b59dba15c..e054930684 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -96,6 +96,15 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); } + /** + * Get the active tag used when accounting {@link Socket} traffic originating + * from the current thread. Only one active tag per thread is supported. + * {@link #tagSocket(Socket)}. + */ + public static int getThreadStatsTag() { + return NetworkManagementSocketTagger.getThreadSocketStatsTag(); + } + /** * @deprecated unsupported, will eventually be removed */ From 0c6ebed1df9920e4c805ea2311b2423c5078c5fb Mon Sep 17 00:00:00 2001 From: repo sync Date: Fri, 24 Jun 2011 14:23:07 -0700 Subject: [PATCH 0067/1150] Updated: Wi-Fi p2p framework First stage. Get the bones in right now even though we are not ready on the native side. Once, we have things underneath working - we will further update the framework Change-Id: I4a7dab5cd4267373dc5f8989ae4122f91c384ed5 --- .../android/net/wifi/p2p/IWifiP2pManager.aidl | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl new file mode 100644 index 0000000000..a0c7dd1450 --- /dev/null +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2008, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.p2p; + +import android.os.Messenger; + +/** + * Interface that WifiP2pService implements + * + * {@hide} + */ +interface IWifiP2pManager +{ + Messenger getMessenger(); + boolean isP2pSupported(); +} + From 7407e09009b0cef68d20a33d37a89bbccca0681b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 19 Jul 2011 23:47:12 -0700 Subject: [PATCH 0068/1150] Add operation counts to network statistics. Provide API to increment "operation counts" for a UID and tag, used to eventually derive bytes/operation stats. Internally is stored at network layer, but should belong at data layer. Switch profiling to use data layer stats, which are emulated by summarizing network layer details. Read packet counts from new /proc/ columns and collect them into NetworkStatsHistory. Prevent double-counting by ignoring values from first snapshot. Watch for duplicate /proc/ entries. Update tests to verify packet and operation counters. Bug: 5052136, 5097392 Change-Id: I1832f65a2b8a9188f8088f253474a667c21a2f09 --- .../android/net/INetworkStatsService.aidl | 13 +- core/java/android/net/NetworkStats.java | 85 +++++-- .../java/android/net/NetworkStatsHistory.java | 227 +++++++++++++----- core/java/android/net/TrafficStats.java | 39 ++- .../server/net/NetworkStatsService.java | 78 +++++- 5 files changed, 340 insertions(+), 102 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 054825024b..c41d182cfa 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,16 +23,21 @@ import android.net.NetworkTemplate; /** {@hide} */ interface INetworkStatsService { - /** Return historical stats for traffic that matches template. */ + /** Return historical network layer stats for traffic that matches template. */ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); - /** Return historical stats for specific UID traffic that matches template. */ + /** Return historical network layer stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag); - /** Return usage summary for traffic that matches template. */ + /** Return network layer usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); - /** Return usage summary per UID for traffic that matches template. */ + /** Return network layer usage summary per UID for traffic that matches template. */ NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + /** Return data layer snapshot of UID network usage. */ + NetworkStats getDataLayerSnapshotForUid(int uid); + /** Increment data layer count of operations performed for UID and tag. */ + void incrementOperationCount(int uid, int tag, int operationCount); + /** Force update of statistics. */ void forceUpdate(); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index fbff7d89fc..0e8e7fc5ec 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,8 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.SparseBooleanArray; +import com.android.internal.util.Objects; + import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; @@ -56,6 +58,7 @@ public class NetworkStats implements Parcelable { private long[] rxPackets; private long[] txBytes; private long[] txPackets; + private int[] operations; public static class Entry { public String iface; @@ -65,12 +68,13 @@ public class NetworkStats implements Parcelable { public long rxPackets; public long txBytes; public long txPackets; + public int operations; public Entry() { } public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, - long txPackets) { + long txPackets, int operations) { this.iface = iface; this.uid = uid; this.tag = tag; @@ -78,6 +82,7 @@ public class NetworkStats implements Parcelable { this.rxPackets = rxPackets; this.txBytes = txBytes; this.txPackets = txPackets; + this.operations = operations; } } @@ -91,6 +96,7 @@ public class NetworkStats implements Parcelable { this.rxPackets = new long[initialSize]; this.txBytes = new long[initialSize]; this.txPackets = new long[initialSize]; + this.operations = new int[initialSize]; } public NetworkStats(Parcel parcel) { @@ -103,11 +109,32 @@ public class NetworkStats implements Parcelable { rxPackets = parcel.createLongArray(); txBytes = parcel.createLongArray(); txPackets = parcel.createLongArray(); + operations = parcel.createIntArray(); + } + + /** {@inheritDoc} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(elapsedRealtime); + dest.writeInt(size); + dest.writeStringArray(iface); + dest.writeIntArray(uid); + dest.writeIntArray(tag); + dest.writeLongArray(rxBytes); + dest.writeLongArray(rxPackets); + dest.writeLongArray(txBytes); + dest.writeLongArray(txPackets); + dest.writeIntArray(operations); } public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets)); + return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0); + } + + public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets, int operations) { + return addValues( + new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @@ -124,6 +151,7 @@ public class NetworkStats implements Parcelable { rxPackets = Arrays.copyOf(rxPackets, newLength); txBytes = Arrays.copyOf(txBytes, newLength); txPackets = Arrays.copyOf(txPackets, newLength); + operations = Arrays.copyOf(operations, newLength); } iface[size] = entry.iface; @@ -133,6 +161,7 @@ public class NetworkStats implements Parcelable { rxPackets[size] = entry.rxPackets; txBytes[size] = entry.txBytes; txPackets[size] = entry.txPackets; + operations[size] = entry.operations; size++; return this; @@ -150,6 +179,7 @@ public class NetworkStats implements Parcelable { entry.rxPackets = rxPackets[i]; entry.txBytes = txBytes[i]; entry.txPackets = txPackets[i]; + entry.operations = operations[i]; return entry; } @@ -167,8 +197,9 @@ public class NetworkStats implements Parcelable { } public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets) { - return combineValues(new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets)); + long txBytes, long txPackets, int operations) { + return combineValues( + new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @@ -186,6 +217,7 @@ public class NetworkStats implements Parcelable { rxPackets[i] += entry.rxPackets; txBytes[i] += entry.txBytes; txPackets[i] += entry.txPackets; + operations[i] += entry.operations; } return this; } @@ -195,13 +227,29 @@ public class NetworkStats implements Parcelable { */ public int findIndex(String iface, int uid, int tag) { for (int i = 0; i < size; i++) { - if (equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) { + if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) { return i; } } return -1; } + /** + * Splice in {@link #operations} from the given {@link NetworkStats} based + * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, + * since operation counts are at data layer. + */ + public void spliceOperationsFrom(NetworkStats stats) { + for (int i = 0; i < size; i++) { + final int j = stats.findIndex(IFACE_ALL, uid[i], tag[i]); + if (j == -1) { + operations[i] = 0; + } else { + operations[i] = stats.operations[j]; + } + } + } + /** * Return list of unique interfaces known by this data structure. */ @@ -289,15 +337,17 @@ public class NetworkStats implements Parcelable { entry.rxPackets = rxPackets[i]; entry.txBytes = txBytes[i]; entry.txPackets = txPackets[i]; + entry.operations = operations[i]; } else { // existing row, subtract remote value entry.rxBytes = rxBytes[i] - value.rxBytes[j]; entry.rxPackets = rxPackets[i] - value.rxPackets[j]; entry.txBytes = txBytes[i] - value.txBytes[j]; entry.txPackets = txPackets[i] - value.txPackets[j]; + entry.operations = operations[i] - value.operations[j]; if (enforceMonotonic && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 - || entry.txPackets < 0)) { + || entry.txPackets < 0 || entry.operations < 0)) { throw new IllegalArgumentException("found non-monotonic values"); } if (clampNegative) { @@ -305,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.rxPackets = Math.max(0, entry.rxPackets); entry.txBytes = Math.max(0, entry.txBytes); entry.txPackets = Math.max(0, entry.txPackets); + entry.operations = Math.max(0, entry.operations); } } @@ -314,10 +365,6 @@ public class NetworkStats implements Parcelable { return result; } - private static boolean equal(Object a, Object b) { - return a == b || (a != null && a.equals(b)); - } - public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); @@ -325,11 +372,12 @@ public class NetworkStats implements Parcelable { pw.print(prefix); pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); - pw.print(" tag="); pw.print(tag[i]); + pw.print(" tag=0x"); pw.print(Integer.toHexString(tag[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); pw.print(" txBytes="); pw.print(txBytes[i]); - pw.print(" txPackets="); pw.println(txPackets[i]); + pw.print(" txPackets="); pw.print(txPackets[i]); + pw.print(" operations="); pw.println(operations[i]); } } @@ -345,19 +393,6 @@ public class NetworkStats implements Parcelable { return 0; } - /** {@inheritDoc} */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(elapsedRealtime); - dest.writeInt(size); - dest.writeStringArray(iface); - dest.writeIntArray(uid); - dest.writeIntArray(tag); - dest.writeLongArray(rxBytes); - dest.writeLongArray(rxPackets); - dest.writeLongArray(txBytes); - dest.writeLongArray(txPackets); - } - public static final Creator CREATOR = new Creator() { public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 8bd1738937..4ffabb15b6 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -16,6 +16,16 @@ package android.net; +import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStatsHistory.DataStreamUtils.readLongArray; +import static android.net.NetworkStatsHistory.DataStreamUtils.writeLongArray; +import static android.net.NetworkStatsHistory.ParcelUtils.readIntArray; +import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; +import static android.net.NetworkStatsHistory.ParcelUtils.writeIntArray; +import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; + import android.os.Parcel; import android.os.Parcelable; @@ -43,19 +53,26 @@ public class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; // TODO: teach about varint encoding to use less disk space - // TODO: extend to record rxPackets/txPackets + // TODO: teach about omitting entire fields to reduce parcel pressure + // TODO: persist/restore packet and operation counts private final long bucketDuration; private int bucketCount; private long[] bucketStart; private long[] rxBytes; + private long[] rxPackets; private long[] txBytes; + private long[] txPackets; + private int[] operations; public static class Entry { public long bucketStart; public long bucketDuration; public long rxBytes; + public long rxPackets; public long txBytes; + public long txPackets; + public int operations; } public NetworkStatsHistory(long bucketDuration) { @@ -66,15 +83,21 @@ public class NetworkStatsHistory implements Parcelable { this.bucketDuration = bucketDuration; bucketStart = new long[initialSize]; rxBytes = new long[initialSize]; + rxPackets = new long[initialSize]; txBytes = new long[initialSize]; + txPackets = new long[initialSize]; + operations = new int[initialSize]; bucketCount = 0; } public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); - rxBytes = in.createLongArray(); - txBytes = in.createLongArray(); + rxBytes = readLongArray(in); + rxPackets = readLongArray(in); + txBytes = readLongArray(in); + txPackets = readLongArray(in); + operations = readIntArray(in); bucketCount = bucketStart.length; } @@ -83,17 +106,24 @@ public class NetworkStatsHistory implements Parcelable { out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, rxBytes, bucketCount); + writeLongArray(out, rxPackets, bucketCount); writeLongArray(out, txBytes, bucketCount); + writeLongArray(out, txPackets, bucketCount); + writeIntArray(out, operations, bucketCount); } public NetworkStatsHistory(DataInputStream in) throws IOException { + // TODO: read packet and operation counts final int version = in.readInt(); switch (version) { case VERSION_INIT: { bucketDuration = in.readLong(); bucketStart = readLongArray(in); rxBytes = readLongArray(in); + rxPackets = new long[bucketStart.length]; txBytes = readLongArray(in); + txPackets = new long[bucketStart.length]; + operations = new int[bucketStart.length]; bucketCount = bucketStart.length; break; } @@ -104,6 +134,7 @@ public class NetworkStatsHistory implements Parcelable { } public void writeToStream(DataOutputStream out) throws IOException { + // TODO: write packet and operation counts out.writeInt(VERSION_INIT); out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); @@ -148,7 +179,10 @@ public class NetworkStatsHistory implements Parcelable { entry.bucketStart = bucketStart[i]; entry.bucketDuration = bucketDuration; entry.rxBytes = rxBytes[i]; + entry.rxPackets = rxPackets[i]; entry.txBytes = txBytes[i]; + entry.txPackets = txPackets[i]; + entry.operations = operations[i]; return entry; } @@ -156,17 +190,27 @@ public class NetworkStatsHistory implements Parcelable { * Record that data traffic occurred in the given time range. Will * distribute across internal buckets, creating new buckets as needed. */ - public void recordData(long start, long end, long rx, long tx) { - if (rx < 0 || tx < 0) { - throw new IllegalArgumentException( - "tried recording negative data: rx=" + rx + ", tx=" + tx); + @Deprecated + public void recordData(long start, long end, long rxBytes, long txBytes) { + recordData(start, end, + new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0)); + } + + /** + * Record that data traffic occurred in the given time range. Will + * distribute across internal buckets, creating new buckets as needed. + */ + public void recordData(long start, long end, NetworkStats.Entry entry) { + if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 + || entry.operations < 0) { + throw new IllegalArgumentException("tried recording negative data"); } // create any buckets needed by this range ensureBuckets(start, end); // distribute data usage into buckets - final long duration = end - start; + long duration = end - start; for (int i = bucketCount - 1; i >= 0; i--) { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; @@ -177,10 +221,22 @@ public class NetworkStatsHistory implements Parcelable { if (curStart > end) continue; final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (overlap > 0) { - this.rxBytes[i] += rx * overlap / duration; - this.txBytes[i] += tx * overlap / duration; - } + if (overlap <= 0) continue; + + // integer math each time is faster than floating point + final long fracRxBytes = entry.rxBytes * overlap / duration; + final long fracRxPackets = entry.rxPackets * overlap / duration; + final long fracTxBytes = entry.txBytes * overlap / duration; + final long fracTxPackets = entry.txPackets * overlap / duration; + final int fracOperations = (int) (entry.operations * overlap / duration); + + rxBytes[i] += fracRxBytes; entry.rxBytes -= fracRxBytes; + rxPackets[i] += fracRxPackets; entry.rxPackets -= fracRxPackets; + txBytes[i] += fracTxBytes; entry.txBytes -= fracTxBytes; + txPackets[i] += fracTxPackets; entry.txPackets -= fracTxPackets; + operations[i] += fracOperations; entry.operations -= fracOperations; + + duration -= overlap; } } @@ -189,10 +245,19 @@ public class NetworkStatsHistory implements Parcelable { * for combining together stats for external reporting. */ public void recordEntireHistory(NetworkStatsHistory input) { + final NetworkStats.Entry entry = new NetworkStats.Entry( + IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0); for (int i = 0; i < input.bucketCount; i++) { final long start = input.bucketStart[i]; final long end = start + input.bucketDuration; - recordData(start, end, input.rxBytes[i], input.txBytes[i]); + + entry.rxBytes = input.rxBytes[i]; + entry.rxPackets = input.rxPackets[i]; + entry.txBytes = input.txBytes[i]; + entry.txPackets = input.txPackets[i]; + entry.operations = input.operations[i]; + + recordData(start, end, entry); } } @@ -223,7 +288,10 @@ public class NetworkStatsHistory implements Parcelable { final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); + rxPackets = Arrays.copyOf(rxPackets, newLength); txBytes = Arrays.copyOf(txBytes, newLength); + txPackets = Arrays.copyOf(txPackets, newLength); + operations = Arrays.copyOf(operations, newLength); } // create gap when inserting bucket in middle @@ -233,12 +301,18 @@ public class NetworkStatsHistory implements Parcelable { System.arraycopy(bucketStart, index, bucketStart, dstPos, length); System.arraycopy(rxBytes, index, rxBytes, dstPos, length); + System.arraycopy(rxPackets, index, rxPackets, dstPos, length); System.arraycopy(txBytes, index, txBytes, dstPos, length); + System.arraycopy(txPackets, index, txPackets, dstPos, length); + System.arraycopy(operations, index, operations, dstPos, length); } bucketStart[index] = start; rxBytes[index] = 0; + rxPackets[index] = 0; txBytes[index] = 0; + txPackets[index] = 0; + operations[index] = 0; bucketCount++; } @@ -260,7 +334,10 @@ public class NetworkStatsHistory implements Parcelable { final int length = bucketStart.length; bucketStart = Arrays.copyOfRange(bucketStart, i, length); rxBytes = Arrays.copyOfRange(rxBytes, i, length); + rxPackets = Arrays.copyOfRange(rxPackets, i, length); txBytes = Arrays.copyOfRange(txBytes, i, length); + txPackets = Arrays.copyOfRange(txPackets, i, length); + operations = Arrays.copyOfRange(operations, i, length); bucketCount -= i; } } @@ -282,7 +359,10 @@ public class NetworkStatsHistory implements Parcelable { entry.bucketStart = start; entry.bucketDuration = end - start; entry.rxBytes = 0; + entry.rxPackets = 0; entry.txBytes = 0; + entry.txPackets = 0; + entry.operations = 0; for (int i = bucketCount - 1; i >= 0; i--) { final long curStart = bucketStart[i]; @@ -295,14 +375,16 @@ public class NetworkStatsHistory implements Parcelable { // include full value for active buckets, otherwise only fractional final boolean activeBucket = curStart < now && curEnd > now; - final long overlap = Math.min(curEnd, end) - Math.max(curStart, start); - if (activeBucket || overlap == bucketDuration) { - entry.rxBytes += rxBytes[i]; - entry.txBytes += txBytes[i]; - } else if (overlap > 0) { - entry.rxBytes += rxBytes[i] * overlap / bucketDuration; - entry.txBytes += txBytes[i] * overlap / bucketDuration; - } + final long overlap = activeBucket ? bucketDuration + : Math.min(curEnd, end) - Math.max(curStart, start); + if (overlap <= 0) continue; + + // integer math each time is faster than floating point + entry.rxBytes += rxBytes[i] * overlap / bucketDuration; + entry.rxPackets += rxPackets[i] * overlap / bucketDuration; + entry.txBytes += txBytes[i] * overlap / bucketDuration; + entry.txPackets += txPackets[i] * overlap / bucketDuration; + entry.operations += operations[i] * overlap / bucketDuration; } return entry; @@ -315,17 +397,19 @@ public class NetworkStatsHistory implements Parcelable { public void generateRandom(long start, long end, long rx, long tx) { ensureBuckets(start, end); + final NetworkStats.Entry entry = new NetworkStats.Entry( + IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0); final Random r = new Random(); while (rx > 1024 && tx > 1024) { final long curStart = randomLong(r, start, end); final long curEnd = randomLong(r, curStart, end); - final long curRx = randomLong(r, 0, rx); - final long curTx = randomLong(r, 0, tx); + entry.rxBytes = randomLong(r, 0, rx); + entry.txBytes = randomLong(r, 0, tx); - recordData(curStart, curEnd, curRx, curTx); + recordData(curStart, curEnd, entry); - rx -= curRx; - tx -= curTx; + rx -= entry.rxBytes; + tx -= entry.txBytes; } } @@ -347,7 +431,10 @@ public class NetworkStatsHistory implements Parcelable { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); pw.print(" rxBytes="); pw.print(rxBytes[i]); - pw.print(" txBytes="); pw.println(txBytes[i]); + pw.print(" rxPackets="); pw.print(rxPackets[i]); + pw.print(" txBytes="); pw.print(txBytes[i]); + pw.print(" txPackets="); pw.print(txPackets[i]); + pw.print(" operations="); pw.println(operations[i]); } } @@ -368,41 +455,73 @@ public class NetworkStatsHistory implements Parcelable { } }; - private static long[] readLongArray(DataInputStream in) throws IOException { - final int size = in.readInt(); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); + /** + * Utility methods for interacting with {@link DataInputStream} and + * {@link DataOutputStream}, mostly dealing with writing partial arrays. + */ + public static class DataStreamUtils { + public static long[] readLongArray(DataInputStream in) throws IOException { + final int size = in.readInt(); + final long[] values = new long[size]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + return values; } - return values; - } - private static void writeLongArray(DataOutputStream out, long[] values, int size) throws IOException { - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - out.writeLong(values[i]); + public static void writeLongArray(DataOutputStream out, long[] values, int size) + throws IOException { + if (size > values.length) { + throw new IllegalArgumentException("size larger than length"); + } + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeLong(values[i]); + } } } - private static long[] readLongArray(Parcel in) { - final int size = in.readInt(); - final long[] values = new long[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readLong(); + /** + * Utility methods for interacting with {@link Parcel} structures, mostly + * dealing with writing partial arrays. + */ + public static class ParcelUtils { + public static long[] readLongArray(Parcel in) { + final int size = in.readInt(); + final long[] values = new long[size]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readLong(); + } + return values; } - return values; - } - private static void writeLongArray(Parcel out, long[] values, int size) { - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); + public static void writeLongArray(Parcel out, long[] values, int size) { + if (size > values.length) { + throw new IllegalArgumentException("size larger than length"); + } + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeLong(values[i]); + } } - out.writeInt(size); - for (int i = 0; i < size; i++) { - out.writeLong(values[i]); + + public static int[] readIntArray(Parcel in) { + final int size = in.readInt(); + final int[] values = new int[size]; + for (int i = 0; i < values.length; i++) { + values[i] = in.readInt(); + } + return values; + } + + public static void writeIntArray(Parcel out, int[] values, int size) { + if (size > values.length) { + throw new IllegalArgumentException("size larger than length"); + } + out.writeInt(size); + for (int i = 0; i < size; i++) { + out.writeInt(values[i]); + } } } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e054930684..f138e49140 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,14 +20,13 @@ import android.app.DownloadManager; import android.app.backup.BackupManager; import android.content.Context; import android.media.MediaPlayer; -import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.ServiceManager; import com.android.server.NetworkManagementSocketTagger; import dalvik.system.SocketTagger; + import java.net.Socket; import java.net.SocketException; @@ -172,7 +171,7 @@ public class TrafficStats { } // take snapshot in time; we calculate delta later - sActiveProfilingStart = getNetworkStatsForUid(context); + sActiveProfilingStart = getDataLayerSnapshotForUid(context); } } @@ -190,7 +189,7 @@ public class TrafficStats { } // subtract starting values and return delta - final NetworkStats profilingStop = getNetworkStatsForUid(context); + final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); final NetworkStats profilingDelta = profilingStop.subtractClamped( sActiveProfilingStart); sActiveProfilingStart = null; @@ -198,6 +197,28 @@ public class TrafficStats { } } + /** + * Increment count of network operations performed under the given + * accounting tag. This can be used to derive bytes-per-operation. + * + * @param tag Accounting tag used in {@link #setThreadStatsTag(int)}. + * @param operationCount Number of operations to increment count by. + */ + public static void incrementOperationCount(int tag, int operationCount) { + if (operationCount < 0) { + throw new IllegalArgumentException("operation count can only be incremented"); + } + + final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + final int uid = android.os.Process.myUid(); + try { + statsService.incrementOperationCount(uid, tag, operationCount); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** * Get the total number of packets transmitted through the mobile interface. * @@ -461,14 +482,12 @@ public class TrafficStats { * Return detailed {@link NetworkStats} for the current UID. Requires no * special permission. */ - private static NetworkStats getNetworkStatsForUid(Context context) { - final IBinder binder = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); - final INetworkManagementService service = INetworkManagementService.Stub.asInterface( - binder); - + private static NetworkStats getDataLayerSnapshotForUid(Context context) { + final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); try { - return service.getNetworkStatsUidDetail(uid); + return statsService.getDataLayerSnapshotForUid(uid); } catch (RemoteException e) { throw new RuntimeException(e); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 6cc01f40d9..24188cab76 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; +import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.DUMP; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; @@ -56,6 +58,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.os.Binder; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -65,6 +68,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; +import android.util.Log; import android.util.LongSparseArray; import android.util.NtpTrustedTime; import android.util.Slog; @@ -150,9 +154,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of currently active ifaces. */ private HashMap mActiveIfaces = Maps.newHashMap(); - /** Set of historical stats for known networks. */ + /** Set of historical network layer stats for known networks. */ private HashMap mNetworkStats = Maps.newHashMap(); - /** Set of historical stats for known UIDs. */ + /** Set of historical network layer stats for known UIDs. */ private HashMap> mUidStats = Maps.newHashMap(); @@ -164,6 +168,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats mLastUidSnapshot; + /** Data layer operation counters for splicing into other structures. */ + private NetworkStats mOperations = new NetworkStats(0L, 10); + private NetworkStats mLastOperationsSnapshot; + private final HandlerThread mHandlerThread; private final Handler mHandler; @@ -381,9 +389,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { entry.uid = uid; entry.tag = tag; entry.rxBytes = historyEntry.rxBytes; + entry.rxPackets = historyEntry.rxPackets; entry.txBytes = historyEntry.txBytes; + entry.txPackets = historyEntry.txPackets; + entry.operations = historyEntry.operations; - if (entry.rxBytes > 0 || entry.txBytes > 0) { + if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 + || entry.txPackets > 0 || entry.operations > 0) { stats.combineValues(entry); } } @@ -395,6 +407,41 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { + if (Binder.getCallingUid() != uid) { + mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); + } + + // TODO: switch to data layer stats once kernel exports + // for now, read network layer stats and flatten across all ifaces + final NetworkStats networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + final NetworkStats dataLayer = new NetworkStats( + networkLayer.getElapsedRealtime(), networkLayer.size()); + + NetworkStats.Entry entry = null; + for (int i = 0; i < networkLayer.size(); i++) { + entry = networkLayer.getValues(i, entry); + entry.iface = IFACE_ALL; + dataLayer.combineValues(entry); + } + + // splice in operation counts + dataLayer.spliceOperationsFrom(mOperations); + return dataLayer; + } + + @Override + public void incrementOperationCount(int uid, int tag, int operationCount) { + if (Binder.getCallingUid() != uid) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + } + + synchronized (mStatsLock) { + mOperations.combineValues(IFACE_ALL, uid, tag, 0L, 0L, 0L, 0L, operationCount); + } + } + @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); @@ -533,7 +580,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats uidSnapshot; try { networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsDetail() : null; + uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsUidDetail(UID_ALL) : null; } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); return; @@ -592,7 +639,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); - history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes); + history.recordData(timeStart, currentTime, entry); } // trim any history beyond max @@ -615,9 +662,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot); + final NetworkStats operationsDelta = computeStatsDelta( + mLastOperationsSnapshot, mOperations); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; + NetworkStats.Entry operationsEntry = null; for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); @@ -625,9 +675,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { continue; } + // splice in operation counts since last poll + final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.tag); + if (j != -1) { + operationsEntry = operationsDelta.getValues(j, operationsEntry); + entry.operations = operationsEntry.operations; + } + final NetworkStatsHistory history = findOrCreateUidStatsLocked( ident, entry.uid, entry.tag); - history.recordData(timeStart, currentTime, entry.rxBytes, entry.txBytes); + history.recordData(timeStart, currentTime, entry); } // trim any history beyond max @@ -648,6 +705,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mLastUidSnapshot = uidSnapshot; + mLastOperationsSnapshot = mOperations; + mOperations = new NetworkStats(0L, 10); } /** @@ -980,7 +1039,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int tag = unpackTag(packed); final NetworkStatsHistory history = uidStats.valueAt(i); pw.print(" UID="); pw.print(uid); - pw.print(" tag="); pw.println(tag); + pw.print(" tag=0x"); pw.println(Integer.toHexString(tag)); history.dump(" ", pw, fullHistory); } } @@ -1028,7 +1087,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (before != null) { return current.subtractClamped(before); } else { - return current; + // this is first snapshot; to prevent from double-counting we only + // observe traffic occuring between known snapshots. + return new NetworkStats(0L, 10); } } @@ -1114,5 +1175,4 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return DAY_IN_MILLIS; } } - } From 84b60d6489a7e9e293390a3e56fd09b2de4cfbb3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 2 Aug 2011 17:22:34 -0700 Subject: [PATCH 0069/1150] Expose quota status for active network. Create API to expose quota status derived from underlying network policy. This is designed to support applications making informed decisions when performing network requests. Fix bug with random stats generation, and write policy when changing restrict background data flag. Deprecate EXTRA_NETWORK_INFO, since it varies based on UID. Bug: 4517283, 5088603 Change-Id: Ic6893a8967f69937e466be226ba7bb86ef5a5d2d --- core/java/android/net/NetworkStatsHistory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 4ffabb15b6..7a4b811763 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -405,11 +405,10 @@ public class NetworkStatsHistory implements Parcelable { final long curEnd = randomLong(r, curStart, end); entry.rxBytes = randomLong(r, 0, rx); entry.txBytes = randomLong(r, 0, tx); - - recordData(curStart, curEnd, entry); - rx -= entry.rxBytes; tx -= entry.txBytes; + + recordData(curStart, curEnd, entry); } } From 4ac474e88b66a4ccbb1917b36cae86ef2afd399b Mon Sep 17 00:00:00 2001 From: Chia-chi Yeh Date: Wed, 3 Aug 2011 14:42:11 -0700 Subject: [PATCH 0070/1150] NativeDaemonConnector: offload callbacks to another thread. Now callbacks can communicate to the same daemon without causing a deadlock. This also improves the latency of calls because they no longer need to wait for the callbacks for the pending events. Change-Id: I153fcf16bd64de79ee1c1a57d3cfdb12b354cf47 --- .../android/server/NativeDaemonConnector.java | 38 +++++++++++++------ 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 88d94c2c10..fed554cce3 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -19,6 +19,9 @@ package com.android.server; import android.net.LocalSocketAddress; import android.net.LocalSocket; import android.os.Environment; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; import android.os.SystemClock; import android.os.SystemProperties; import android.util.Slog; @@ -39,7 +42,7 @@ import java.util.concurrent.LinkedBlockingQueue; * daemon which uses the libsysutils FrameworkListener * protocol. */ -final class NativeDaemonConnector implements Runnable { +final class NativeDaemonConnector implements Runnable, Handler.Callback { private static final boolean LOCAL_LOGD = false; private BlockingQueue mResponseQueue; @@ -47,6 +50,7 @@ final class NativeDaemonConnector implements Runnable { private String TAG = "NativeDaemonConnector"; private String mSocket; private INativeDaemonConnectorCallbacks mCallbacks; + private Handler mCallbackHandler; private final int BUFFER_SIZE = 4096; @@ -76,7 +80,11 @@ final class NativeDaemonConnector implements Runnable { mResponseQueue = new LinkedBlockingQueue(responseQueueSize); } + @Override public void run() { + HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); + thread.start(); + mCallbackHandler = new Handler(thread.getLooper(), this); while (true) { try { @@ -88,6 +96,21 @@ final class NativeDaemonConnector implements Runnable { } } + @Override + public boolean handleMessage(Message msg) { + String event = (String) msg.obj; + try { + if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { + Slog.w(TAG, String.format( + "Unhandled event '%s'", event)); + } + } catch (Exception e) { + Slog.e(TAG, String.format( + "Error handling '%s'", event), e); + } + return true; + } + private void listenToSocket() throws IOException { LocalSocket socket = null; @@ -119,20 +142,13 @@ final class NativeDaemonConnector implements Runnable { String event = new String(buffer, start, i - start); if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event)); - String[] tokens = event.split(" "); + String[] tokens = event.split(" ", 2); try { int code = Integer.parseInt(tokens[0]); if (code >= ResponseCode.UnsolicitedInformational) { - try { - if (!mCallbacks.onEvent(code, event, tokens)) { - Slog.w(TAG, String.format( - "Unhandled event (%s)", event)); - } - } catch (Exception ex) { - Slog.e(TAG, String.format( - "Error handling '%s'", event), ex); - } + mCallbackHandler.sendMessage( + mCallbackHandler.obtainMessage(code, event)); } else { try { mResponseQueue.put(event); From c76817d37071a38354ccc77f691c293009ea7c52 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 3 Aug 2011 17:04:22 -0700 Subject: [PATCH 0071/1150] Network stats with varint, omit parcel fields. Persist NetworkStatsHistory using variable-length encoding; since most buckets have small numbers, we can encode them tighter. Initial test showed 44% space savings. Also persist packet and operation counters. Let NetworkStatsHistory consumers request which fields they actually need to reduce parcel overhead. Tests for verify varint and history field requests, also verify end- to-end by persisting history into byte[] and restoring. Expose bandwidth control enabled state. Extend random generation to create packet and operation counts. Moved operation counts to long. Fix bug that miscalculated bytes since last persist, which would cause partial stats loss when battery pulled. Bug: 4581977, 5023706, 5023635, 5096903 Change-Id: If61e89f681ffa11fe5711471fd9f7c238d3d37b0 --- .../android/net/INetworkStatsService.aidl | 4 +- core/java/android/net/NetworkStats.java | 23 +- .../java/android/net/NetworkStatsHistory.java | 296 +++++++++++------- .../server/net/NetworkStatsService.java | 59 ++-- 4 files changed, 238 insertions(+), 144 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index c41d182cfa..b65506c411 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -24,9 +24,9 @@ import android.net.NetworkTemplate; interface INetworkStatsService { /** Return historical network layer stats for traffic that matches template. */ - NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template); + NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); /** Return historical network layer stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields); /** Return network layer usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0e8e7fc5ec..f2fcb8fad8 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -58,7 +58,7 @@ public class NetworkStats implements Parcelable { private long[] rxPackets; private long[] txBytes; private long[] txPackets; - private int[] operations; + private long[] operations; public static class Entry { public String iface; @@ -68,13 +68,18 @@ public class NetworkStats implements Parcelable { public long rxPackets; public long txBytes; public long txPackets; - public int operations; + public long operations; public Entry() { + this(IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); + } + + public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + this(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations); } public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, - long txPackets, int operations) { + long txPackets, long operations) { this.iface = iface; this.uid = uid; this.tag = tag; @@ -96,7 +101,7 @@ public class NetworkStats implements Parcelable { this.rxPackets = new long[initialSize]; this.txBytes = new long[initialSize]; this.txPackets = new long[initialSize]; - this.operations = new int[initialSize]; + this.operations = new long[initialSize]; } public NetworkStats(Parcel parcel) { @@ -109,7 +114,7 @@ public class NetworkStats implements Parcelable { rxPackets = parcel.createLongArray(); txBytes = parcel.createLongArray(); txPackets = parcel.createLongArray(); - operations = parcel.createIntArray(); + operations = parcel.createLongArray(); } /** {@inheritDoc} */ @@ -123,16 +128,16 @@ public class NetworkStats implements Parcelable { dest.writeLongArray(rxPackets); dest.writeLongArray(txBytes); dest.writeLongArray(txPackets); - dest.writeIntArray(operations); + dest.writeLongArray(operations); } public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0); + return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L); } public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, int operations) { + long txBytes, long txPackets, long operations) { return addValues( new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -197,7 +202,7 @@ public class NetworkStats implements Parcelable { } public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, int operations) { + long txBytes, long txPackets, long operations) { return combineValues( new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 7a4b811763..c917af919e 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -19,11 +19,11 @@ package android.net; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.DataStreamUtils.readLongArray; -import static android.net.NetworkStatsHistory.DataStreamUtils.writeLongArray; -import static android.net.NetworkStatsHistory.ParcelUtils.readIntArray; +import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray; +import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLongArray; +import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; +import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; -import static android.net.NetworkStatsHistory.ParcelUtils.writeIntArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import android.os.Parcel; @@ -51,42 +51,53 @@ import java.util.Random; */ public class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; + private static final int VERSION_ADD_PACKETS = 2; - // TODO: teach about varint encoding to use less disk space - // TODO: teach about omitting entire fields to reduce parcel pressure - // TODO: persist/restore packet and operation counts + public static final int FIELD_RX_BYTES = 0x01; + public static final int FIELD_RX_PACKETS = 0x02; + public static final int FIELD_TX_BYTES = 0x04; + public static final int FIELD_TX_PACKETS = 0x08; + public static final int FIELD_OPERATIONS = 0x10; - private final long bucketDuration; + public static final int FIELD_ALL = 0xFFFFFFFF; + + private long bucketDuration; private int bucketCount; private long[] bucketStart; private long[] rxBytes; private long[] rxPackets; private long[] txBytes; private long[] txPackets; - private int[] operations; + private long[] operations; public static class Entry { + public static final long UNKNOWN = -1; + public long bucketStart; public long bucketDuration; public long rxBytes; public long rxPackets; public long txBytes; public long txPackets; - public int operations; + public long operations; } public NetworkStatsHistory(long bucketDuration) { - this(bucketDuration, 10); + this(bucketDuration, 10, FIELD_ALL); } public NetworkStatsHistory(long bucketDuration, int initialSize) { + this(bucketDuration, initialSize, FIELD_ALL); + } + + public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { this.bucketDuration = bucketDuration; bucketStart = new long[initialSize]; - rxBytes = new long[initialSize]; - rxPackets = new long[initialSize]; - txBytes = new long[initialSize]; - txPackets = new long[initialSize]; - operations = new int[initialSize]; + if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize]; + if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize]; + if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize]; + if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize]; + if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize]; bucketCount = 0; } @@ -97,7 +108,7 @@ public class NetworkStatsHistory implements Parcelable { rxPackets = readLongArray(in); txBytes = readLongArray(in); txPackets = readLongArray(in); - operations = readIntArray(in); + operations = readLongArray(in); bucketCount = bucketStart.length; } @@ -109,21 +120,31 @@ public class NetworkStatsHistory implements Parcelable { writeLongArray(out, rxPackets, bucketCount); writeLongArray(out, txBytes, bucketCount); writeLongArray(out, txPackets, bucketCount); - writeIntArray(out, operations, bucketCount); + writeLongArray(out, operations, bucketCount); } public NetworkStatsHistory(DataInputStream in) throws IOException { - // TODO: read packet and operation counts final int version = in.readInt(); switch (version) { case VERSION_INIT: { bucketDuration = in.readLong(); - bucketStart = readLongArray(in); - rxBytes = readLongArray(in); + bucketStart = readFullLongArray(in); + rxBytes = readFullLongArray(in); rxPackets = new long[bucketStart.length]; - txBytes = readLongArray(in); + txBytes = readFullLongArray(in); txPackets = new long[bucketStart.length]; - operations = new int[bucketStart.length]; + operations = new long[bucketStart.length]; + bucketCount = bucketStart.length; + break; + } + case VERSION_ADD_PACKETS: { + bucketDuration = in.readLong(); + bucketStart = readVarLongArray(in); + rxBytes = readVarLongArray(in); + rxPackets = readVarLongArray(in); + txBytes = readVarLongArray(in); + txPackets = readVarLongArray(in); + operations = readVarLongArray(in); bucketCount = bucketStart.length; break; } @@ -134,12 +155,14 @@ public class NetworkStatsHistory implements Parcelable { } public void writeToStream(DataOutputStream out) throws IOException { - // TODO: write packet and operation counts - out.writeInt(VERSION_INIT); + out.writeInt(VERSION_ADD_PACKETS); out.writeLong(bucketDuration); - writeLongArray(out, bucketStart, bucketCount); - writeLongArray(out, rxBytes, bucketCount); - writeLongArray(out, txBytes, bucketCount); + writeVarLongArray(out, bucketStart, bucketCount); + writeVarLongArray(out, rxBytes, bucketCount); + writeVarLongArray(out, rxPackets, bucketCount); + writeVarLongArray(out, txBytes, bucketCount); + writeVarLongArray(out, txPackets, bucketCount); + writeVarLongArray(out, operations, bucketCount); } /** {@inheritDoc} */ @@ -178,11 +201,11 @@ public class NetworkStatsHistory implements Parcelable { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; entry.bucketDuration = bucketDuration; - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; + entry.rxBytes = getLong(rxBytes, i, UNKNOWN); + entry.rxPackets = getLong(rxPackets, i, UNKNOWN); + entry.txBytes = getLong(txBytes, i, UNKNOWN); + entry.txPackets = getLong(txPackets, i, UNKNOWN); + entry.operations = getLong(operations, i, UNKNOWN); return entry; } @@ -193,7 +216,7 @@ public class NetworkStatsHistory implements Parcelable { @Deprecated public void recordData(long start, long end, long rxBytes, long txBytes) { recordData(start, end, - new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0)); + new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); } /** @@ -230,11 +253,11 @@ public class NetworkStatsHistory implements Parcelable { final long fracTxPackets = entry.txPackets * overlap / duration; final int fracOperations = (int) (entry.operations * overlap / duration); - rxBytes[i] += fracRxBytes; entry.rxBytes -= fracRxBytes; - rxPackets[i] += fracRxPackets; entry.rxPackets -= fracRxPackets; - txBytes[i] += fracTxBytes; entry.txBytes -= fracTxBytes; - txPackets[i] += fracTxPackets; entry.txPackets -= fracTxPackets; - operations[i] += fracOperations; entry.operations -= fracOperations; + addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes; + addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets; + addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes; + addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets; + addLong(operations, i, fracOperations); entry.operations -= fracOperations; duration -= overlap; } @@ -246,16 +269,16 @@ public class NetworkStatsHistory implements Parcelable { */ public void recordEntireHistory(NetworkStatsHistory input) { final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0); + IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); for (int i = 0; i < input.bucketCount; i++) { final long start = input.bucketStart[i]; final long end = start + input.bucketDuration; - entry.rxBytes = input.rxBytes[i]; - entry.rxPackets = input.rxPackets[i]; - entry.txBytes = input.txBytes[i]; - entry.txPackets = input.txPackets[i]; - entry.operations = input.operations[i]; + entry.rxBytes = getLong(input.rxBytes, i, 0L); + entry.rxPackets = getLong(input.rxPackets, i, 0L); + entry.txBytes = getLong(input.txBytes, i, 0L); + entry.txPackets = getLong(input.txPackets, i, 0L); + entry.operations = getLong(input.operations, i, 0L); recordData(start, end, entry); } @@ -287,11 +310,11 @@ public class NetworkStatsHistory implements Parcelable { if (bucketCount >= bucketStart.length) { final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); - rxBytes = Arrays.copyOf(rxBytes, newLength); - rxPackets = Arrays.copyOf(rxPackets, newLength); - txBytes = Arrays.copyOf(txBytes, newLength); - txPackets = Arrays.copyOf(txPackets, newLength); - operations = Arrays.copyOf(operations, newLength); + if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength); + if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength); + if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength); + if (txPackets != null) txPackets = Arrays.copyOf(txPackets, newLength); + if (operations != null) operations = Arrays.copyOf(operations, newLength); } // create gap when inserting bucket in middle @@ -300,19 +323,19 @@ public class NetworkStatsHistory implements Parcelable { final int length = bucketCount - index; System.arraycopy(bucketStart, index, bucketStart, dstPos, length); - System.arraycopy(rxBytes, index, rxBytes, dstPos, length); - System.arraycopy(rxPackets, index, rxPackets, dstPos, length); - System.arraycopy(txBytes, index, txBytes, dstPos, length); - System.arraycopy(txPackets, index, txPackets, dstPos, length); - System.arraycopy(operations, index, operations, dstPos, length); + if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length); + if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length); + if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length); + if (txPackets != null) System.arraycopy(txPackets, index, txPackets, dstPos, length); + if (operations != null) System.arraycopy(operations, index, operations, dstPos, length); } bucketStart[index] = start; - rxBytes[index] = 0; - rxPackets[index] = 0; - txBytes[index] = 0; - txPackets[index] = 0; - operations[index] = 0; + setLong(rxBytes, index, 0L); + setLong(rxPackets, index, 0L); + setLong(txBytes, index, 0L); + setLong(txPackets, index, 0L); + setLong(operations, index, 0L); bucketCount++; } @@ -333,11 +356,11 @@ public class NetworkStatsHistory implements Parcelable { if (i > 0) { final int length = bucketStart.length; bucketStart = Arrays.copyOfRange(bucketStart, i, length); - rxBytes = Arrays.copyOfRange(rxBytes, i, length); - rxPackets = Arrays.copyOfRange(rxPackets, i, length); - txBytes = Arrays.copyOfRange(txBytes, i, length); - txPackets = Arrays.copyOfRange(txPackets, i, length); - operations = Arrays.copyOfRange(operations, i, length); + if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length); + if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length); + if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length); + if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length); + if (operations != null) operations = Arrays.copyOfRange(operations, i, length); bucketCount -= i; } } @@ -358,11 +381,11 @@ public class NetworkStatsHistory implements Parcelable { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = start; entry.bucketDuration = end - start; - entry.rxBytes = 0; - entry.rxPackets = 0; - entry.txBytes = 0; - entry.txPackets = 0; - entry.operations = 0; + entry.rxBytes = rxBytes != null ? 0 : UNKNOWN; + entry.rxPackets = rxPackets != null ? 0 : UNKNOWN; + entry.txBytes = txBytes != null ? 0 : UNKNOWN; + entry.txPackets = txPackets != null ? 0 : UNKNOWN; + entry.operations = operations != null ? 0 : UNKNOWN; for (int i = bucketCount - 1; i >= 0; i--) { final long curStart = bucketStart[i]; @@ -380,11 +403,11 @@ public class NetworkStatsHistory implements Parcelable { if (overlap <= 0) continue; // integer math each time is faster than floating point - entry.rxBytes += rxBytes[i] * overlap / bucketDuration; - entry.rxPackets += rxPackets[i] * overlap / bucketDuration; - entry.txBytes += txBytes[i] * overlap / bucketDuration; - entry.txPackets += txPackets[i] * overlap / bucketDuration; - entry.operations += operations[i] * overlap / bucketDuration; + if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration; + if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration; + if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration; + if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; + if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; } return entry; @@ -394,19 +417,29 @@ public class NetworkStatsHistory implements Parcelable { * @deprecated only for temporary testing */ @Deprecated - public void generateRandom(long start, long end, long rx, long tx) { + public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { ensureBuckets(start, end); final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0); + IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); final Random r = new Random(); - while (rx > 1024 && tx > 1024) { + while (rxBytes > 1024 && rxPackets > 128 && txBytes > 1024 && txPackets > 128 + && operations > 32) { final long curStart = randomLong(r, start, end); final long curEnd = randomLong(r, curStart, end); - entry.rxBytes = randomLong(r, 0, rx); - entry.txBytes = randomLong(r, 0, tx); - rx -= entry.rxBytes; - tx -= entry.txBytes; + + entry.rxBytes = randomLong(r, 0, rxBytes); + entry.rxPackets = randomLong(r, 0, rxPackets); + entry.txBytes = randomLong(r, 0, txBytes); + entry.txPackets = randomLong(r, 0, txPackets); + entry.operations = randomLong(r, 0, operations); + + rxBytes -= entry.rxBytes; + rxPackets -= entry.rxPackets; + txBytes -= entry.txBytes; + txPackets -= entry.txPackets; + operations -= entry.operations; recordData(curStart, curEnd, entry); } @@ -429,11 +462,12 @@ public class NetworkStatsHistory implements Parcelable { for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); - pw.print(" rxBytes="); pw.print(rxBytes[i]); - pw.print(" rxPackets="); pw.print(rxPackets[i]); - pw.print(" txBytes="); pw.print(txBytes[i]); - pw.print(" txPackets="); pw.print(txPackets[i]); - pw.print(" operations="); pw.println(operations[i]); + if (rxBytes != null) pw.print(" rxBytes="); pw.print(rxBytes[i]); + if (rxPackets != null) pw.print(" rxPackets="); pw.print(rxPackets[i]); + if (txBytes != null) pw.print(" txBytes="); pw.print(txBytes[i]); + if (txPackets != null) pw.print(" txPackets="); pw.print(txPackets[i]); + if (operations != null) pw.print(" operations="); pw.print(operations[i]); + pw.println(); } } @@ -454,12 +488,25 @@ public class NetworkStatsHistory implements Parcelable { } }; + private static long getLong(long[] array, int i, long value) { + return array != null ? array[i] : value; + } + + private static void setLong(long[] array, int i, long value) { + if (array != null) array[i] = value; + } + + private static void addLong(long[] array, int i, long value) { + if (array != null) array[i] += value; + } + /** * Utility methods for interacting with {@link DataInputStream} and * {@link DataOutputStream}, mostly dealing with writing partial arrays. */ public static class DataStreamUtils { - public static long[] readLongArray(DataInputStream in) throws IOException { + @Deprecated + public static long[] readFullLongArray(DataInputStream in) throws IOException { final int size = in.readInt(); final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { @@ -468,14 +515,59 @@ public class NetworkStatsHistory implements Parcelable { return values; } - public static void writeLongArray(DataOutputStream out, long[] values, int size) + /** + * Read variable-length {@link Long} using protobuf-style approach. + */ + public static long readVarLong(DataInputStream in) throws IOException { + int shift = 0; + long result = 0; + while (shift < 64) { + byte b = in.readByte(); + result |= (long) (b & 0x7F) << shift; + if ((b & 0x80) == 0) + return result; + shift += 7; + } + throw new ProtocolException("malformed long"); + } + + /** + * Write variable-length {@link Long} using protobuf-style approach. + */ + public static void writeVarLong(DataOutputStream out, long value) throws IOException { + while (true) { + if ((value & ~0x7FL) == 0) { + out.writeByte((int) value); + return; + } else { + out.writeByte(((int) value & 0x7F) | 0x80); + value >>>= 7; + } + } + } + + public static long[] readVarLongArray(DataInputStream in) throws IOException { + final int size = in.readInt(); + if (size == -1) return null; + final long[] values = new long[size]; + for (int i = 0; i < values.length; i++) { + values[i] = readVarLong(in); + } + return values; + } + + public static void writeVarLongArray(DataOutputStream out, long[] values, int size) throws IOException { + if (values == null) { + out.writeInt(-1); + return; + } if (size > values.length) { throw new IllegalArgumentException("size larger than length"); } out.writeInt(size); for (int i = 0; i < size; i++) { - out.writeLong(values[i]); + writeVarLong(out, values[i]); } } } @@ -487,6 +579,7 @@ public class NetworkStatsHistory implements Parcelable { public static class ParcelUtils { public static long[] readLongArray(Parcel in) { final int size = in.readInt(); + if (size == -1) return null; final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { values[i] = in.readLong(); @@ -495,6 +588,10 @@ public class NetworkStatsHistory implements Parcelable { } public static void writeLongArray(Parcel out, long[] values, int size) { + if (values == null) { + out.writeInt(-1); + return; + } if (size > values.length) { throw new IllegalArgumentException("size larger than length"); } @@ -503,25 +600,6 @@ public class NetworkStatsHistory implements Parcelable { out.writeLong(values[i]); } } - - public static int[] readIntArray(Parcel in) { - final int size = in.readInt(); - final int[] values = new int[size]; - for (int i = 0; i < values.length; i++) { - values[i] = in.readInt(); - } - return values; - } - - public static void writeIntArray(Parcel out, int[] values, int size) { - if (size > values.length) { - throw new IllegalArgumentException("size larger than length"); - } - out.writeInt(size); - for (int i = 0; i < size; i++) { - out.writeInt(values[i]); - } - } } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 24188cab76..deca7a91cf 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -16,10 +16,10 @@ package com.android.server.net; -import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.ACCESS_NETWORK_STATE; -import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; +import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; @@ -68,7 +68,6 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; -import android.util.Log; import android.util.LongSparseArray; import android.util.NtpTrustedTime; import android.util.Slog; @@ -282,13 +281,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template) { + public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getNetworkBucketDuration(), estimateNetworkBuckets()); + mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields); for (NetworkIdentitySet ident : mNetworkStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mNetworkStats.get(ident); @@ -302,7 +301,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int tag) { + public NetworkStatsHistory getHistoryForUid( + NetworkTemplate template, int uid, int tag, int fields) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { @@ -311,7 +311,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getUidBucketDuration(), estimateUidBuckets()); + mSettings.getUidBucketDuration(), estimateUidBuckets(), fields); for (NetworkIdentitySet ident : mUidStats.keySet()) { if (templateMatches(template, ident)) { final NetworkStatsHistory history = mUidStats.get(ident).get(packed); @@ -596,7 +596,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // decide if enough has changed to trigger persist final NetworkStats persistDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot); + mLastPersistNetworkSnapshot, networkSnapshot, true); final long persistThreshold = mSettings.getPersistThreshold(); NetworkStats.Entry entry = null; @@ -626,7 +626,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet unknownIface = Sets.newHashSet(); - final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot); + final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -661,9 +661,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot); + final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false); final NetworkStats operationsDelta = computeStatsDelta( - mLastOperationsSnapshot, mOperations); + mLastOperationsSnapshot, mOperations, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -932,6 +932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { out.flush(); mNetworkFile.finishWrite(fos); } catch (IOException e) { + Slog.w(TAG, "problem writing stats: ", e); if (fos != null) { mNetworkFile.failWrite(fos); } @@ -978,6 +979,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { out.flush(); mUidFile.finishWrite(fos); } catch (IOException e) { + Slog.w(TAG, "problem writing stats: ", e); if (fos != null) { mUidFile.failWrite(fos); } @@ -1052,15 +1054,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @Deprecated private void generateRandomLocked() { - long networkEnd = System.currentTimeMillis(); - long networkStart = networkEnd - mSettings.getNetworkMaxHistory(); - long networkRx = 3 * GB_IN_BYTES; - long networkTx = 2 * GB_IN_BYTES; + final long NET_END = System.currentTimeMillis(); + final long NET_START = NET_END - mSettings.getNetworkMaxHistory(); + final long NET_RX_BYTES = 3 * GB_IN_BYTES; + final long NET_RX_PACKETS = NET_RX_BYTES / 1024; + final long NET_TX_BYTES = 2 * GB_IN_BYTES; + final long NET_TX_PACKETS = NET_TX_BYTES / 1024; - long uidEnd = System.currentTimeMillis(); - long uidStart = uidEnd - mSettings.getUidMaxHistory(); - long uidRx = 500 * MB_IN_BYTES; - long uidTx = 100 * MB_IN_BYTES; + final long UID_END = System.currentTimeMillis(); + final long UID_START = UID_END - mSettings.getUidMaxHistory(); + final long UID_RX_BYTES = 500 * MB_IN_BYTES; + final long UID_RX_PACKETS = UID_RX_BYTES / 1024; + final long UID_TX_BYTES = 100 * MB_IN_BYTES; + final long UID_TX_PACKETS = UID_TX_BYTES / 1024; + final long UID_OPERATIONS = UID_RX_BYTES / 2048; final List installedApps = mContext .getPackageManager().getInstalledApplications(0); @@ -1068,13 +1075,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mNetworkStats.clear(); mUidStats.clear(); for (NetworkIdentitySet ident : mActiveIfaces.values()) { - findOrCreateNetworkStatsLocked(ident).generateRandom( - networkStart, networkEnd, networkRx, networkTx); + findOrCreateNetworkStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES, + NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L); for (ApplicationInfo info : installedApps) { final int uid = info.uid; - findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom( - uidStart, uidEnd, uidRx, uidTx); + findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END, + UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS); } } } @@ -1083,9 +1090,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return the delta between two {@link NetworkStats} snapshots, where {@code * before} can be {@code null}. */ - private static NetworkStats computeStatsDelta(NetworkStats before, NetworkStats current) { + private static NetworkStats computeStatsDelta( + NetworkStats before, NetworkStats current, boolean collectStale) { if (before != null) { return current.subtractClamped(before); + } else if (collectStale) { + // caller is okay collecting stale stats for first call. + return current; } else { // this is first snapshot; to prevent from double-counting we only // observe traffic occuring between known snapshots. From 0c001477c23ed81909380bfbbfc2a1b58c328f05 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 5 Aug 2011 11:09:46 -0700 Subject: [PATCH 0072/1150] Fix random stats generation for debugging. Change-Id: I53f0e9ea9b15fbf7b99886ea8604eda8d3958d8d --- core/java/android/net/NetworkStatsHistory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index c917af919e..4ba44cac29 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -424,8 +424,8 @@ public class NetworkStatsHistory implements Parcelable { final NetworkStats.Entry entry = new NetworkStats.Entry( IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); final Random r = new Random(); - while (rxBytes > 1024 && rxPackets > 128 && txBytes > 1024 && txPackets > 128 - && operations > 32) { + while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 + || operations > 32) { final long curStart = randomLong(r, start, end); final long curEnd = randomLong(r, curStart, end); From 7b331c0451282b3babf96167e1799ae1fc213f5f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 9 Aug 2011 21:44:24 -0700 Subject: [PATCH 0073/1150] Add NativeDaemonConnector users to watchdog. To catch instances where NativeDaemonConnector hangs while executing commands, add users to system_server watchdog. Also moved qtaguid enabler to separate thread to prevent blocking systemReady(). Bug: 5145437 Change-Id: I4c6c1dc09864a1c05f9486a31faa1b366548e911 --- .../android/server/NativeDaemonConnector.java | 72 ++++++++++--------- 1 file changed, 38 insertions(+), 34 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index fed554cce3..43d938cea3 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -16,24 +16,18 @@ package com.android.server; -import android.net.LocalSocketAddress; import android.net.LocalSocket; -import android.os.Environment; +import android.net.LocalSocketAddress; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.SystemClock; -import android.os.SystemProperties; import android.util.Slog; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.Socket; - -import java.util.List; import java.util.ArrayList; -import java.util.ListIterator; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -42,7 +36,7 @@ import java.util.concurrent.LinkedBlockingQueue; * daemon which uses the libsysutils FrameworkListener * protocol. */ -final class NativeDaemonConnector implements Runnable, Handler.Callback { +final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { private static final boolean LOCAL_LOGD = false; private BlockingQueue mResponseQueue; @@ -52,6 +46,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; + /** Lock held whenever communicating with native daemon. */ + private Object mDaemonLock = new Object(); + private final int BUFFER_SIZE = 4096; class ResponseCode { @@ -177,7 +174,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { Slog.e(TAG, "Communications error", ex); throw ex; } finally { - synchronized (this) { + synchronized (mDaemonLock) { if (mOutputStream != null) { try { mOutputStream.close(); @@ -198,9 +195,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { } } - private void sendCommand(String command) - throws NativeDaemonConnectorException { - sendCommand(command, null); + private void sendCommandLocked(String command) throws NativeDaemonConnectorException { + sendCommandLocked(command, null); } /** @@ -209,25 +205,23 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { * @param command The command to send to the daemon * @param argument The argument to send with the command (or null) */ - private void sendCommand(String command, String argument) - throws NativeDaemonConnectorException { - synchronized (this) { - if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); - if (mOutputStream == null) { - Slog.e(TAG, "No connection to daemon", new IllegalStateException()); - throw new NativeDaemonConnectorException("No output stream!"); - } else { - StringBuilder builder = new StringBuilder(command); - if (argument != null) { - builder.append(argument); - } - builder.append('\0'); + private void sendCommandLocked(String command, String argument) + throws NativeDaemonConnectorException { + if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); + if (mOutputStream == null) { + Slog.e(TAG, "No connection to daemon", new IllegalStateException()); + throw new NativeDaemonConnectorException("No output stream!"); + } else { + StringBuilder builder = new StringBuilder(command); + if (argument != null) { + builder.append(argument); + } + builder.append('\0'); - try { - mOutputStream.write(builder.toString().getBytes()); - } catch (IOException ex) { - Slog.e(TAG, "IOException in sendCommand", ex); - } + try { + mOutputStream.write(builder.toString().getBytes()); + } catch (IOException ex) { + Slog.e(TAG, "IOException in sendCommand", ex); } } } @@ -235,10 +229,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { /** * Issue a command to the native daemon and return the responses */ - public synchronized ArrayList doCommand(String cmd) - throws NativeDaemonConnectorException { + public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { + synchronized (mDaemonLock) { + return doCommandLocked(cmd); + } + } + + private ArrayList doCommandLocked(String cmd) throws NativeDaemonConnectorException { mResponseQueue.clear(); - sendCommand(cmd); + sendCommandLocked(cmd); ArrayList response = new ArrayList(); boolean complete = false; @@ -278,7 +277,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { return response; } - /* + /** * Issues a list command and returns the cooked list */ public String[] doListCommand(String cmd, int expectedResponseCode) @@ -317,4 +316,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { } throw new NativeDaemonConnectorException("Got an empty response"); } + + /** {@inheritDoc} */ + public void monitor() { + synchronized (mDaemonLock) { } + } } From 806d1fdf9ac9f6286bd1764fd99f33bb88e48abd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 10 Aug 2011 17:53:27 -0700 Subject: [PATCH 0074/1150] Foreground/background network stats using sets. Teach NetworkStats about "counter sets" coming from kernel, and use them to track usage in foreground/background. Add AID_NET_BW_ACCT to system_server so it can control counter sets. Move to composite key of NetworkIdentitySet, UID, set, and tag when recording historical usage. Persisting still clusters by identity, since that is heaviest object. Request async stats poll during systemReady() to bootstrap later delta calculations. Reset kernel counters when UID removed. Update various tests. Bug: 5105592, 5146067 Change-Id: Idabec9e3ffcaf212879821515602ecde0a03de8c --- .../android/net/INetworkStatsService.aidl | 4 +- core/java/android/net/NetworkStats.java | 94 +++-- .../java/android/net/NetworkStatsHistory.java | 9 +- core/java/android/net/TrafficStats.java | 4 - .../server/net/NetworkStatsService.java | 342 +++++++++++------- 5 files changed, 284 insertions(+), 169 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b65506c411..0e883cf8ac 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -26,7 +26,7 @@ interface INetworkStatsService { /** Return historical network layer stats for traffic that matches template. */ NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); /** Return historical network layer stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int tag, int fields); + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); /** Return network layer usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); @@ -38,6 +38,8 @@ interface INetworkStatsService { /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); + /** Mark given UID as being in foreground for stats purposes. */ + void setUidForeground(int uid, boolean uidForeground); /** Force update of statistics. */ void forceUpdate(); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f2fcb8fad8..272545d0dc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -42,7 +42,13 @@ public class NetworkStats implements Parcelable { public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; - /** {@link #tag} value for without tag. */ + /** {@link #set} value when all sets combined. */ + public static final int SET_ALL = -1; + /** {@link #set} value where background data is accounted. */ + public static final int SET_DEFAULT = 0; + /** {@link #set} value where foreground data is accounted. */ + public static final int SET_FOREGROUND = 1; + /** {@link #tag} value for total data across all tags. */ public static final int TAG_NONE = 0; /** @@ -53,6 +59,7 @@ public class NetworkStats implements Parcelable { private int size; private String[] iface; private int[] uid; + private int[] set; private int[] tag; private long[] rxBytes; private long[] rxPackets; @@ -63,6 +70,7 @@ public class NetworkStats implements Parcelable { public static class Entry { public String iface; public int uid; + public int set; public int tag; public long rxBytes; public long rxPackets; @@ -71,17 +79,19 @@ public class NetworkStats implements Parcelable { public long operations; public Entry() { - this(IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); + this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, operations); + this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, + operations); } - public Entry(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; + this.set = set; this.tag = tag; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -96,6 +106,7 @@ public class NetworkStats implements Parcelable { this.size = 0; this.iface = new String[initialSize]; this.uid = new int[initialSize]; + this.set = new int[initialSize]; this.tag = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -109,6 +120,7 @@ public class NetworkStats implements Parcelable { size = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); + set = parcel.createIntArray(); tag = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -123,6 +135,7 @@ public class NetworkStats implements Parcelable { dest.writeInt(size); dest.writeStringArray(iface); dest.writeIntArray(uid); + dest.writeIntArray(set); dest.writeIntArray(tag); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -131,15 +144,18 @@ public class NetworkStats implements Parcelable { dest.writeLongArray(operations); } - public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets) { - return addValues(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, 0L); + // @VisibleForTesting + public NetworkStats addIfaceValues( + String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { + return addValues( + iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } - public NetworkStats addValues(String iface, int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - return addValues( - new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); + // @VisibleForTesting + public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes, + long rxPackets, long txBytes, long txPackets, long operations) { + return addValues(new Entry( + iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @@ -151,6 +167,7 @@ public class NetworkStats implements Parcelable { final int newLength = Math.max(iface.length, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); uid = Arrays.copyOf(uid, newLength); + set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -161,6 +178,7 @@ public class NetworkStats implements Parcelable { iface[size] = entry.iface; uid[size] = entry.uid; + set[size] = entry.set; tag[size] = entry.tag; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -179,6 +197,7 @@ public class NetworkStats implements Parcelable { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = iface[i]; entry.uid = uid[i]; + entry.set = set[i]; entry.tag = tag[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -201,19 +220,26 @@ public class NetworkStats implements Parcelable { return iface.length; } + @Deprecated public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return combineValues( - new Entry(iface, uid, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations); + } + + public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes, + long rxPackets, long txBytes, long txPackets, long operations) { + return combineValues(new Entry( + iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** * Combine given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int)} is unable to find match. Can also be - * used to subtract values from existing rows. + * {@link #findIndex(String, int, int, int)} is unable to find match. Can + * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.tag); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -230,9 +256,10 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int tag) { + public int findIndex(String iface, int uid, int set, int tag) { for (int i = 0; i < size; i++) { - if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && tag == this.tag[i]) { + if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && set == this.set[i] + && tag == this.tag[i]) { return i; } } @@ -246,7 +273,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(IFACE_ALL, uid[i], tag[i]); + final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]); if (j == -1) { operations[i] = 0; } else { @@ -332,10 +359,11 @@ public class NetworkStats implements Parcelable { for (int i = 0; i < size; i++) { entry.iface = iface[i]; entry.uid = uid[i]; + entry.set = set[i]; entry.tag = tag[i]; // find remote row that matches, and subtract - final int j = value.findIndex(entry.iface, entry.uid, entry.tag); + final int j = value.findIndex(entry.iface, entry.uid, entry.set, entry.tag); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = rxBytes[i]; @@ -377,7 +405,8 @@ public class NetworkStats implements Parcelable { pw.print(prefix); pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); - pw.print(" tag=0x"); pw.print(Integer.toHexString(tag[i])); + pw.print(" set="); pw.print(setToString(set[i])); + pw.print(" tag="); pw.print(tagToString(tag[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); pw.print(" txBytes="); pw.print(txBytes[i]); @@ -386,6 +415,29 @@ public class NetworkStats implements Parcelable { } } + /** + * Return text description of {@link #set} value. + */ + public static String setToString(int set) { + switch (set) { + case SET_ALL: + return "ALL"; + case SET_DEFAULT: + return "DEFAULT"; + case SET_FOREGROUND: + return "FOREGROUND"; + default: + return "UNKNOWN"; + } + } + + /** + * Return text description of {@link #tag} value. + */ + public static String tagToString(int tag) { + return "0x" + Integer.toHexString(tag); + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 4ba44cac29..b4f15acff1 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -17,6 +17,7 @@ package android.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.DataStreamUtils.readFullLongArray; @@ -215,8 +216,8 @@ public class NetworkStatsHistory implements Parcelable { */ @Deprecated public void recordData(long start, long end, long rxBytes, long txBytes) { - recordData(start, end, - new NetworkStats.Entry(IFACE_ALL, UID_ALL, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); + recordData(start, end, new NetworkStats.Entry( + IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, 0L, txBytes, 0L, 0L)); } /** @@ -269,7 +270,7 @@ public class NetworkStatsHistory implements Parcelable { */ public void recordEntireHistory(NetworkStatsHistory input) { final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); + IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); for (int i = 0; i < input.bucketCount; i++) { final long start = input.bucketStart[i]; final long end = start + input.bucketDuration; @@ -422,7 +423,7 @@ public class NetworkStatsHistory implements Parcelable { ensureBuckets(start, end); final NetworkStats.Entry entry = new NetworkStats.Entry( - IFACE_ALL, UID_ALL, TAG_NONE, 0L, 0L, 0L, 0L, 0L); + IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); final Random r = new Random(); while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 || operations > 32) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index f138e49140..c2c5c183d3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -205,10 +205,6 @@ public class TrafficStats { * @param operationCount Number of operations to increment count by. */ public static void incrementOperationCount(int tag, int operationCount) { - if (operationCount < 0) { - throw new IllegalArgumentException("operation count can only be incremented"); - } - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index deca7a91cf..c911687ab7 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,9 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.SET_ALL; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; @@ -40,6 +43,8 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; +import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.app.AlarmManager; import android.app.IAlarmManager; @@ -63,17 +68,20 @@ import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; import android.os.INetworkManagementService; +import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; -import android.util.LongSparseArray; import android.util.NtpTrustedTime; import android.util.Slog; +import android.util.SparseIntArray; import android.util.TrustedTime; import com.android.internal.os.AtomicFile; +import com.android.internal.util.Objects; +import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -88,6 +96,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -109,6 +119,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_INIT = 1; private static final int VERSION_UID_WITH_IDENT = 2; private static final int VERSION_UID_WITH_TAG = 3; + private static final int VERSION_UID_WITH_SET = 4; + + private static final int MSG_FORCE_UPDATE = 0x1; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -156,8 +169,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of historical network layer stats for known networks. */ private HashMap mNetworkStats = Maps.newHashMap(); /** Set of historical network layer stats for known UIDs. */ - private HashMap> mUidStats = - Maps.newHashMap(); + private HashMap mUidStats = Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; @@ -167,6 +179,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats mLastUidSnapshot; + /** Current counter sets for each UID. */ + private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); + /** Data layer operation counters for splicing into other structures. */ private NetworkStats mOperations = new NetworkStats(0L, 10); private NetworkStats mLastOperationsSnapshot; @@ -177,11 +192,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final AtomicFile mNetworkFile; private final AtomicFile mUidFile; - // TODO: collect detailed uid stats, storing tag-granularity data until next - // dropbox, and uid summary for a specific bucket count. - - // TODO: periodically compile statistics and send to dropbox. - public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), @@ -207,7 +217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerThread = new HandlerThread(TAG); mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper()); + mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin")); mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin")); @@ -246,6 +256,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { Slog.w(TAG, "unable to register poll alarm"); } + + // kick off background poll to bootstrap deltas + mHandler.obtainMessage(MSG_FORCE_UPDATE).sendToTarget(); } private void shutdownLocked() { @@ -302,24 +315,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( - NetworkTemplate template, int uid, int tag, int fields) { + NetworkTemplate template, int uid, int set, int tag, int fields) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); synchronized (mStatsLock) { ensureUidStatsLoadedLocked(); - final long packed = packUidAndTag(uid, tag); // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getUidBucketDuration(), estimateUidBuckets(), fields); - for (NetworkIdentitySet ident : mUidStats.keySet()) { - if (templateMatches(template, ident)) { - final NetworkStatsHistory history = mUidStats.get(ident).get(packed); - if (history != null) { - combined.recordEntireHistory(history); - } + for (UidStatsKey key : mUidStats.keySet()) { + final boolean setMatches = set == SET_ALL || key.set == set; + if (templateMatches(template, key.ident) && key.uid == uid && setMatches + && key.tag == tag) { + final NetworkStatsHistory history = mUidStats.get(key); + combined.recordEntireHistory(history); } } + return combined; } } @@ -371,33 +384,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; - for (NetworkIdentitySet ident : mUidStats.keySet()) { - if (templateMatches(template, ident)) { - final LongSparseArray uidStats = mUidStats.get(ident); - for (int i = 0; i < uidStats.size(); i++) { - final long packed = uidStats.keyAt(i); - final int uid = unpackUid(packed); - final int tag = unpackTag(packed); + for (UidStatsKey key : mUidStats.keySet()) { + if (templateMatches(template, key.ident)) { + // always include summary under TAG_NONE, and include + // other tags when requested. + if (key.tag == TAG_NONE || includeTags) { + final NetworkStatsHistory history = mUidStats.get(key); + historyEntry = history.getValues(start, end, now, historyEntry); - // always include summary under TAG_NONE, and include - // other tags when requested. - if (tag == TAG_NONE || includeTags) { - final NetworkStatsHistory history = uidStats.valueAt(i); - historyEntry = history.getValues(start, end, now, historyEntry); + entry.iface = IFACE_ALL; + entry.uid = key.uid; + entry.set = key.set; + entry.tag = key.tag; + entry.rxBytes = historyEntry.rxBytes; + entry.rxPackets = historyEntry.rxPackets; + entry.txBytes = historyEntry.txBytes; + entry.txPackets = historyEntry.txPackets; + entry.operations = historyEntry.operations; - entry.iface = IFACE_ALL; - entry.uid = uid; - entry.tag = tag; - entry.rxBytes = historyEntry.rxBytes; - entry.rxPackets = historyEntry.rxPackets; - entry.txBytes = historyEntry.txBytes; - entry.txPackets = historyEntry.txPackets; - entry.operations = historyEntry.operations; - - if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 - || entry.txPackets > 0 || entry.operations > 0) { - stats.combineValues(entry); - } + if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 + || entry.txPackets > 0 || entry.operations > 0) { + stats.combineValues(entry); } } } @@ -437,8 +444,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); } + if (operationCount < 0) { + throw new IllegalArgumentException("operation count can only be incremented"); + } + if (tag == TAG_NONE) { + throw new IllegalArgumentException("operation count must have specific tag"); + } + synchronized (mStatsLock) { - mOperations.combineValues(IFACE_ALL, uid, tag, 0L, 0L, 0L, 0L, operationCount); + final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT); + mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); + mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); + } + } + + @Override + public void setUidForeground(int uid, boolean uidForeground) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + + synchronized (mStatsLock) { + final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; + final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); + if (oldSet != set) { + mActiveUidCounterSet.put(uid, set); + setKernelCounterSet(uid, set); + } } } @@ -601,7 +631,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStats.Entry entry = null; for (String iface : persistDelta.getUniqueIfaces()) { - final int index = persistDelta.findIndex(iface, UID_ALL, TAG_NONE); + final int index = persistDelta.findIndex(iface, UID_ALL, SET_DEFAULT, TAG_NONE); entry = persistDelta.getValues(index, entry); if (forcePersist || entry.rxBytes > persistThreshold || entry.txBytes > persistThreshold) { @@ -676,31 +706,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // splice in operation counts since last poll - final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.tag); + final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag); if (j != -1) { operationsEntry = operationsDelta.getValues(j, operationsEntry); entry.operations = operationsEntry.operations; } final NetworkStatsHistory history = findOrCreateUidStatsLocked( - ident, entry.uid, entry.tag); + ident, entry.uid, entry.set, entry.tag); history.recordData(timeStart, currentTime, entry); } // trim any history beyond max final long maxUidHistory = mSettings.getUidMaxHistory(); final long maxTagHistory = mSettings.getTagMaxHistory(); - for (LongSparseArray uidStats : mUidStats.values()) { - for (int i = 0; i < uidStats.size(); i++) { - final long packed = uidStats.keyAt(i); - final NetworkStatsHistory history = uidStats.valueAt(i); + for (UidStatsKey key : mUidStats.keySet()) { + final NetworkStatsHistory history = mUidStats.get(key); - // detailed tags are trimmed sooner than summary in TAG_NONE - if (unpackTag(packed) == TAG_NONE) { - history.removeBucketsBefore(currentTime - maxUidHistory); - } else { - history.removeBucketsBefore(currentTime - maxTagHistory); - } + // detailed tags are trimmed sooner than summary in TAG_NONE + if (key.tag == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); } } @@ -715,26 +742,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void removeUidLocked(int uid) { ensureUidStatsLoadedLocked(); + final ArrayList knownKeys = Lists.newArrayList(); + knownKeys.addAll(mUidStats.keySet()); + // migrate all UID stats into special "removed" bucket - for (NetworkIdentitySet ident : mUidStats.keySet()) { - final LongSparseArray uidStats = mUidStats.get(ident); - for (int i = 0; i < uidStats.size(); i++) { - final long packed = uidStats.keyAt(i); - if (unpackUid(packed) == uid) { - // only migrate combined TAG_NONE history - if (unpackTag(packed) == TAG_NONE) { - final NetworkStatsHistory uidHistory = uidStats.valueAt(i); - final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( - ident, UID_REMOVED, TAG_NONE); - removedHistory.recordEntireHistory(uidHistory); - } - uidStats.remove(packed); + for (UidStatsKey key : knownKeys) { + if (key.uid == uid) { + // only migrate combined TAG_NONE history + if (key.tag == TAG_NONE) { + final NetworkStatsHistory uidHistory = mUidStats.get(key); + final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( + key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); + removedHistory.recordEntireHistory(uidHistory); } + mUidStats.remove(key); } } - // TODO: push kernel event to wipe stats for UID, otherwise we risk - // picking them up again during next poll. + // clear kernel stats associated with UID + resetKernelUidStats(uid); // since this was radical rewrite, push to disk writeUidStatsLocked(); @@ -763,17 +789,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private NetworkStatsHistory findOrCreateUidStatsLocked( - NetworkIdentitySet ident, int uid, int tag) { + NetworkIdentitySet ident, int uid, int set, int tag) { ensureUidStatsLoadedLocked(); - LongSparseArray uidStats = mUidStats.get(ident); - if (uidStats == null) { - uidStats = new LongSparseArray(); - mUidStats.put(ident, uidStats); - } - - final long packed = packUidAndTag(uid, tag); - final NetworkStatsHistory existing = uidStats.get(packed); + final UidStatsKey key = new UidStatsKey(ident, uid, set, tag); + final NetworkStatsHistory existing = mUidStats.get(key); // update when no existing, or when bucket duration changed final long bucketDuration = mSettings.getUidBucketDuration(); @@ -787,7 +807,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - uidStats.put(packed, updated); + mUidStats.put(key, updated); return updated; } else { return existing; @@ -874,25 +894,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // for a short time. break; } - case VERSION_UID_WITH_TAG: { - // uid := size *(NetworkIdentitySet size *(UID tag NetworkStatsHistory)) - final int ifaceSize = in.readInt(); - for (int i = 0; i < ifaceSize; i++) { + case VERSION_UID_WITH_TAG: + case VERSION_UID_WITH_SET: { + // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) + final int identSize = in.readInt(); + for (int i = 0; i < identSize; i++) { final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final int childSize = in.readInt(); - final LongSparseArray uidStats = new LongSparseArray< - NetworkStatsHistory>(childSize); - for (int j = 0; j < childSize; j++) { + final int size = in.readInt(); + for (int j = 0; j < size; j++) { final int uid = in.readInt(); + final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() + : SET_DEFAULT; final int tag = in.readInt(); - final long packed = packUidAndTag(uid, tag); + final UidStatsKey key = new UidStatsKey(ident, uid, set, tag); final NetworkStatsHistory history = new NetworkStatsHistory(in); - uidStats.put(packed, history); + mUidStats.put(key, history); } - - mUidStats.put(ident, uidStats); } break; } @@ -949,29 +968,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // build UidStatsKey lists grouped by ident + final HashMap> keysByIdent = Maps.newHashMap(); + for (UidStatsKey key : mUidStats.keySet()) { + ArrayList keys = keysByIdent.get(key.ident); + if (keys == null) { + keys = Lists.newArrayList(); + keysByIdent.put(key.ident, keys); + } + keys.add(key); + } + FileOutputStream fos = null; try { fos = mUidFile.startWrite(); final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UID_WITH_TAG); + out.writeInt(VERSION_UID_WITH_SET); - final int size = mUidStats.size(); - out.writeInt(size); - for (NetworkIdentitySet ident : mUidStats.keySet()) { - final LongSparseArray uidStats = mUidStats.get(ident); + out.writeInt(keysByIdent.size()); + for (NetworkIdentitySet ident : keysByIdent.keySet()) { + final ArrayList keys = keysByIdent.get(ident); ident.writeToStream(out); - final int childSize = uidStats.size(); - out.writeInt(childSize); - for (int i = 0; i < childSize; i++) { - final long packed = uidStats.keyAt(i); - final int uid = unpackUid(packed); - final int tag = unpackTag(packed); - final NetworkStatsHistory history = uidStats.valueAt(i); - out.writeInt(uid); - out.writeInt(tag); + out.writeInt(keys.size()); + for (UidStatsKey key : keys) { + final NetworkStatsHistory history = mUidStats.get(key); + out.writeInt(key.uid); + out.writeInt(key.set); + out.writeInt(key.tag); history.writeToStream(out); } } @@ -1030,20 +1056,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // from disk if not already in memory. ensureUidStatsLoadedLocked(); - pw.println("Detailed UID stats:"); - for (NetworkIdentitySet ident : mUidStats.keySet()) { - pw.print(" ident="); pw.println(ident.toString()); + final ArrayList keys = Lists.newArrayList(); + keys.addAll(mUidStats.keySet()); + Collections.sort(keys); - final LongSparseArray uidStats = mUidStats.get(ident); - for (int i = 0; i < uidStats.size(); i++) { - final long packed = uidStats.keyAt(i); - final int uid = unpackUid(packed); - final int tag = unpackTag(packed); - final NetworkStatsHistory history = uidStats.valueAt(i); - pw.print(" UID="); pw.print(uid); - pw.print(" tag=0x"); pw.println(Integer.toHexString(tag)); - history.dump(" ", pw, fullHistory); - } + pw.println("Detailed UID stats:"); + for (UidStatsKey key : keys) { + pw.print(" ident="); pw.print(key.ident.toString()); + pw.print(" uid="); pw.print(key.uid); + pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); + pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); + + final NetworkStatsHistory history = mUidStats.get(key); + history.dump(" ", pw, fullHistory); } } } @@ -1080,8 +1105,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (ApplicationInfo info : installedApps) { final int uid = info.uid; - findOrCreateUidStatsLocked(ident, uid, TAG_NONE).generateRandom(UID_START, UID_END, - UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, UID_TX_PACKETS, UID_OPERATIONS); + findOrCreateUidStatsLocked(ident, uid, SET_DEFAULT, TAG_NONE).generateRandom( + UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, + UID_TX_PACKETS, UID_OPERATIONS); + findOrCreateUidStatsLocked(ident, uid, SET_FOREGROUND, TAG_NONE).generateRandom( + UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, + UID_TX_PACKETS, UID_OPERATIONS); } } } @@ -1116,23 +1145,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration); } - // @VisibleForTesting - public static long packUidAndTag(int uid, int tag) { - final long uidLong = uid; - final long tagLong = tag; - return (uidLong << 32) | (tagLong & 0xFFFFFFFFL); - } - - // @VisibleForTesting - public static int unpackUid(long packed) { - return (int) (packed >> 32); - } - - // @VisibleForTesting - public static int unpackTag(long packed) { - return (int) (packed & 0xFFFFFFFFL); - } - /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. @@ -1146,6 +1158,58 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return false; } + private Handler.Callback mHandlerCallback = new Handler.Callback() { + /** {@inheritDoc} */ + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_FORCE_UPDATE: { + forceUpdate(); + return true; + } + default: { + return false; + } + } + } + }; + + /** + * Key uniquely identifying a {@link NetworkStatsHistory} for a UID. + */ + private static class UidStatsKey implements Comparable { + public final NetworkIdentitySet ident; + public final int uid; + public final int set; + public final int tag; + + public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) { + this.ident = ident; + this.uid = uid; + this.set = set; + this.tag = tag; + } + + @Override + public int hashCode() { + return Objects.hashCode(ident, uid, set, tag); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof UidStatsKey) { + final UidStatsKey key = (UidStatsKey) obj; + return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set + && tag == key.tag; + } + return false; + } + + /** {@inheritDoc} */ + public int compareTo(UidStatsKey another) { + return Integer.compare(uid, another.uid); + } + } + /** * Default external settings that read from {@link Settings.Secure}. */ From 93db9450912b643242c17096c092514aac4be0f2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 23 Aug 2011 18:37:23 -0700 Subject: [PATCH 0075/1150] Register for kernel global data usage alerts. Instead of polling every 15 minutes, register for alerts that trigger when system-wide traffic passes a threshold. Still mixed with polling to persist UID stats, but relaxed to 30 minutes. Currently watches for every 512kB. Make persistence decision separately for network versus UID, and use total delta bytes when making decision. Use light bootstrap during systemReady() instead of heavy poll, which had been force-loading all UID data unnecessarily. Bug: 5023631 Change-Id: I04b723d6c4bf872fb1028071122dba66a8e1b576 --- core/java/android/net/NetworkStats.java | 16 ++ .../server/net/NetworkStatsService.java | 192 ++++++++++++------ 2 files changed, 150 insertions(+), 58 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 272545d0dc..5b883a0741 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -312,6 +312,22 @@ public class NetworkStats implements Parcelable { return result; } + /** + * Return total bytes represented by this snapshot object, usually used when + * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. + */ + public long getTotalBytes() { + long totalBytes = 0; + for (int i = 0; i < size; i++) { + // skip specific tags, since already counted in TAG_NONE + if (tag[i] != TAG_NONE) continue; + + totalBytes += rxBytes[i]; + totalBytes += txBytes[i]; + } + return totalBytes; + } + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index c911687ab7..80ae9bc6cb 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -43,6 +43,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; @@ -56,6 +57,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.net.IConnectivityManager; +import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkInfo; @@ -121,7 +123,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_TAG = 3; private static final int VERSION_UID_WITH_SET = 4; - private static final int MSG_FORCE_UPDATE = 0x1; + private static final int MSG_PERFORM_POLL = 0x1; + private static final int MSG_PERFORM_POLL_DETAILED = 0x2; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -141,7 +144,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; - // TODO: listen for kernel push events through netd instead of polling // TODO: trim empty history objects entirely private static final long KB_IN_BYTES = 1024; @@ -174,17 +176,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; - private NetworkStats mLastNetworkSnapshot; - private NetworkStats mLastPersistNetworkSnapshot; + private NetworkStats mLastPollNetworkSnapshot; + private NetworkStats mLastPollUidSnapshot; + private NetworkStats mLastPollOperationsSnapshot; - private NetworkStats mLastUidSnapshot; + private NetworkStats mLastPersistNetworkSnapshot; + private NetworkStats mLastPersistUidSnapshot; /** Current counter sets for each UID. */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); /** Data layer operation counters for splicing into other structures. */ private NetworkStats mOperations = new NetworkStats(0L, 10); - private NetworkStats mLastOperationsSnapshot; private final HandlerThread mHandlerThread; private final Handler mHandler; @@ -252,13 +255,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.registerReceiver(mShutdownReceiver, shutdownFilter); try { - registerPollAlarmLocked(); + mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { - Slog.w(TAG, "unable to register poll alarm"); + // ouch, no push updates means we fall back to + // ACTION_NETWORK_STATS_POLL intervals. + Slog.e(TAG, "unable to register INetworkManagementEventObserver", e); } - // kick off background poll to bootstrap deltas - mHandler.obtainMessage(MSG_FORCE_UPDATE).sendToTarget(); + registerPollAlarmLocked(); + registerGlobalAlert(); + + // bootstrap initial stats to prevent double-counting later + bootstrapStats(); } private void shutdownLocked() { @@ -280,17 +288,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ - private void registerPollAlarmLocked() throws RemoteException { - if (mPollIntent != null) { - mAlarmManager.remove(mPollIntent); + private void registerPollAlarmLocked() { + try { + if (mPollIntent != null) { + mAlarmManager.remove(mPollIntent); + } + + mPollIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, + mSettings.getPollInterval(), mPollIntent); + } catch (RemoteException e) { + Slog.w(TAG, "problem registering for poll alarm: " + e); } + } - mPollIntent = PendingIntent.getBroadcast( - mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); - - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), mPollIntent); + /** + * Register for a global alert that is delivered through + * {@link INetworkManagementEventObserver} once a threshold amount of data + * has been transferred. + */ + private void registerGlobalAlert() { + try { + final long alertBytes = mSettings.getPersistThreshold(); + mNetworkManager.setGlobalAlert(alertBytes); + } catch (IllegalStateException e) { + Slog.w(TAG, "problem registering for global alert: " + e); + } catch (RemoteException e) { + Slog.w(TAG, "problem registering for global alert: " + e); + } } @Override @@ -475,10 +503,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - - synchronized (mStatsLock) { - performPollLocked(true, false); - } + performPoll(true, false); } /** @@ -507,14 +532,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - performPollLocked(true, false); - } finally { - mWakeLock.release(); - } - } + performPoll(true, false); + + // verify that we're watching global alert + registerGlobalAlert(); } }; @@ -546,6 +567,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Observer that watches for {@link INetworkManagementService} alerts. + */ + private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() { + @Override + public void limitReached(String limitName, String iface) { + // only someone like NMS should be calling us + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + + if (LIMIT_GLOBAL_ALERT.equals(limitName)) { + // kick off background poll to collect network stats; UID stats + // are handled during normal polling interval. + mHandler.obtainMessage(MSG_PERFORM_POLL).sendToTarget(); + + // re-arm global alert for next update + registerGlobalAlert(); + } + } + }; + /** * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} @@ -587,6 +628,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + /** + * Bootstrap initial stats snapshot, usually during {@link #systemReady()} + * so we have baseline values without double-counting. + */ + private void bootstrapStats() { + try { + mLastPollNetworkSnapshot = mNetworkManager.getNetworkStatsSummary(); + mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + mLastPollOperationsSnapshot = new NetworkStats(0L, 0); + } catch (IllegalStateException e) { + Slog.w(TAG, "problem reading network stats: " + e); + } catch (RemoteException e) { + Slog.w(TAG, "problem reading network stats: " + e); + } + } + + private void performPoll(boolean detailedPoll, boolean forcePersist) { + synchronized (mStatsLock) { + mWakeLock.acquire(); + try { + performPollLocked(detailedPoll, forcePersist); + } finally { + mWakeLock.release(); + } + } + } + /** * Periodic poll operation, reading current statistics and recording into * {@link NetworkStatsHistory}. @@ -596,6 +664,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void performPollLocked(boolean detailedPoll, boolean forcePersist) { if (LOGV) Slog.v(TAG, "performPollLocked()"); + final long startRealtime = SystemClock.elapsedRealtime(); // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { @@ -605,6 +674,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + final long persistThreshold = mSettings.getPersistThreshold(); final NetworkStats networkSnapshot; final NetworkStats uidSnapshot; @@ -620,30 +690,32 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } performNetworkPollLocked(networkSnapshot, currentTime); - if (detailedPoll) { - performUidPollLocked(uidSnapshot, currentTime); + + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + if (forcePersist || persistNetworkDelta.getTotalBytes() > persistThreshold) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; } - // decide if enough has changed to trigger persist - final NetworkStats persistDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final long persistThreshold = mSettings.getPersistThreshold(); + if (detailedPoll) { + performUidPollLocked(uidSnapshot, currentTime); - NetworkStats.Entry entry = null; - for (String iface : persistDelta.getUniqueIfaces()) { - final int index = persistDelta.findIndex(iface, UID_ALL, SET_DEFAULT, TAG_NONE); - entry = persistDelta.getValues(index, entry); - if (forcePersist || entry.rxBytes > persistThreshold - || entry.txBytes > persistThreshold) { - writeNetworkStatsLocked(); - if (mUidStatsLoaded) { - writeUidStatsLocked(); - } + // persist when enough network data has occurred + final NetworkStats persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true); + if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) { + writeUidStatsLocked(); mLastPersistNetworkSnapshot = networkSnapshot; - break; } } + if (LOGV) { + final long duration = SystemClock.elapsedRealtime() - startRealtime; + Slog.v(TAG, "performPollLocked() took " + duration + "ms"); + } + // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -656,7 +728,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { final HashSet unknownIface = Sets.newHashSet(); - final NetworkStats delta = computeStatsDelta(mLastNetworkSnapshot, networkSnapshot, false); + final NetworkStats delta = computeStatsDelta(mLastPollNetworkSnapshot, networkSnapshot, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -678,7 +750,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.removeBucketsBefore(currentTime - maxHistory); } - mLastNetworkSnapshot = networkSnapshot; + mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); @@ -691,9 +763,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastUidSnapshot, uidSnapshot, false); + final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false); final NetworkStats operationsDelta = computeStatsDelta( - mLastOperationsSnapshot, mOperations, false); + mLastPollOperationsSnapshot, mOperations, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -731,8 +803,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - mLastUidSnapshot = uidSnapshot; - mLastOperationsSnapshot = mOperations; + mLastPollUidSnapshot = uidSnapshot; + mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); } @@ -1162,8 +1234,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** {@inheritDoc} */ public boolean handleMessage(Message msg) { switch (msg.what) { - case MSG_FORCE_UPDATE: { - forceUpdate(); + case MSG_PERFORM_POLL: { + performPoll(false, false); + return true; + } + case MSG_PERFORM_POLL_DETAILED: { + performPoll(true, false); return true; } default: { @@ -1226,10 +1302,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public long getPollInterval() { - return getSecureLong(NETSTATS_POLL_INTERVAL, 15 * MINUTE_IN_MILLIS); + return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } public long getPersistThreshold() { - return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 16 * KB_IN_BYTES); + return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 512 * KB_IN_BYTES); } public long getNetworkBucketDuration() { return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); From 60ca02379f4f3f29edfe3a2b6e1f92766c234a7f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 24 Aug 2011 15:42:09 -0700 Subject: [PATCH 0076/1150] Data usage buckets active time, parsing ISE. When recording data usage, measure the actual active time, since buckets can be quite long. Offer incrementOperationCount() version that reads thread stats tag for caller. Rethrow any NPE as ISE during stats parsing, which callers already handle. Bug: 5171812, 5184508, 5180659 Change-Id: I6da80ccc0162be68bee279529e3a23b6f98ebd87 --- .../java/android/net/NetworkStatsHistory.java | 40 ++++++++++++++----- core/java/android/net/TrafficStats.java | 12 ++++++ 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index b4f15acff1..b19949e39d 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -53,18 +53,21 @@ import java.util.Random; public class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_PACKETS = 2; + private static final int VERSION_ADD_ACTIVE = 3; - public static final int FIELD_RX_BYTES = 0x01; - public static final int FIELD_RX_PACKETS = 0x02; - public static final int FIELD_TX_BYTES = 0x04; - public static final int FIELD_TX_PACKETS = 0x08; - public static final int FIELD_OPERATIONS = 0x10; + public static final int FIELD_ACTIVE_TIME = 0x01; + public static final int FIELD_RX_BYTES = 0x02; + public static final int FIELD_RX_PACKETS = 0x04; + public static final int FIELD_TX_BYTES = 0x08; + public static final int FIELD_TX_PACKETS = 0x10; + public static final int FIELD_OPERATIONS = 0x20; public static final int FIELD_ALL = 0xFFFFFFFF; private long bucketDuration; private int bucketCount; private long[] bucketStart; + private long[] activeTime; private long[] rxBytes; private long[] rxPackets; private long[] txBytes; @@ -74,8 +77,9 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - public long bucketStart; public long bucketDuration; + public long bucketStart; + public long activeTime; public long rxBytes; public long rxPackets; public long txBytes; @@ -94,6 +98,7 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { this.bucketDuration = bucketDuration; bucketStart = new long[initialSize]; + if ((fields & FIELD_ACTIVE_TIME) != 0) activeTime = new long[initialSize]; if ((fields & FIELD_RX_BYTES) != 0) rxBytes = new long[initialSize]; if ((fields & FIELD_RX_PACKETS) != 0) rxPackets = new long[initialSize]; if ((fields & FIELD_TX_BYTES) != 0) txBytes = new long[initialSize]; @@ -105,6 +110,7 @@ public class NetworkStatsHistory implements Parcelable { public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); + activeTime = readLongArray(in); rxBytes = readLongArray(in); rxPackets = readLongArray(in); txBytes = readLongArray(in); @@ -117,6 +123,7 @@ public class NetworkStatsHistory implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); + writeLongArray(out, activeTime, bucketCount); writeLongArray(out, rxBytes, bucketCount); writeLongArray(out, rxPackets, bucketCount); writeLongArray(out, txBytes, bucketCount); @@ -138,9 +145,12 @@ public class NetworkStatsHistory implements Parcelable { bucketCount = bucketStart.length; break; } - case VERSION_ADD_PACKETS: { + case VERSION_ADD_PACKETS: + case VERSION_ADD_ACTIVE: { bucketDuration = in.readLong(); bucketStart = readVarLongArray(in); + activeTime = (version >= VERSION_ADD_ACTIVE) ? readVarLongArray(in) + : new long[bucketStart.length]; rxBytes = readVarLongArray(in); rxPackets = readVarLongArray(in); txBytes = readVarLongArray(in); @@ -156,9 +166,10 @@ public class NetworkStatsHistory implements Parcelable { } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_PACKETS); + out.writeInt(VERSION_ADD_ACTIVE); out.writeLong(bucketDuration); writeVarLongArray(out, bucketStart, bucketCount); + writeVarLongArray(out, activeTime, bucketCount); writeVarLongArray(out, rxBytes, bucketCount); writeVarLongArray(out, rxPackets, bucketCount); writeVarLongArray(out, txBytes, bucketCount); @@ -202,6 +213,7 @@ public class NetworkStatsHistory implements Parcelable { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; entry.bucketDuration = bucketDuration; + entry.activeTime = getLong(activeTime, i, UNKNOWN); entry.rxBytes = getLong(rxBytes, i, UNKNOWN); entry.rxPackets = getLong(rxPackets, i, UNKNOWN); entry.txBytes = getLong(txBytes, i, UNKNOWN); @@ -252,8 +264,9 @@ public class NetworkStatsHistory implements Parcelable { final long fracRxPackets = entry.rxPackets * overlap / duration; final long fracTxBytes = entry.txBytes * overlap / duration; final long fracTxPackets = entry.txPackets * overlap / duration; - final int fracOperations = (int) (entry.operations * overlap / duration); + final long fracOperations = entry.operations * overlap / duration; + addLong(activeTime, i, overlap); addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes; addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets; addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes; @@ -311,6 +324,7 @@ public class NetworkStatsHistory implements Parcelable { if (bucketCount >= bucketStart.length) { final int newLength = Math.max(bucketStart.length, 10) * 3 / 2; bucketStart = Arrays.copyOf(bucketStart, newLength); + if (activeTime != null) activeTime = Arrays.copyOf(activeTime, newLength); if (rxBytes != null) rxBytes = Arrays.copyOf(rxBytes, newLength); if (rxPackets != null) rxPackets = Arrays.copyOf(rxPackets, newLength); if (txBytes != null) txBytes = Arrays.copyOf(txBytes, newLength); @@ -324,6 +338,7 @@ public class NetworkStatsHistory implements Parcelable { final int length = bucketCount - index; System.arraycopy(bucketStart, index, bucketStart, dstPos, length); + if (activeTime != null) System.arraycopy(activeTime, index, activeTime, dstPos, length); if (rxBytes != null) System.arraycopy(rxBytes, index, rxBytes, dstPos, length); if (rxPackets != null) System.arraycopy(rxPackets, index, rxPackets, dstPos, length); if (txBytes != null) System.arraycopy(txBytes, index, txBytes, dstPos, length); @@ -332,6 +347,7 @@ public class NetworkStatsHistory implements Parcelable { } bucketStart[index] = start; + setLong(activeTime, index, 0L); setLong(rxBytes, index, 0L); setLong(rxPackets, index, 0L); setLong(txBytes, index, 0L); @@ -357,6 +373,7 @@ public class NetworkStatsHistory implements Parcelable { if (i > 0) { final int length = bucketStart.length; bucketStart = Arrays.copyOfRange(bucketStart, i, length); + if (activeTime != null) activeTime = Arrays.copyOfRange(activeTime, i, length); if (rxBytes != null) rxBytes = Arrays.copyOfRange(rxBytes, i, length); if (rxPackets != null) rxPackets = Arrays.copyOfRange(rxPackets, i, length); if (txBytes != null) txBytes = Arrays.copyOfRange(txBytes, i, length); @@ -380,8 +397,9 @@ public class NetworkStatsHistory implements Parcelable { */ public Entry getValues(long start, long end, long now, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); - entry.bucketStart = start; entry.bucketDuration = end - start; + entry.bucketStart = start; + entry.activeTime = activeTime != null ? 0 : UNKNOWN; entry.rxBytes = rxBytes != null ? 0 : UNKNOWN; entry.rxPackets = rxPackets != null ? 0 : UNKNOWN; entry.txBytes = txBytes != null ? 0 : UNKNOWN; @@ -404,6 +422,7 @@ public class NetworkStatsHistory implements Parcelable { if (overlap <= 0) continue; // integer math each time is faster than floating point + if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration; if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration; if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration; if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration; @@ -463,6 +482,7 @@ public class NetworkStatsHistory implements Parcelable { for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); + if (activeTime != null) pw.print(" activeTime="); pw.print(activeTime[i]); if (rxBytes != null) pw.print(" rxBytes="); pw.print(rxBytes[i]); if (rxPackets != null) pw.print(" rxPackets="); pw.print(rxPackets[i]); if (txBytes != null) pw.print(" txBytes="); pw.print(txBytes[i]); diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index c2c5c183d3..ec3b1e1477 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -197,6 +197,18 @@ public class TrafficStats { } } + /** + * Increment count of network operations performed under the accounting tag + * currently active on the calling thread. This can be used to derive + * bytes-per-operation. + * + * @param operationCount Number of operations to increment count by. + */ + public static void incrementOperationCount(int operationCount) { + final int tag = getThreadStatsTag(); + incrementOperationCount(tag, operationCount); + } + /** * Increment count of network operations performed under the given * accounting tag. This can be used to derive bytes-per-operation. From dcaeff31759fc2c7fecb44616c971ab1597fe45c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 25 Aug 2011 17:48:52 -0700 Subject: [PATCH 0077/1150] Always splice historical data stats, debug info. When reading network counters, always splice in xt_qtaguid values to avoid counting backwards. Test to verify. Remove verbose logging around global alerts, and add dumpsys debug info for NMS and MDST. Also fix subtle bug around stats persisting and dumping. Bug: 5212893, 5211028 Change-Id: I783e5286637a67ee2dd2b09878198711a926d0cb --- core/java/android/net/NetworkStats.java | 8 +++++++- core/java/android/net/NetworkStatsHistory.java | 12 ++++++------ .../com/android/server/net/NetworkStatsService.java | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 5b883a0741..e5f32735b0 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,6 +19,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.Log; import android.util.SparseBooleanArray; import com.android.internal.util.Objects; @@ -38,6 +39,8 @@ import java.util.HashSet; * @hide */ public class NetworkStats implements Parcelable { + private static final String TAG = "NetworkStats"; + /** {@link #iface} value when interface details unavailable. */ public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ @@ -397,7 +400,10 @@ public class NetworkStats implements Parcelable { if (enforceMonotonic && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 || entry.operations < 0)) { - throw new IllegalArgumentException("found non-monotonic values"); + Log.v(TAG, "lhs=" + this); + Log.v(TAG, "rhs=" + value); + throw new IllegalArgumentException( + "found non-monotonic values at lhs[" + i + "] - rhs[" + j + "]"); } if (clampNegative) { entry.rxBytes = Math.max(0, entry.rxBytes); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index b19949e39d..d07d8990d7 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -482,12 +482,12 @@ public class NetworkStatsHistory implements Parcelable { for (int i = start; i < bucketCount; i++) { pw.print(prefix); pw.print(" bucketStart="); pw.print(bucketStart[i]); - if (activeTime != null) pw.print(" activeTime="); pw.print(activeTime[i]); - if (rxBytes != null) pw.print(" rxBytes="); pw.print(rxBytes[i]); - if (rxPackets != null) pw.print(" rxPackets="); pw.print(rxPackets[i]); - if (txBytes != null) pw.print(" txBytes="); pw.print(txBytes[i]); - if (txPackets != null) pw.print(" txPackets="); pw.print(txPackets[i]); - if (operations != null) pw.print(" operations="); pw.print(operations[i]); + if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); } + if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); } + if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); } + if (txBytes != null) { pw.print(" txBytes="); pw.print(txBytes[i]); } + if (txPackets != null) { pw.print(" txPackets="); pw.print(txPackets[i]); } + if (operations != null) { pw.print(" operations="); pw.print(operations[i]); } pw.println(); } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 80ae9bc6cb..bb0a0d132b 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -707,7 +707,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastPersistUidSnapshot, uidSnapshot, true); if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) { writeUidStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; + mLastPersistUidSnapshot = networkSnapshot; } } From b4d8c1fd1cfa226f48c8d615f96406ad66b7760c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 29 Aug 2011 16:02:57 -0700 Subject: [PATCH 0078/1150] Introduce immediate CONNECTIVITY_ACTION variant. New broadcast that is dispatched immediately after connectivity changes have been handled by ConnectivityService, bypassing any applicable CONNECTIVITY_CHANGE_DELAY. Also protect CONNECTIVITY_CHANGE broadcasts, since they should only be sent by system. Bug: 5198167 Change-Id: I75f1fb44b21da1879f0ab960bcaa481126d70fde --- services/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bb0a0d132b..e0dc96f998 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,7 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -239,7 +239,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // watch for network interfaces to be claimed - final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION); + final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); // listen for periodic polling events From b63138c9b9a6b5594dc5f9a22dc276b85751c16f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 1 Sep 2011 13:06:19 -0700 Subject: [PATCH 0079/1150] Sample network statistics for sanity check. After detailed poll events, sample high-level network statistics to sanity check iface totals against UID totals. Bug: 5248382 Change-Id: I1c1fbb7c094c9ff0c9dde416467c563dda68f478 --- core/java/android/net/NetworkStats.java | 29 ++++++++++-- .../server/net/NetworkStatsService.java | 44 +++++++++++++++++++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e5f32735b0..3918cfdfb4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -320,15 +320,36 @@ public class NetworkStats implements Parcelable { * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. */ public long getTotalBytes() { - long totalBytes = 0; + final Entry entry = getTotal(null); + return entry.rxBytes + entry.txBytes; + } + + /** + * Return total of all fields represented by this snapshot object. + */ + public Entry getTotal(Entry recycle) { + final Entry entry = recycle != null ? recycle : new Entry(); + + entry.iface = IFACE_ALL; + entry.uid = UID_ALL; + entry.set = SET_ALL; + entry.tag = TAG_NONE; + entry.rxBytes = 0; + entry.rxPackets = 0; + entry.txBytes = 0; + entry.txPackets = 0; + for (int i = 0; i < size; i++) { // skip specific tags, since already counted in TAG_NONE if (tag[i] != TAG_NONE) continue; - totalBytes += rxBytes[i]; - totalBytes += txBytes[i]; + entry.rxBytes += rxBytes[i]; + entry.rxPackets += rxPackets[i]; + entry.txBytes += txBytes[i]; + entry.txPackets += txPackets[i]; + entry.operations += operations[i]; } - return totalBytes; + return entry; } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index e0dc96f998..4d54fd4ea0 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -31,6 +31,8 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkTemplate.buildTemplateMobileAll; +import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; @@ -76,6 +78,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; +import android.util.EventLog; import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; @@ -83,6 +86,7 @@ import android.util.TrustedTime; import com.android.internal.os.AtomicFile; import com.android.internal.util.Objects; +import com.android.server.EventLogTags; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -387,7 +391,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { entry.uid = UID_ALL; entry.tag = TAG_NONE; entry.rxBytes = historyEntry.rxBytes; + entry.rxPackets = historyEntry.rxPackets; entry.txBytes = historyEntry.txBytes; + entry.txPackets = historyEntry.txPackets; stats.combineValues(entry); } @@ -716,6 +722,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } + // sample stats after detailed poll + if (detailedPoll) { + performSample(); + } + // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -808,6 +819,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mOperations = new NetworkStats(0L, 10); } + /** + * Sample recent statistics summary into {@link EventLog}. + */ + private void performSample() { + // take sample as total over last 4 hours + final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + final long start = end - (4 * HOUR_IN_MILLIS); + + NetworkTemplate template = null; + NetworkStats.Entry ifaceTotal = null; + NetworkStats.Entry uidTotal = null; + + // collect mobile sample + template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); + ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); + uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); + EventLogTags.writeNetstatsMobileSample( + ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + + // collect wifi sample + template = buildTemplateWifi(); + ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); + uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); + EventLogTags.writeNetstatsWifiSample( + ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + } + /** * Clean up {@link #mUidStats} after UID is removed. */ @@ -1249,6 +1287,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + private static String getActiveSubscriberId(Context context) { + final TelephonyManager telephony = (TelephonyManager) context.getSystemService( + Context.TELEPHONY_SERVICE); + return telephony.getSubscriberId(); + } + /** * Key uniquely identifying a {@link NetworkStatsHistory} for a UID. */ From 459657bab04faf6970bd60718546e03dd9bc9c4e Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 7 Sep 2011 14:35:25 -0700 Subject: [PATCH 0080/1150] Use hasSystemFeature() API to check for p2p Bug: 5267396 Change-Id: I4ff3f77c15322564f63beea793c4585cece596e0 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 1 - 1 file changed, 1 deletion(-) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index a0c7dd1450..381a450187 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -26,6 +26,5 @@ import android.os.Messenger; interface IWifiP2pManager { Messenger getMessenger(); - boolean isP2pSupported(); } From d905762784dbef6c59b40487b10004d5637b0356 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 7 Sep 2011 17:20:27 -0700 Subject: [PATCH 0081/1150] Poll UID stats during iface changes, enforce idx. When ifaces change, poll UID stats without persisting, since they depend on knowing active iface to store correctly. Log dropped UID stats when iface is unknown. Switch to using flags when calling performPoll(). Enforce that "idx" values are consistent from xt_qtaguid. Transition to using Log.wtf() for important checks, mostly around file I/O, kernel stats parsing, and kernel module control. Increase stats persist threshold to 2MB to reduce churn. Bug: 5269476, 5270106 Change-Id: I721215bfb65127f95775c71cf135e907cd567e92 --- core/java/android/net/NetworkStats.java | 15 ++ .../server/net/NetworkStatsService.java | 142 ++++++++++-------- 2 files changed, 94 insertions(+), 63 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 3918cfdfb4..f3be39ca2b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -102,6 +102,21 @@ public class NetworkStats implements Parcelable { this.txPackets = txPackets; this.operations = operations; } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("iface=").append(iface); + builder.append(" uid=").append(uid); + builder.append(" set=").append(setToString(set)); + builder.append(" tag=").append(tagToString(tag)); + builder.append(" rxBytes=").append(rxBytes); + builder.append(" rxPackets=").append(rxPackets); + builder.append(" txBytes=").append(txBytes); + builder.append(" txPackets=").append(txPackets); + builder.append(" operations=").append(operations); + return builder.toString(); + } } public NetworkStats(long elapsedRealtime, int initialSize) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 4d54fd4ea0..af29d85ac6 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -79,6 +79,7 @@ import android.os.SystemClock; import android.provider.Settings; import android.telephony.TelephonyManager; import android.util.EventLog; +import android.util.Log; import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; @@ -128,7 +129,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_SET = 4; private static final int MSG_PERFORM_POLL = 0x1; - private static final int MSG_PERFORM_POLL_DETAILED = 0x2; + + /** Flags to control detail level of poll event. */ + private static final int FLAG_POLL_NETWORK = 0x1; + private static final int FLAG_POLL_UID = 0x2; + private static final int FLAG_PERSIST_NETWORK = 0x10; + private static final int FLAG_PERSIST_UID = 0x20; + private static final int FLAG_FORCE_PERSIST = 0x100; + + private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID; + private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -261,9 +271,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { try { mNetworkManager.registerObserver(mAlertObserver); } catch (RemoteException e) { - // ouch, no push updates means we fall back to - // ACTION_NETWORK_STATS_POLL intervals. - Slog.e(TAG, "unable to register INetworkManagementEventObserver", e); + // ignored; service lives in system_server } registerPollAlarmLocked(); @@ -305,7 +313,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), mPollIntent); } catch (RemoteException e) { - Slog.w(TAG, "problem registering for poll alarm: " + e); + // ignored; service lives in system_server } } @@ -321,7 +329,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (IllegalStateException e) { Slog.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { - Slog.w(TAG, "problem registering for global alert: " + e); + // ignored; service lives in system_server } } @@ -509,7 +517,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - performPoll(true, false); + performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); } /** @@ -538,7 +546,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. - performPoll(true, false); + performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); // verify that we're watching global alert registerGlobalAlert(); @@ -585,7 +593,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. - mHandler.obtainMessage(MSG_PERFORM_POLL).sendToTarget(); + final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK; + mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); // re-arm global alert for next update registerGlobalAlert(); @@ -605,13 +614,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from // the updated network. - performPollLocked(false, false); + + // poll both network and UID stats, but only persist network stats, + // since this codepath should stay fast. UID stats will be persisted + // during next alarm poll event. + performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK); final NetworkState[] states; try { states = mConnManager.getAllNetworkState(); } catch (RemoteException e) { - Slog.w(TAG, "problem reading network state"); + // ignored; service lives in system_server return; } @@ -646,15 +659,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { - Slog.w(TAG, "problem reading network stats: " + e); + // ignored; service lives in system_server } } - private void performPoll(boolean detailedPoll, boolean forcePersist) { + private void performPoll(int flags) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - performPollLocked(detailedPoll, forcePersist); + performPollLocked(flags); } finally { mWakeLock.release(); } @@ -664,14 +677,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Periodic poll operation, reading current statistics and recording into * {@link NetworkStatsHistory}. - * - * @param detailedPoll Indicate if detailed UID stats should be collected - * during this poll operation. */ - private void performPollLocked(boolean detailedPoll, boolean forcePersist) { - if (LOGV) Slog.v(TAG, "performPollLocked()"); + private void performPollLocked(int flags) { + if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); final long startRealtime = SystemClock.elapsedRealtime(); + final boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; + final boolean pollUid = (flags & FLAG_POLL_UID) != 0; + final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; + final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; + final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; + // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { mTime.forceRefresh(); @@ -680,41 +696,40 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long persistThreshold = mSettings.getPersistThreshold(); + final long threshold = mSettings.getPersistThreshold(); - final NetworkStats networkSnapshot; - final NetworkStats uidSnapshot; try { - networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - uidSnapshot = detailedPoll ? mNetworkManager.getNetworkStatsUidDetail(UID_ALL) : null; - } catch (IllegalStateException e) { - Slog.w(TAG, "problem reading network stats: " + e); - return; - } catch (RemoteException e) { - Slog.w(TAG, "problem reading network stats: " + e); - return; - } + if (pollNetwork) { + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); - performNetworkPollLocked(networkSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - if (forcePersist || persistNetworkDelta.getTotalBytes() > persistThreshold) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } - - if (detailedPoll) { - performUidPollLocked(uidSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true); - if (forcePersist || persistUidDelta.getTotalBytes() > persistThreshold) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = networkSnapshot; + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (forcePersist || (persistNetwork && pastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; + } } + + if (pollUid) { + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + performUidPollLocked(uidSnapshot, currentTime); + + // persist when enough network data has occurred + final NetworkStats persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true); + final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold; + if (forcePersist || (persistUid && pastThreshold)) { + writeUidStatsLocked(); + mLastPersistUidSnapshot = uidSnapshot; + } + } + } catch (IllegalStateException e) { + Log.wtf(TAG, "problem reading network stats", e); + } catch (RemoteException e) { + // ignored; service lives in system_server } if (LOGV) { @@ -722,8 +737,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } - // sample stats after detailed poll - if (detailedPoll) { + // sample stats after each full poll + if (pollNetwork && pollUid) { performSample(); } @@ -785,6 +800,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { entry = delta.getValues(i, entry); final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); if (ident == null) { + if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 + || entry.txPackets > 0) { + Log.w(TAG, "dropping UID delta from unknown iface: " + entry); + } continue; } @@ -959,7 +978,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (FileNotFoundException e) { // missing stats is okay, probably first boot } catch (IOException e) { - Slog.e(TAG, "problem reading network stats", e); + Log.wtf(TAG, "problem reading network stats", e); } finally { IoUtils.closeQuietly(in); } @@ -1032,7 +1051,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (FileNotFoundException e) { // missing stats is okay, probably first boot } catch (IOException e) { - Slog.e(TAG, "problem reading uid stats", e); + Log.wtf(TAG, "problem reading uid stats", e); } finally { IoUtils.closeQuietly(in); } @@ -1061,7 +1080,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { out.flush(); mNetworkFile.finishWrite(fos); } catch (IOException e) { - Slog.w(TAG, "problem writing stats: ", e); + Log.wtf(TAG, "problem writing stats", e); if (fos != null) { mNetworkFile.failWrite(fos); } @@ -1115,7 +1134,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { out.flush(); mUidFile.finishWrite(fos); } catch (IOException e) { - Slog.w(TAG, "problem writing stats: ", e); + Log.wtf(TAG, "problem writing stats", e); if (fos != null) { mUidFile.failWrite(fos); } @@ -1142,7 +1161,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(true, true); + performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST); pw.println("Forced poll"); return; } @@ -1273,11 +1292,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { - performPoll(false, false); - return true; - } - case MSG_PERFORM_POLL_DETAILED: { - performPoll(true, false); + final int flags = msg.arg1; + performPoll(flags); return true; } default: { @@ -1349,7 +1365,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } public long getPersistThreshold() { - return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 512 * KB_IN_BYTES); + return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES); } public long getNetworkBucketDuration() { return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); From 869f9e165ba9ecd0bbfb08c6e4961913f6738b10 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 11 Sep 2011 17:33:14 -0700 Subject: [PATCH 0082/1150] Data usage structure optimizations. Driven by traceview hotspots found in Settings UI. Change-Id: I614a049523c526b7fcd12fffdf53a3e4723623e4 --- .../java/android/net/NetworkStatsHistory.java | 45 +++++++++++++++++-- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d07d8990d7..d8ac31f277 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -29,6 +29,7 @@ import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import android.os.Parcel; import android.os.Parcelable; +import android.util.MathUtils; import java.io.CharArrayWriter; import java.io.DataInputStream; @@ -206,6 +207,34 @@ public class NetworkStatsHistory implements Parcelable { } } + /** + * Return index of bucket that contains or is immediately before the + * requested time. + */ + public int getIndexBefore(long time) { + int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); + if (index < 0) { + index = (~index) - 1; + } else { + index -= 1; + } + return MathUtils.constrain(index, 0, bucketCount - 1); + } + + /** + * Return index of bucket that contains or is immediately after the + * requested time. + */ + public int getIndexAfter(long time) { + int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); + if (index < 0) { + index = ~index; + } else { + index += 1; + } + return MathUtils.constrain(index, 0, bucketCount - 1); + } + /** * Return specific stats entry. */ @@ -247,7 +276,8 @@ public class NetworkStatsHistory implements Parcelable { // distribute data usage into buckets long duration = end - start; - for (int i = bucketCount - 1; i >= 0; i--) { + final int startIndex = getIndexAfter(end); + for (int i = startIndex; i >= 0; i--) { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; @@ -406,7 +436,8 @@ public class NetworkStatsHistory implements Parcelable { entry.txPackets = txPackets != null ? 0 : UNKNOWN; entry.operations = operations != null ? 0 : UNKNOWN; - for (int i = bucketCount - 1; i >= 0; i--) { + final int startIndex = getIndexAfter(end); + for (int i = startIndex; i >= 0; i--) { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; @@ -417,8 +448,14 @@ public class NetworkStatsHistory implements Parcelable { // include full value for active buckets, otherwise only fractional final boolean activeBucket = curStart < now && curEnd > now; - final long overlap = activeBucket ? bucketDuration - : Math.min(curEnd, end) - Math.max(curStart, start); + final long overlap; + if (activeBucket) { + overlap = bucketDuration; + } else { + final long overlapEnd = curEnd < end ? curEnd : end; + final long overlapStart = curStart > start ? curStart : start; + overlap = overlapEnd - overlapStart; + } if (overlap <= 0) continue; // integer math each time is faster than floating point From 23f0af822ae963d8b3e4ed26a9d1d988af548f2a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 13 Sep 2011 20:22:15 -0700 Subject: [PATCH 0083/1150] Remove deprecated TrafficStats API. Bug: 5314214 Change-Id: If7dc3ef012a0e998e83ab4fef27ff19398d3e14c --- core/java/android/net/TrafficStats.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ec3b1e1477..47cfa73de0 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -104,14 +104,6 @@ public class TrafficStats { return NetworkManagementSocketTagger.getThreadSocketStatsTag(); } - /** - * @deprecated unsupported, will eventually be removed - */ - @Deprecated - public static void setThreadStatsTag(String tag) { - setThreadStatsTag(tag.hashCode()); - } - public static void clearThreadStatsTag() { NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); } From 4d675fdcf615dea441a2b52f90a9f6a7577de1d9 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 14 Sep 2011 19:31:04 -0700 Subject: [PATCH 0084/1150] Network stats flag to force complete poll. Devices currently delay collecting UID stats during common operations like global alerts to reduce parsing load. Here we introduce a flag to always collect UID and iface stats together to aid debugging. Bug: 5321340 Change-Id: Ia8e1daf1a6f9d5f5cf1f64a04b6b6766ee965ab6 --- .../server/net/NetworkStatsService.java | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index af29d85ac6..a2b097ecb4 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; +import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -176,6 +177,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory(); public long getTagMaxHistory(); public long getTimeCacheMaxAge(); + public boolean getForceCompletePoll(); } private final Object mStatsLock = new Object(); @@ -682,8 +684,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); final long startRealtime = SystemClock.elapsedRealtime(); - final boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; - final boolean pollUid = (flags & FLAG_POLL_UID) != 0; + boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; + boolean pollUid = (flags & FLAG_POLL_UID) != 0; + + // when complete poll requested, any partial poll enables everything + final boolean forceCompletePoll = mSettings.getForceCompletePoll(); + if (forceCompletePoll && (pollNetwork || pollUid)) { + pollNetwork = true; + pollUid = true; + } + final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; @@ -1360,6 +1370,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long getSecureLong(String name, long def) { return Settings.Secure.getLong(mResolver, name, def); } + private boolean getSecureBoolean(String name, boolean def) { + final int defInt = def ? 1 : 0; + return Settings.Secure.getInt(mResolver, name, defInt) != 0; + } public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); @@ -1385,5 +1399,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } + public boolean getForceCompletePoll() { + return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false); + } } } From 4b8629c4bdc834afb65a9bd546efcc50e0d98ed1 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 14 Sep 2011 23:13:55 -0700 Subject: [PATCH 0085/1150] Add packet counts to uid and iface stats. Needed to add Ethernet overhead to uid_stats (IP level) to compare with interface stats (Ethernet level). Change-Id: Ia6324c21a868eea5ad3b67f546c9d10c7fb64172 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index af29d85ac6..5a0e1e4187 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -855,14 +855,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); EventLogTags.writeNetstatsMobileSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + ifaceTotal.rxBytes, ifaceTotal.txBytes, + ifaceTotal.rxPackets, ifaceTotal.txPackets, + uidTotal.rxBytes, uidTotal.txBytes, + uidTotal.rxPackets, uidTotal.txPackets); // collect wifi sample template = buildTemplateWifi(); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); EventLogTags.writeNetstatsWifiSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + ifaceTotal.rxBytes, ifaceTotal.txBytes, + ifaceTotal.rxPackets, ifaceTotal.txPackets, + uidTotal.rxBytes, uidTotal.txBytes, + uidTotal.rxPackets, uidTotal.txPackets); } /** From 987f5ff357a7527aa99dbd334d85a071cb898863 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Sep 2011 01:52:49 -0700 Subject: [PATCH 0086/1150] Collect and persist tethering stats. Use new "gettetherstats" netd command to retrieve statistics for active tethering connections. Keep tethering poll events separate from UID poll, even though they end up same historical structures. Bug: 5244846 Change-Id: Ia0c5165f6712c12b51586f86c331a2aad4ad6afb --- core/java/android/net/TrafficStats.java | 18 ++++- .../server/net/NetworkStatsService.java | 69 ++++++++++++++++++- 2 files changed, 82 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 47cfa73de0..18eb9f69da 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -52,26 +52,34 @@ public class TrafficStats { */ public static final int UID_REMOVED = -4; + /** + * Special UID value used when collecting {@link NetworkStatsHistory} for + * tethering traffic. + * + * @hide + */ + public static final int UID_TETHERING = -5; + /** * Default tag value for {@link DownloadManager} traffic. * * @hide */ - public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFF0001; + public static final int TAG_SYSTEM_DOWNLOAD = 0xFFFFFF01; /** * Default tag value for {@link MediaPlayer} traffic. * * @hide */ - public static final int TAG_SYSTEM_MEDIA = 0xFFFF0002; + public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02; /** * Default tag value for {@link BackupManager} traffic. * * @hide */ - public static final int TAG_SYSTEM_BACKUP = 0xFFFF0003; + public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; /** * Snapshot of {@link NetworkStats} when the currently active profiling @@ -90,6 +98,10 @@ public class TrafficStats { *

* Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. + *

+ * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and + * used internally by system services like {@link DownloadManager} when + * performing traffic on behalf of an application. */ public static void setThreadStatsTag(int tag) { NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index a2b097ecb4..bb5f015de6 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -34,6 +35,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; +import static android.net.TrafficStats.UID_TETHERING; import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; @@ -68,6 +70,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.TrafficStats; import android.os.Binder; import android.os.Environment; import android.os.Handler; @@ -89,6 +92,7 @@ import android.util.TrustedTime; import com.android.internal.os.AtomicFile; import com.android.internal.util.Objects; import com.android.server.EventLogTags; +import com.android.server.connectivity.Tethering; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -134,11 +138,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Flags to control detail level of poll event. */ private static final int FLAG_POLL_NETWORK = 0x1; private static final int FLAG_POLL_UID = 0x2; + private static final int FLAG_POLL_TETHER = 0x3; private static final int FLAG_PERSIST_NETWORK = 0x10; private static final int FLAG_PERSIST_UID = 0x20; private static final int FLAG_FORCE_PERSIST = 0x100; - private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID; + private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private final Context mContext; @@ -195,6 +200,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats mLastPollNetworkSnapshot; private NetworkStats mLastPollUidSnapshot; private NetworkStats mLastPollOperationsSnapshot; + private NetworkStats mLastPollTetherSnapshot; private NetworkStats mLastPersistNetworkSnapshot; private NetworkStats mLastPersistUidSnapshot; @@ -258,6 +264,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); + // watch for tethering changes + final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED); + mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler); + // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); mContext.registerReceiver(mPollReceiver, pollFilter, READ_NETWORK_USAGE_HISTORY, mHandler); @@ -543,6 +553,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Receiver that watches for {@link Tethering} to claim interface pairs. + */ + private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // on background handler thread, and verified CONNECTIVITY_INTERNAL + // permission above. + performPoll(FLAG_POLL_TETHER); + } + }; + private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -686,12 +708,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; boolean pollUid = (flags & FLAG_POLL_UID) != 0; + boolean pollTether = (flags & FLAG_POLL_TETHER) != 0; // when complete poll requested, any partial poll enables everything final boolean forceCompletePoll = mSettings.getForceCompletePoll(); - if (forceCompletePoll && (pollNetwork || pollUid)) { + if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) { pollNetwork = true; pollUid = true; + pollTether = true; } final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; @@ -723,6 +747,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + if (pollTether) { + final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); + final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( + ifacePairs); + performTetherPollLocked(tetherSnapshot, currentTime); + + // persisted during normal UID cycle below + } + if (pollUid) { final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); performUidPollLocked(uidSnapshot, currentTime); @@ -848,6 +881,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mOperations = new NetworkStats(0L, 10); } + /** + * Update {@link #mUidStats} historical usage for + * {@link TrafficStats#UID_TETHERING} based on tethering statistics. + */ + private void performTetherPollLocked(NetworkStats tetherSnapshot, long currentTime) { + ensureUidStatsLoadedLocked(); + + final NetworkStats delta = computeStatsDelta( + mLastPollTetherSnapshot, tetherSnapshot, false); + final long timeStart = currentTime - delta.getElapsedRealtime(); + + NetworkStats.Entry entry = null; + for (int i = 0; i < delta.size(); i++) { + entry = delta.getValues(i, entry); + final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); + if (ident == null) { + if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 + || entry.txPackets > 0) { + Log.w(TAG, "dropping tether delta from unknown iface: " + entry); + } + continue; + } + + final NetworkStatsHistory history = findOrCreateUidStatsLocked( + ident, UID_TETHERING, SET_DEFAULT, TAG_NONE); + history.recordData(timeStart, currentTime, entry); + } + + // normal UID poll will trim any history beyond max + mLastPollTetherSnapshot = tetherSnapshot; + } + /** * Sample recent statistics summary into {@link EventLog}. */ From b10824574cdb21a31b14f9538c64414b62462953 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 18 Sep 2011 13:30:23 -0700 Subject: [PATCH 0087/1150] DO NOT MERGE: Sample atomic network stats buckets, full poll. When sampling network stats, always use atomic buckets instead of interpolating. Always poll iface and UID together so we distribute into buckets equally. Move stale bucket trimming to just before writing stats. Bug: 5321340 Change-Id: I78a2226778a79c875f3668336e39ea24a7b4d5c4 --- .../java/android/net/NetworkStatsHistory.java | 9 +- .../server/net/NetworkStatsService.java | 168 ++++++++---------- 2 files changed, 79 insertions(+), 98 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d8ac31f277..a5cdf70325 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -441,10 +441,10 @@ public class NetworkStatsHistory implements Parcelable { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; - // bucket is older than record; we're finished - if (curEnd < start) break; - // bucket is newer than record; keep looking - if (curStart > end) continue; + // bucket is older than request; we're finished + if (curEnd <= start) break; + // bucket is newer than request; keep looking + if (curStart >= end) continue; // include full value for active buckets, otherwise only fractional final boolean activeBucket = curStart < now && curEnd > now; @@ -466,7 +466,6 @@ public class NetworkStatsHistory implements Parcelable { if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; } - return entry; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bb5f015de6..947cf9c2d8 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -36,7 +36,6 @@ import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; -import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -136,15 +135,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 0x1; /** Flags to control detail level of poll event. */ - private static final int FLAG_POLL_NETWORK = 0x1; - private static final int FLAG_POLL_UID = 0x2; - private static final int FLAG_POLL_TETHER = 0x3; private static final int FLAG_PERSIST_NETWORK = 0x10; private static final int FLAG_PERSIST_UID = 0x20; - private static final int FLAG_FORCE_PERSIST = 0x100; - - private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; + private static final int FLAG_PERSIST_FORCE = 0x100; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -182,7 +176,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory(); public long getTagMaxHistory(); public long getTimeCacheMaxAge(); - public boolean getForceCompletePoll(); } private final Object mStatsLock = new Object(); @@ -529,7 +522,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); } /** @@ -561,7 +554,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - performPoll(FLAG_POLL_TETHER); + performPoll(FLAG_PERSIST_NETWORK); } }; @@ -570,7 +563,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); // verify that we're watching global alert registerGlobalAlert(); @@ -617,7 +610,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. - final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK; + final int flags = FLAG_PERSIST_NETWORK; mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); // re-arm global alert for next update @@ -639,10 +632,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // isn't perfect, since the kernel may already be counting traffic from // the updated network. - // poll both network and UID stats, but only persist network stats, - // since this codepath should stay fast. UID stats will be persisted - // during next alarm poll event. - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK); + // poll, but only persist network stats to keep codepath fast. UID stats + // will be persisted during next alarm poll event. + performPollLocked(FLAG_PERSIST_NETWORK); final NetworkState[] states; try { @@ -706,21 +698,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); final long startRealtime = SystemClock.elapsedRealtime(); - boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; - boolean pollUid = (flags & FLAG_POLL_UID) != 0; - boolean pollTether = (flags & FLAG_POLL_TETHER) != 0; - - // when complete poll requested, any partial poll enables everything - final boolean forceCompletePoll = mSettings.getForceCompletePoll(); - if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) { - pollNetwork = true; - pollUid = true; - pollTether = true; - } - final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; - final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; + final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { @@ -733,41 +713,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long threshold = mSettings.getPersistThreshold(); try { - if (pollNetwork) { - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); + // record network stats + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (forcePersist || (persistNetwork && pastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (persistForce || (persistNetwork && networkPastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; } - if (pollTether) { - final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); - final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - ifacePairs); - performTetherPollLocked(tetherSnapshot, currentTime); + // record tethering stats; persisted during normal UID cycle below + final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); + final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( + ifacePairs); + performTetherPollLocked(tetherSnapshot, currentTime); - // persisted during normal UID cycle below - } + // record uid stats + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + performUidPollLocked(uidSnapshot, currentTime); - if (pollUid) { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - performUidPollLocked(uidSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true); - final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold; - if (forcePersist || (persistUid && pastThreshold)) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = uidSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true); + final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold; + if (persistForce || (persistUid && uidPastThreshold)) { + writeUidStatsLocked(); + mLastPersistUidSnapshot = uidSnapshot; } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); @@ -781,9 +756,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // sample stats after each full poll - if (pollNetwork && pollUid) { - performSample(); - } + performSample(); // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); @@ -813,12 +786,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxHistory = mSettings.getNetworkMaxHistory(); - for (NetworkStatsHistory history : mNetworkStats.values()) { - history.removeBucketsBefore(currentTime - maxHistory); - } - mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { @@ -862,20 +829,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxUidHistory = mSettings.getUidMaxHistory(); - final long maxTagHistory = mSettings.getTagMaxHistory(); - for (UidStatsKey key : mUidStats.keySet()) { - final NetworkStatsHistory history = mUidStats.get(key); - - // detailed tags are trimmed sooner than summary in TAG_NONE - if (key.tag == TAG_NONE) { - history.removeBucketsBefore(currentTime - maxUidHistory); - } else { - history.removeBucketsBefore(currentTime - maxTagHistory); - } - } - mLastPollUidSnapshot = uidSnapshot; mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); @@ -917,9 +870,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Sample recent statistics summary into {@link EventLog}. */ private void performSample() { - // take sample as total over last 4 hours - final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long start = end - (4 * HOUR_IN_MILLIS); + final long largestBucketSize = Math.max( + mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration()); + + // take sample as atomic buckets + final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + final long end = now - (now % largestBucketSize) + largestBucketSize; + final long start = end - largestBucketSize; NetworkTemplate template = null; NetworkStats.Entry ifaceTotal = null; @@ -929,15 +886,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsMobileSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); // collect wifi sample template = buildTemplateWifi(); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsWifiSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, uidTotal.rxBytes, uidTotal.txBytes); + EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); } /** @@ -1137,6 +1096,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : mNetworkStats.values()) { + history.removeBucketsBefore(currentTime - maxHistory); + } + } + FileOutputStream fos = null; try { fos = mNetworkFile.startWrite(); @@ -1172,6 +1140,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxUidHistory = mSettings.getUidMaxHistory(); + final long maxTagHistory = mSettings.getTagMaxHistory(); + for (UidStatsKey key : mUidStats.keySet()) { + final NetworkStatsHistory history = mUidStats.get(key); + + // detailed tags are trimmed sooner than summary in TAG_NONE + if (key.tag == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); + } + } + } + // build UidStatsKey lists grouped by ident final HashMap> keysByIdent = Maps.newHashMap(); for (UidStatsKey key : mUidStats.keySet()) { @@ -1236,7 +1221,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST); + performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); return; } @@ -1464,8 +1449,5 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } - public boolean getForceCompletePoll() { - return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false); - } } } From 8d8ecaef3769f9cc9b1a54efb6e1c76753682d2c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 18 Sep 2011 13:30:23 -0700 Subject: [PATCH 0088/1150] Sample atomic network stats buckets, full poll. When sampling network stats, always use atomic buckets instead of interpolating. Always poll iface and UID together so we distribute into buckets equally. Move stale bucket trimming to just before writing stats. Bug: 5321340 Change-Id: I78a2226778a79c875f3668336e39ea24a7b4d5c4 --- .../java/android/net/NetworkStatsHistory.java | 9 +- .../server/net/NetworkStatsService.java | 174 ++++++++---------- 2 files changed, 79 insertions(+), 104 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d8ac31f277..a5cdf70325 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -441,10 +441,10 @@ public class NetworkStatsHistory implements Parcelable { final long curStart = bucketStart[i]; final long curEnd = curStart + bucketDuration; - // bucket is older than record; we're finished - if (curEnd < start) break; - // bucket is newer than record; keep looking - if (curStart > end) continue; + // bucket is older than request; we're finished + if (curEnd <= start) break; + // bucket is newer than request; keep looking + if (curStart >= end) continue; // include full value for active buckets, otherwise only fractional final boolean activeBucket = curStart < now && curEnd > now; @@ -466,7 +466,6 @@ public class NetworkStatsHistory implements Parcelable { if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; } - return entry; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index c180b7200f..947cf9c2d8 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -36,7 +36,6 @@ import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; -import static android.provider.Settings.Secure.NETSTATS_FORCE_COMPLETE_POLL; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -136,15 +135,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 0x1; /** Flags to control detail level of poll event. */ - private static final int FLAG_POLL_NETWORK = 0x1; - private static final int FLAG_POLL_UID = 0x2; - private static final int FLAG_POLL_TETHER = 0x3; private static final int FLAG_PERSIST_NETWORK = 0x10; private static final int FLAG_PERSIST_UID = 0x20; - private static final int FLAG_FORCE_PERSIST = 0x100; - - private static final int FLAG_POLL_ALL = FLAG_POLL_NETWORK | FLAG_POLL_UID | FLAG_POLL_TETHER; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; + private static final int FLAG_PERSIST_FORCE = 0x100; private final Context mContext; private final INetworkManagementService mNetworkManager; @@ -182,7 +176,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getUidMaxHistory(); public long getTagMaxHistory(); public long getTimeCacheMaxAge(); - public boolean getForceCompletePoll(); } private final Object mStatsLock = new Object(); @@ -529,7 +522,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); } /** @@ -561,7 +554,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - performPoll(FLAG_POLL_TETHER); + performPoll(FLAG_PERSIST_NETWORK); } }; @@ -570,7 +563,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified UPDATE_DEVICE_STATS // permission above. - performPoll(FLAG_POLL_ALL | FLAG_PERSIST_ALL); + performPoll(FLAG_PERSIST_ALL); // verify that we're watching global alert registerGlobalAlert(); @@ -617,7 +610,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats; UID stats // are handled during normal polling interval. - final int flags = FLAG_POLL_NETWORK | FLAG_PERSIST_NETWORK; + final int flags = FLAG_PERSIST_NETWORK; mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); // re-arm global alert for next update @@ -639,10 +632,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // isn't perfect, since the kernel may already be counting traffic from // the updated network. - // poll both network and UID stats, but only persist network stats, - // since this codepath should stay fast. UID stats will be persisted - // during next alarm poll event. - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_NETWORK); + // poll, but only persist network stats to keep codepath fast. UID stats + // will be persisted during next alarm poll event. + performPollLocked(FLAG_PERSIST_NETWORK); final NetworkState[] states; try { @@ -706,21 +698,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); final long startRealtime = SystemClock.elapsedRealtime(); - boolean pollNetwork = (flags & FLAG_POLL_NETWORK) != 0; - boolean pollUid = (flags & FLAG_POLL_UID) != 0; - boolean pollTether = (flags & FLAG_POLL_TETHER) != 0; - - // when complete poll requested, any partial poll enables everything - final boolean forceCompletePoll = mSettings.getForceCompletePoll(); - if (forceCompletePoll && (pollNetwork || pollUid || pollTether)) { - pollNetwork = true; - pollUid = true; - pollTether = true; - } - final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; - final boolean forcePersist = (flags & FLAG_FORCE_PERSIST) != 0; + final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // try refreshing time source when stale if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { @@ -733,41 +713,36 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long threshold = mSettings.getPersistThreshold(); try { - if (pollNetwork) { - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); + // record network stats + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean pastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (forcePersist || (persistNetwork && pastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (persistForce || (persistNetwork && networkPastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; } - if (pollTether) { - final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); - final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - ifacePairs); - performTetherPollLocked(tetherSnapshot, currentTime); + // record tethering stats; persisted during normal UID cycle below + final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); + final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( + ifacePairs); + performTetherPollLocked(tetherSnapshot, currentTime); - // persisted during normal UID cycle below - } + // record uid stats + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + performUidPollLocked(uidSnapshot, currentTime); - if (pollUid) { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - performUidPollLocked(uidSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true); - final boolean pastThreshold = persistUidDelta.getTotalBytes() > threshold; - if (forcePersist || (persistUid && pastThreshold)) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = uidSnapshot; - } + // persist when enough network data has occurred + final NetworkStats persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true); + final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold; + if (persistForce || (persistUid && uidPastThreshold)) { + writeUidStatsLocked(); + mLastPersistUidSnapshot = uidSnapshot; } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); @@ -781,9 +756,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // sample stats after each full poll - if (pollNetwork && pollUid) { - performSample(); - } + performSample(); // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); @@ -813,12 +786,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxHistory = mSettings.getNetworkMaxHistory(); - for (NetworkStatsHistory history : mNetworkStats.values()) { - history.removeBucketsBefore(currentTime - maxHistory); - } - mLastPollNetworkSnapshot = networkSnapshot; if (LOGD && unknownIface.size() > 0) { @@ -862,20 +829,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { history.recordData(timeStart, currentTime, entry); } - // trim any history beyond max - final long maxUidHistory = mSettings.getUidMaxHistory(); - final long maxTagHistory = mSettings.getTagMaxHistory(); - for (UidStatsKey key : mUidStats.keySet()) { - final NetworkStatsHistory history = mUidStats.get(key); - - // detailed tags are trimmed sooner than summary in TAG_NONE - if (key.tag == TAG_NONE) { - history.removeBucketsBefore(currentTime - maxUidHistory); - } else { - history.removeBucketsBefore(currentTime - maxTagHistory); - } - } - mLastPollUidSnapshot = uidSnapshot; mLastPollOperationsSnapshot = mOperations; mOperations = new NetworkStats(0L, 10); @@ -917,9 +870,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Sample recent statistics summary into {@link EventLog}. */ private void performSample() { - // take sample as total over last 4 hours - final long end = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long start = end - (4 * HOUR_IN_MILLIS); + final long largestBucketSize = Math.max( + mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration()); + + // take sample as atomic buckets + final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); + final long end = now - (now % largestBucketSize) + largestBucketSize; + final long start = end - largestBucketSize; NetworkTemplate template = null; NetworkStats.Entry ifaceTotal = null; @@ -929,21 +886,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsMobileSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, - ifaceTotal.rxPackets, ifaceTotal.txPackets, - uidTotal.rxBytes, uidTotal.txBytes, - uidTotal.rxPackets, uidTotal.txPackets); + EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); // collect wifi sample template = buildTemplateWifi(); ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsWifiSample( - ifaceTotal.rxBytes, ifaceTotal.txBytes, - ifaceTotal.rxPackets, ifaceTotal.txPackets, - uidTotal.rxBytes, uidTotal.txBytes, - uidTotal.rxPackets, uidTotal.txPackets); + EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, + ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, + uidTotal.txBytes, uidTotal.rxPackets); } /** @@ -1143,6 +1096,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : mNetworkStats.values()) { + history.removeBucketsBefore(currentTime - maxHistory); + } + } + FileOutputStream fos = null; try { fos = mNetworkFile.startWrite(); @@ -1178,6 +1140,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider duplicating stats and releasing lock while writing + // trim any history beyond max + if (mTime.hasCache()) { + final long currentTime = mTime.currentTimeMillis(); + final long maxUidHistory = mSettings.getUidMaxHistory(); + final long maxTagHistory = mSettings.getTagMaxHistory(); + for (UidStatsKey key : mUidStats.keySet()) { + final NetworkStatsHistory history = mUidStats.get(key); + + // detailed tags are trimmed sooner than summary in TAG_NONE + if (key.tag == TAG_NONE) { + history.removeBucketsBefore(currentTime - maxUidHistory); + } else { + history.removeBucketsBefore(currentTime - maxTagHistory); + } + } + } + // build UidStatsKey lists grouped by ident final HashMap> keysByIdent = Maps.newHashMap(); for (UidStatsKey key : mUidStats.keySet()) { @@ -1242,7 +1221,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (argSet.contains("poll")) { - performPollLocked(FLAG_POLL_ALL | FLAG_PERSIST_ALL | FLAG_FORCE_PERSIST); + performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); return; } @@ -1470,8 +1449,5 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getTimeCacheMaxAge() { return DAY_IN_MILLIS; } - public boolean getForceCompletePoll() { - return getSecureBoolean(NETSTATS_FORCE_COMPLETE_POLL, false); - } } } From ed94a3c7661fc5c85063758da637143a6b52d332 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 19 Sep 2011 18:36:51 -0700 Subject: [PATCH 0089/1150] Upload correct txPackets count. Bug: 5321340 Change-Id: Ie4dc7a91bf1cdc4d64c75ff09ae0cdd0fb141b5d --- services/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 947cf9c2d8..bc65205cbe 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -888,7 +888,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, - uidTotal.txBytes, uidTotal.rxPackets); + uidTotal.txBytes, uidTotal.txPackets); // collect wifi sample template = buildTemplateWifi(); @@ -896,7 +896,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, - uidTotal.txBytes, uidTotal.rxPackets); + uidTotal.txBytes, uidTotal.txPackets); } /** From 6a2cbb63b337e7fff7084a5a08f236058b8cc8f4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 22 Sep 2011 14:59:51 -0700 Subject: [PATCH 0090/1150] Watch network subtype, tethering teardown, empty. Watch for changes to telephony network subtype, and update iface mapping to persist stats under correct type. Update network stats before removing tethering NAT rules. Skip recording that would create empty historical buckets. Query UID stats before iface stats to always skew positive when counters are actively rolling forward. Bug: 5360042, 5359860, 5335674, 5334448 Change-Id: I8aa37b568e8ffb70647218aa1aff5195d3e44d5a --- .../java/android/net/NetworkStatsHistory.java | 5 + .../server/net/NetworkStatsService.java | 99 ++++++++++++++----- 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a5cdf70325..a6635bee20 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -270,6 +270,11 @@ public class NetworkStatsHistory implements Parcelable { || entry.operations < 0) { throw new IllegalArgumentException("tried recording negative data"); } + if (entry.rxBytes == 0 && entry.rxPackets == 0 && entry.txBytes == 0 && entry.txPackets == 0 + && entry.operations == 0) { + // nothing to record; skip + return; + } // create any buckets needed by this range ensureBuckets(start, end); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bc65205cbe..aa46795b4f 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -24,8 +24,8 @@ import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; +import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -43,9 +43,12 @@ import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; +import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -80,6 +83,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; +import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; @@ -121,7 +125,7 @@ import libcore.io.IoUtils; */ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStats"; - private static final boolean LOGD = true; + private static final boolean LOGD = false; private static final boolean LOGV = false; /** File header magic number: "ANET" */ @@ -132,7 +136,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int VERSION_UID_WITH_TAG = 3; private static final int VERSION_UID_WITH_SET = 4; - private static final int MSG_PERFORM_POLL = 0x1; + private static final int MSG_PERFORM_POLL = 1; + private static final int MSG_UPDATE_IFACES = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x10; @@ -144,6 +149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; private final TrustedTime mTime; + private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final PowerManager.WakeLock mWakeLock; @@ -227,6 +233,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); + mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); final PowerManager powerManager = (PowerManager) context.getSystemService( @@ -279,6 +286,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // ignored; service lives in system_server } + // watch for networkType changes that aren't broadcast through + // CONNECTIVITY_ACTION_IMMEDIATE above. + mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + registerPollAlarmLocked(); registerGlobalAlert(); @@ -288,10 +299,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void shutdownLocked() { mContext.unregisterReceiver(mConnReceiver); + mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + writeNetworkStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); @@ -535,14 +549,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and verified CONNECTIVITY_INTERNAL // permission above. - synchronized (mStatsLock) { - mWakeLock.acquire(); - try { - updateIfacesLocked(); - } finally { - mWakeLock.release(); - } - } + updateIfaces(); } }; @@ -619,6 +626,46 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN; + private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between network types. + */ + private PhoneStateListener mPhoneListener = new PhoneStateListener() { + @Override + public void onDataConnectionStateChanged(int state, int networkType) { + final boolean stateChanged = state != mLastPhoneState; + final boolean networkTypeChanged = networkType != mLastPhoneNetworkType; + + if (networkTypeChanged && !stateChanged) { + // networkType changed without a state change, which means we + // need to roll our own update. delay long enough for + // ConnectivityManager to process. + // TODO: add direct event to ConnectivityService instead of + // relying on this delay. + if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()"); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + + mLastPhoneState = state; + mLastPhoneNetworkType = networkType; + } + }; + + private void updateIfaces() { + synchronized (mStatsLock) { + mWakeLock.acquire(); + try { + updateIfacesLocked(); + } finally { + mWakeLock.release(); + } + } + } + /** * Inspect all current {@link NetworkState} to derive mapping from {@code * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} @@ -713,19 +760,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long threshold = mSettings.getPersistThreshold(); try { - // record network stats - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); - - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (persistForce || (persistNetwork && networkPastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } - // record tethering stats; persisted during normal UID cycle below final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( @@ -744,6 +778,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; } + + // record network stats + final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkPollLocked(networkSnapshot, currentTime); + + // persist when enough network data has occurred + final NetworkStats persistNetworkDelta = computeStatsDelta( + mLastPersistNetworkSnapshot, networkSnapshot, true); + final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; + if (persistForce || (persistNetwork && networkPastThreshold)) { + writeNetworkStatsLocked(); + mLastPersistNetworkSnapshot = networkSnapshot; + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); } catch (RemoteException e) { @@ -1356,6 +1403,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(flags); return true; } + case MSG_UPDATE_IFACES: { + updateIfaces(); + return true; + } default: { return false; } From 8cddd4a5c7c9d37c38571528a237fa0104301c47 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 26 Sep 2011 10:47:10 -0700 Subject: [PATCH 0091/1150] Overlay to configure data usage network types. Specify which network types should be counted when computing data usage totals. Bug: 5361005 Change-Id: I830caed1a29199892d209a692b50f8b3e144cafe --- core/java/android/net/NetworkTemplate.java | 41 ++++++++++++++-------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cd4902308b..418b82fdea 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -19,14 +19,15 @@ package android.net; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkIdentity.scrubSubscriberId; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; import static android.telephony.TelephonyManager.getNetworkClass; +import static com.android.internal.util.ArrayUtils.contains; +import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; @@ -51,6 +52,16 @@ public class NetworkTemplate implements Parcelable { /** {@hide} */ public static final int MATCH_ETHERNET = 5; + /** + * Set of {@link NetworkInfo#getType()} that reflect data usage. + */ + private static final int[] DATA_USAGE_NETWORK_TYPES; + + static { + DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray( + com.android.internal.R.array.config_data_usage_network_types); + } + /** * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style * networks together. Only uses statistics for requested IMSI. @@ -151,7 +162,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Test if this network matches the given template and IMSI. + * Test if given {@link NetworkIdentity} matches this template. */ public boolean matches(NetworkIdentity ident) { switch (mMatchRule) { @@ -171,23 +182,25 @@ public class NetworkTemplate implements Parcelable { } /** - * Check if mobile network with matching IMSI. Also matches - * {@link #TYPE_WIMAX}. + * Check if mobile network with matching IMSI. */ private boolean matchesMobile(NetworkIdentity ident) { - if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { - return true; - } else if (ident.mType == TYPE_WIMAX) { + if (ident.mType == TYPE_WIMAX) { + // TODO: consider matching against WiMAX subscriber identity return true; + } else { + return (contains(DATA_USAGE_NETWORK_TYPES, ident.mType) + && Objects.equal(mSubscriberId, ident.mSubscriberId)); } - return false; } /** * Check if mobile network classified 3G or lower with matching IMSI. */ private boolean matchesMobile3gLower(NetworkIdentity ident) { - if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + if (ident.mType == TYPE_WIMAX) { + return false; + } else if (matchesMobile(ident)) { switch (getNetworkClass(ident.mSubType)) { case NETWORK_CLASS_UNKNOWN: case NETWORK_CLASS_2_G: @@ -199,17 +212,17 @@ public class NetworkTemplate implements Parcelable { } /** - * Check if mobile network classified 4G with matching IMSI. Also matches - * {@link #TYPE_WIMAX}. + * Check if mobile network classified 4G with matching IMSI. */ private boolean matchesMobile4g(NetworkIdentity ident) { - if (isNetworkTypeMobile(ident.mType) && Objects.equal(mSubscriberId, ident.mSubscriberId)) { + if (ident.mType == TYPE_WIMAX) { + // TODO: consider matching against WiMAX subscriber identity + return true; + } else if (matchesMobile(ident)) { switch (getNetworkClass(ident.mSubType)) { case NETWORK_CLASS_4_G: return true; } - } else if (ident.mType == TYPE_WIMAX) { - return true; } return false; } From f1369459ed87b8e35bf2cda8da40271a6b6bea58 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 30 Sep 2011 15:19:49 -0700 Subject: [PATCH 0092/1150] Track xtables summary, move tether stats, time. Begin tracking xtables summary of data usage to compare with values reported from /proc/net/dev. Roll tethering directly into UID stats to trigger UID stats persisting when crossing threshold. Include xtables summary and authoritative time in samples. Bug: 5373561, 5397882, 5381980 Change-Id: Ib7945522caadfbe0864fdf391582dc820f4f371e --- core/java/android/net/NetworkStats.java | 39 +++ .../server/net/NetworkStatsService.java | 331 ++++++++++++------ 2 files changed, 254 insertions(+), 116 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f3be39ca2b..e5549753cc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -271,6 +271,17 @@ public class NetworkStats implements Parcelable { return this; } + /** + * Combine all values from another {@link NetworkStats} into this object. + */ + public void combineAllValues(NetworkStats another) { + NetworkStats.Entry entry = null; + for (int i = 0; i < another.size; i++) { + entry = another.getValues(i, entry); + combineValues(entry); + } + } + /** * Find first stats index that matches the requested parameters. */ @@ -456,6 +467,34 @@ public class NetworkStats implements Parcelable { return result; } + /** + * Return total statistics grouped by {@link #iface}; doesn't mutate the + * original structure. + */ + public NetworkStats groupedByIface() { + final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); + + final Entry entry = new Entry(); + entry.uid = UID_ALL; + entry.set = SET_ALL; + entry.tag = TAG_NONE; + entry.operations = 0L; + + for (int i = 0; i < size; i++) { + // skip specific tags, since already counted in TAG_NONE + if (tag[i] != TAG_NONE) continue; + + entry.iface = iface[i]; + entry.rxBytes = rxBytes[i]; + entry.rxPackets = rxPackets[i]; + entry.txBytes = txBytes[i]; + entry.txPackets = txPackets[i]; + stats.combineValues(entry); + } + + return stats; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index aa46795b4f..e5f0a77974 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -35,7 +35,6 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; -import static android.net.TrafficStats.UID_TETHERING; import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; @@ -72,7 +71,6 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.net.TrafficStats; import android.os.Binder; import android.os.Environment; import android.os.Handler; @@ -140,11 +138,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_UPDATE_IFACES = 2; /** Flags to control detail level of poll event. */ - private static final int FLAG_PERSIST_NETWORK = 0x10; - private static final int FLAG_PERSIST_UID = 0x20; + private static final int FLAG_PERSIST_NETWORK = 0x1; + private static final int FLAG_PERSIST_UID = 0x2; private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_FORCE = 0x100; + /** Sample recent usage after each poll event. */ + private static final boolean ENABLE_SAMPLE_AFTER_POLL = true; + private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -188,20 +189,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of currently active ifaces. */ private HashMap mActiveIfaces = Maps.newHashMap(); - /** Set of historical network layer stats for known networks. */ - private HashMap mNetworkStats = Maps.newHashMap(); - /** Set of historical network layer stats for known UIDs. */ + /** Set of historical {@code dev} stats for known networks. */ + private HashMap mNetworkDevStats = Maps.newHashMap(); + /** Set of historical {@code xtables} stats for known networks. */ + private HashMap mNetworkXtStats = Maps.newHashMap(); + /** Set of historical {@code xtables} stats for known UIDs. */ private HashMap mUidStats = Maps.newHashMap(); /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; - private NetworkStats mLastPollNetworkSnapshot; + private NetworkStats mLastPollNetworkDevSnapshot; + private NetworkStats mLastPollNetworkXtSnapshot; private NetworkStats mLastPollUidSnapshot; private NetworkStats mLastPollOperationsSnapshot; - private NetworkStats mLastPollTetherSnapshot; - private NetworkStats mLastPersistNetworkSnapshot; + private NetworkStats mLastPersistNetworkDevSnapshot; + private NetworkStats mLastPersistNetworkXtSnapshot; private NetworkStats mLastPersistUidSnapshot; /** Current counter sets for each UID. */ @@ -213,7 +217,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final HandlerThread mHandlerThread; private final Handler mHandler; - private final AtomicFile mNetworkFile; + private final AtomicFile mNetworkDevFile; + private final AtomicFile mNetworkXtFile; private final AtomicFile mUidFile; public NetworkStatsService( @@ -244,7 +249,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); - mNetworkFile = new AtomicFile(new File(systemDir, "netstats.bin")); + mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin")); + mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin")); mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin")); } @@ -257,7 +263,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // read historical network stats from disk, since policy service // might need them right away. we delay loading detailed UID stats // until actually needed. - readNetworkStatsLocked(); + readNetworkDevStatsLocked(); + readNetworkXtStatsLocked(); } // watch for network interfaces to be claimed @@ -306,11 +313,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mTeleManager.listen(mPhoneListener, LISTEN_NONE); - writeNetworkStatsLocked(); + writeNetworkDevStatsLocked(); + writeNetworkXtStatsLocked(); if (mUidStatsLoaded) { writeUidStatsLocked(); } - mNetworkStats.clear(); + mNetworkDevStats.clear(); + mNetworkXtStats.clear(); mUidStats.clear(); mUidStatsLoaded = false; } @@ -355,14 +364,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return getHistoryForNetworkDev(template, fields); + } + private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) { + return getHistoryForNetwork(template, fields, mNetworkDevStats); + } + + private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) { + return getHistoryForNetwork(template, fields, mNetworkXtStats); + } + + private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields, + HashMap source) { synchronized (mStatsLock) { // combine all interfaces that match template final NetworkStatsHistory combined = new NetworkStatsHistory( mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields); - for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + for (NetworkIdentitySet ident : source.keySet()) { if (templateMatches(template, ident)) { - final NetworkStatsHistory history = mNetworkStats.get(ident); + final NetworkStatsHistory history = source.get(ident); if (history != null) { combined.recordEntireHistory(history); } @@ -399,7 +420,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return getSummaryForNetworkDev(template, start, end); + } + private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) { + return getSummaryForNetwork(template, start, end, mNetworkDevStats); + } + + private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) { + return getSummaryForNetwork(template, start, end, mNetworkXtStats); + } + + private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end, + HashMap source) { synchronized (mStatsLock) { // use system clock to be externally consistent final long now = System.currentTimeMillis(); @@ -409,9 +442,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsHistory.Entry historyEntry = null; // combine total from all interfaces that match template - for (NetworkIdentitySet ident : mNetworkStats.keySet()) { + for (NetworkIdentitySet ident : source.keySet()) { if (templateMatches(template, ident)) { - final NetworkStatsHistory history = mNetworkStats.get(ident); + final NetworkStatsHistory history = source.get(ident); historyEntry = history.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; @@ -716,8 +749,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void bootstrapStats() { try { - mLastPollNetworkSnapshot = mNetworkManager.getNetworkStatsSummary(); mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary(); + mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); mLastPollOperationsSnapshot = new NetworkStats(0L, 0); } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); @@ -759,42 +793,56 @@ public class NetworkStatsService extends INetworkStatsService.Stub { : System.currentTimeMillis(); final long threshold = mSettings.getPersistThreshold(); + final NetworkStats uidSnapshot; + final NetworkStats networkXtSnapshot; + final NetworkStats networkDevSnapshot; try { - // record tethering stats; persisted during normal UID cycle below - final String[] ifacePairs = mConnManager.getTetheredIfacePairs(); + // collect any tethering stats + final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - ifacePairs); - performTetherPollLocked(tetherSnapshot, currentTime); + tetheredIfacePairs); - // record uid stats - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + // record uid stats, folding in tethering stats + uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + uidSnapshot.combineAllValues(tetherSnapshot); performUidPollLocked(uidSnapshot, currentTime); - // persist when enough network data has occurred - final NetworkStats persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true); - final boolean uidPastThreshold = persistUidDelta.getTotalBytes() > threshold; - if (persistForce || (persistUid && uidPastThreshold)) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = uidSnapshot; - } + // record dev network stats + networkDevSnapshot = mNetworkManager.getNetworkStatsSummary(); + performNetworkDevPollLocked(networkDevSnapshot, currentTime); - // record network stats - final NetworkStats networkSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkPollLocked(networkSnapshot, currentTime); + // record xt network stats + networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot); + performNetworkXtPollLocked(networkXtSnapshot, currentTime); - // persist when enough network data has occurred - final NetworkStats persistNetworkDelta = computeStatsDelta( - mLastPersistNetworkSnapshot, networkSnapshot, true); - final boolean networkPastThreshold = persistNetworkDelta.getTotalBytes() > threshold; - if (persistForce || (persistNetwork && networkPastThreshold)) { - writeNetworkStatsLocked(); - mLastPersistNetworkSnapshot = networkSnapshot; - } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); + return; } catch (RemoteException e) { // ignored; service lives in system_server + return; + } + + // persist when enough network data has occurred + final long persistNetworkDevDelta = computeStatsDelta( + mLastPersistNetworkDevSnapshot, networkDevSnapshot, true).getTotalBytes(); + final long persistNetworkXtDelta = computeStatsDelta( + mLastPersistNetworkXtSnapshot, networkXtSnapshot, true).getTotalBytes(); + final boolean networkOverThreshold = persistNetworkDevDelta > threshold + || persistNetworkXtDelta > threshold; + if (persistForce || (persistNetwork && networkOverThreshold)) { + writeNetworkDevStatsLocked(); + writeNetworkXtStatsLocked(); + mLastPersistNetworkDevSnapshot = networkDevSnapshot; + mLastPersistNetworkXtSnapshot = networkXtSnapshot; + } + + // persist when enough uid data has occurred + final long persistUidDelta = computeStatsDelta(mLastPersistUidSnapshot, uidSnapshot, true) + .getTotalBytes(); + if (persistForce || (persistUid && persistUidDelta > threshold)) { + writeUidStatsLocked(); + mLastPersistUidSnapshot = uidSnapshot; } if (LOGV) { @@ -802,8 +850,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } - // sample stats after each full poll - performSample(); + if (ENABLE_SAMPLE_AFTER_POLL) { + // sample stats after each full poll + performSample(); + } // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); @@ -812,12 +862,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Update {@link #mNetworkStats} historical usage. + * Update {@link #mNetworkDevStats} historical usage. */ - private void performNetworkPollLocked(NetworkStats networkSnapshot, long currentTime) { + private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) { final HashSet unknownIface = Sets.newHashSet(); - final NetworkStats delta = computeStatsDelta(mLastPollNetworkSnapshot, networkSnapshot, false); + final NetworkStats delta = computeStatsDelta( + mLastPollNetworkDevSnapshot, networkDevSnapshot, false); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -829,14 +880,44 @@ public class NetworkStatsService extends INetworkStatsService.Stub { continue; } - final NetworkStatsHistory history = findOrCreateNetworkStatsLocked(ident); + final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident); history.recordData(timeStart, currentTime, entry); } - mLastPollNetworkSnapshot = networkSnapshot; + mLastPollNetworkDevSnapshot = networkDevSnapshot; if (LOGD && unknownIface.size() > 0) { - Slog.w(TAG, "unknown interfaces " + unknownIface.toString() + ", ignoring those stats"); + Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats"); + } + } + + /** + * Update {@link #mNetworkXtStats} historical usage. + */ + private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) { + final HashSet unknownIface = Sets.newHashSet(); + + final NetworkStats delta = computeStatsDelta( + mLastPollNetworkXtSnapshot, networkXtSnapshot, false); + final long timeStart = currentTime - delta.getElapsedRealtime(); + + NetworkStats.Entry entry = null; + for (int i = 0; i < delta.size(); i++) { + entry = delta.getValues(i, entry); + final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); + if (ident == null) { + unknownIface.add(entry.iface); + continue; + } + + final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident); + history.recordData(timeStart, currentTime, entry); + } + + mLastPollNetworkXtSnapshot = networkXtSnapshot; + + if (LOGD && unknownIface.size() > 0) { + Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats"); } } @@ -881,38 +962,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mOperations = new NetworkStats(0L, 10); } - /** - * Update {@link #mUidStats} historical usage for - * {@link TrafficStats#UID_TETHERING} based on tethering statistics. - */ - private void performTetherPollLocked(NetworkStats tetherSnapshot, long currentTime) { - ensureUidStatsLoadedLocked(); - - final NetworkStats delta = computeStatsDelta( - mLastPollTetherSnapshot, tetherSnapshot, false); - final long timeStart = currentTime - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); - if (ident == null) { - if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 - || entry.txPackets > 0) { - Log.w(TAG, "dropping tether delta from unknown iface: " + entry); - } - continue; - } - - final NetworkStatsHistory history = findOrCreateUidStatsLocked( - ident, UID_TETHERING, SET_DEFAULT, TAG_NONE); - history.recordData(timeStart, currentTime, entry); - } - - // normal UID poll will trim any history beyond max - mLastPollTetherSnapshot = tetherSnapshot; - } - /** * Sample recent statistics summary into {@link EventLog}. */ @@ -925,25 +974,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long end = now - (now % largestBucketSize) + largestBucketSize; final long start = end - largestBucketSize; + final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; + NetworkTemplate template = null; - NetworkStats.Entry ifaceTotal = null; + NetworkStats.Entry devTotal = null; + NetworkStats.Entry xtTotal = null; NetworkStats.Entry uidTotal = null; // collect mobile sample template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); - ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); + devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); + xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsMobileSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, - ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, - uidTotal.txBytes, uidTotal.txPackets); + EventLogTags.writeNetstatsMobileSample( + devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, + trustedTime); // collect wifi sample template = buildTemplateWifi(); - ifaceTotal = getSummaryForNetwork(template, start, end).getTotal(ifaceTotal); + devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); + xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); - EventLogTags.writeNetstatsWifiSample(ifaceTotal.rxBytes, ifaceTotal.rxPackets, - ifaceTotal.txBytes, ifaceTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, - uidTotal.txBytes, uidTotal.txPackets); + EventLogTags.writeNetstatsWifiSample( + devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, + xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, + uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, + trustedTime); } /** @@ -976,8 +1034,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { writeUidStatsLocked(); } - private NetworkStatsHistory findOrCreateNetworkStatsLocked(NetworkIdentitySet ident) { - final NetworkStatsHistory existing = mNetworkStats.get(ident); + private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) { + return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats); + } + + private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) { + return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats); + } + + private NetworkStatsHistory findOrCreateNetworkStatsLocked( + NetworkIdentitySet ident, HashMap source) { + final NetworkStatsHistory existing = source.get(ident); // update when no existing, or when bucket duration changed final long bucketDuration = mSettings.getNetworkBucketDuration(); @@ -991,7 +1058,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (updated != null) { - mNetworkStats.put(ident, updated); + source.put(ident, updated); return updated; } else { return existing; @@ -1024,15 +1091,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void readNetworkStatsLocked() { - if (LOGV) Slog.v(TAG, "readNetworkStatsLocked()"); + private void readNetworkDevStatsLocked() { + if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()"); + readNetworkStats(mNetworkDevFile, mNetworkDevStats); + } + private void readNetworkXtStatsLocked() { + if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()"); + readNetworkStats(mNetworkXtFile, mNetworkXtStats); + } + + private static void readNetworkStats( + AtomicFile inputFile, HashMap output) { // clear any existing stats and read from disk - mNetworkStats.clear(); + output.clear(); DataInputStream in = null; try { - in = new DataInputStream(new BufferedInputStream(mNetworkFile.openRead())); + in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); // verify file magic header intact final int magic = in.readInt(); @@ -1048,7 +1124,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < size; i++) { final NetworkIdentitySet ident = new NetworkIdentitySet(in); final NetworkStatsHistory history = new NetworkStatsHistory(in); - mNetworkStats.put(ident, history); + output.put(ident, history); } break; } @@ -1138,41 +1214,50 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void writeNetworkStatsLocked() { - if (LOGV) Slog.v(TAG, "writeNetworkStatsLocked()"); + private void writeNetworkDevStatsLocked() { + if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()"); + writeNetworkStats(mNetworkDevStats, mNetworkDevFile); + } + private void writeNetworkXtStatsLocked() { + if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()"); + writeNetworkStats(mNetworkXtStats, mNetworkXtFile); + } + + private void writeNetworkStats( + HashMap input, AtomicFile outputFile) { // TODO: consider duplicating stats and releasing lock while writing // trim any history beyond max if (mTime.hasCache()) { final long currentTime = mTime.currentTimeMillis(); final long maxHistory = mSettings.getNetworkMaxHistory(); - for (NetworkStatsHistory history : mNetworkStats.values()) { + for (NetworkStatsHistory history : input.values()) { history.removeBucketsBefore(currentTime - maxHistory); } } FileOutputStream fos = null; try { - fos = mNetworkFile.startWrite(); + fos = outputFile.startWrite(); final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); out.writeInt(FILE_MAGIC); out.writeInt(VERSION_NETWORK_INIT); - out.writeInt(mNetworkStats.size()); - for (NetworkIdentitySet ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); + out.writeInt(input.size()); + for (NetworkIdentitySet ident : input.keySet()) { + final NetworkStatsHistory history = input.get(ident); ident.writeToStream(out); history.writeToStream(out); } out.flush(); - mNetworkFile.finishWrite(fos); + outputFile.finishWrite(fos); } catch (IOException e) { Log.wtf(TAG, "problem writing stats", e); if (fos != null) { - mNetworkFile.failWrite(fos); + outputFile.failWrite(fos); } } } @@ -1280,9 +1365,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { pw.print(" ident="); pw.println(ident.toString()); } - pw.println("Known historical stats:"); - for (NetworkIdentitySet ident : mNetworkStats.keySet()) { - final NetworkStatsHistory history = mNetworkStats.get(ident); + pw.println("Known historical dev stats:"); + for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) { + final NetworkStatsHistory history = mNetworkDevStats.get(ident); + pw.print(" ident="); pw.println(ident.toString()); + history.dump(" ", pw, fullHistory); + } + + pw.println("Known historical xt stats:"); + for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) { + final NetworkStatsHistory history = mNetworkXtStats.get(ident); pw.print(" ident="); pw.println(ident.toString()); history.dump(" ", pw, fullHistory); } @@ -1333,10 +1425,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final List installedApps = mContext .getPackageManager().getInstalledApplications(0); - mNetworkStats.clear(); + mNetworkDevStats.clear(); + mNetworkXtStats.clear(); mUidStats.clear(); for (NetworkIdentitySet ident : mActiveIfaces.values()) { - findOrCreateNetworkStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES, + findOrCreateNetworkDevStatsLocked(ident).generateRandom(NET_START, NET_END, + NET_RX_BYTES, NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L); + findOrCreateNetworkXtStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES, NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L); for (ApplicationInfo info : installedApps) { @@ -1369,6 +1464,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) { + return uidSnapshot.groupedByIface(); + } + private int estimateNetworkBuckets() { return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); } From 0787a3616f268be728fa8f551096eb883d9176bd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 5 Oct 2011 23:31:57 -0700 Subject: [PATCH 0093/1150] Refine random stats generation. Offer parameters to pick out specific list of packages, and to change duration and total data. Bug: 5416742 Change-Id: I6970a5e76f3198ef23a400c079037212b000ca6b --- .../java/android/net/NetworkStatsHistory.java | 25 ++++- .../server/net/NetworkStatsService.java | 102 ++++++++++++------ 2 files changed, 92 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a6635bee20..8c01331595 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -474,21 +474,38 @@ public class NetworkStatsHistory implements Parcelable { return entry; } + /** + * @deprecated only for temporary testing + */ + @Deprecated + public void generateRandom(long start, long end, long bytes) { + final Random r = new Random(); + + final float fractionRx = r.nextFloat(); + final long rxBytes = (long) (bytes * fractionRx); + final long txBytes = (long) (bytes * (1 - fractionRx)); + + final long rxPackets = rxBytes / 1024; + final long txPackets = txBytes / 1024; + final long operations = rxBytes / 2048; + + generateRandom(start, end, rxBytes, rxPackets, txBytes, txPackets, operations, r); + } + /** * @deprecated only for temporary testing */ @Deprecated public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operations) { + long txPackets, long operations, Random r) { ensureBuckets(start, end); final NetworkStats.Entry entry = new NetworkStats.Entry( IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); - final Random r = new Random(); while (rxBytes > 1024 || rxPackets > 128 || txBytes > 1024 || txPackets > 128 || operations > 32) { final long curStart = randomLong(r, start, end); - final long curEnd = randomLong(r, curStart, end); + final long curEnd = curStart + randomLong(r, 0, (end - curStart) / 2); entry.rxBytes = randomLong(r, 0, rxBytes); entry.rxPackets = randomLong(r, 0, rxPackets); @@ -506,7 +523,7 @@ public class NetworkStatsHistory implements Parcelable { } } - private static long randomLong(Random r, long start, long end) { + public static long randomLong(Random r, long start, long end) { return (long) (start + (r.nextFloat() * (end - start))); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index e5f0a77974..789681e569 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -32,6 +32,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStatsHistory.randomLong; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; @@ -48,6 +49,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -62,6 +64,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; @@ -113,7 +117,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.List; +import java.util.Random; import libcore.io.IoUtils; @@ -1347,7 +1351,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { // TODO: remove this testing code, since it corrupts stats if (argSet.contains("generate")) { - generateRandomLocked(); + generateRandomLocked(args); pw.println("Generated stub stats"); return; } @@ -1406,42 +1410,78 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * @deprecated only for temporary testing */ @Deprecated - private void generateRandomLocked() { - final long NET_END = System.currentTimeMillis(); - final long NET_START = NET_END - mSettings.getNetworkMaxHistory(); - final long NET_RX_BYTES = 3 * GB_IN_BYTES; - final long NET_RX_PACKETS = NET_RX_BYTES / 1024; - final long NET_TX_BYTES = 2 * GB_IN_BYTES; - final long NET_TX_PACKETS = NET_TX_BYTES / 1024; + private void generateRandomLocked(String[] args) { + final long totalBytes = Long.parseLong(args[1]); + final long totalTime = Long.parseLong(args[2]); + + final PackageManager pm = mContext.getPackageManager(); + final ArrayList specialUidList = Lists.newArrayList(); + for (int i = 3; i < args.length; i++) { + try { + specialUidList.add(pm.getApplicationInfo(args[i], 0).uid); + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + } - final long UID_END = System.currentTimeMillis(); - final long UID_START = UID_END - mSettings.getUidMaxHistory(); - final long UID_RX_BYTES = 500 * MB_IN_BYTES; - final long UID_RX_PACKETS = UID_RX_BYTES / 1024; - final long UID_TX_BYTES = 100 * MB_IN_BYTES; - final long UID_TX_PACKETS = UID_TX_BYTES / 1024; - final long UID_OPERATIONS = UID_RX_BYTES / 2048; + final HashSet otherUidSet = Sets.newHashSet(); + for (ApplicationInfo info : pm.getInstalledApplications(0)) { + if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName) + == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) { + otherUidSet.add(info.uid); + } + } - final List installedApps = mContext - .getPackageManager().getInstalledApplications(0); + final ArrayList otherUidList = new ArrayList(otherUidSet); + + final long end = System.currentTimeMillis(); + final long start = end - totalTime; mNetworkDevStats.clear(); mNetworkXtStats.clear(); mUidStats.clear(); - for (NetworkIdentitySet ident : mActiveIfaces.values()) { - findOrCreateNetworkDevStatsLocked(ident).generateRandom(NET_START, NET_END, - NET_RX_BYTES, NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L); - findOrCreateNetworkXtStatsLocked(ident).generateRandom(NET_START, NET_END, NET_RX_BYTES, - NET_RX_PACKETS, NET_TX_BYTES, NET_TX_PACKETS, 0L); - for (ApplicationInfo info : installedApps) { - final int uid = info.uid; - findOrCreateUidStatsLocked(ident, uid, SET_DEFAULT, TAG_NONE).generateRandom( - UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, - UID_TX_PACKETS, UID_OPERATIONS); - findOrCreateUidStatsLocked(ident, uid, SET_FOREGROUND, TAG_NONE).generateRandom( - UID_START, UID_END, UID_RX_BYTES, UID_RX_PACKETS, UID_TX_BYTES, - UID_TX_PACKETS, UID_OPERATIONS); + final Random r = new Random(); + for (NetworkIdentitySet ident : mActiveIfaces.values()) { + final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident); + final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident); + + final ArrayList uidList = new ArrayList(); + uidList.addAll(specialUidList); + + if (uidList.size() == 0) { + Collections.shuffle(otherUidList); + uidList.addAll(otherUidList); + } + + boolean first = true; + long remainingBytes = totalBytes; + for (int uid : uidList) { + final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked( + ident, uid, SET_DEFAULT, TAG_NONE); + final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked( + ident, uid, SET_FOREGROUND, TAG_NONE); + + final long uidBytes = totalBytes / uidList.size(); + + final float fractionDefault = r.nextFloat(); + final long defaultBytes = (long) (uidBytes * fractionDefault); + final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault)); + + defaultHistory.generateRandom(start, end, defaultBytes); + foregroundHistory.generateRandom(start, end, foregroundBytes); + + if (first) { + final long bumpTime = (start + end) / 2; + defaultHistory.recordData( + bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0); + first = false; + } + + devHistory.recordEntireHistory(defaultHistory); + devHistory.recordEntireHistory(foregroundHistory); + xtHistory.recordEntireHistory(defaultHistory); + xtHistory.recordEntireHistory(foregroundHistory); } } } From 27f58b3e2604d86b5ed414803d70490d4f22bcf8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 4 Oct 2011 16:54:49 -0700 Subject: [PATCH 0094/1150] Move battery stats to xt_qtaguid for data stats. Replace TrafficStats calls by reading values from xt_qtaguid kernel module. To keep BatteryStatsImpl changes lightweight, cache recently parsed stats. Tracks mobile ifaces from ConnectivityService. Refactor xt_qtaguid parsing into factory outside of NMS. Add stats grouping based on UID, and total based on limiting filters like iface prefix and UID. Bug: 4902271 Change-Id: I533f116c434b77f93355bf95b839e7478528505b --- core/java/android/net/NetworkStats.java | 85 +++- .../internal/net/NetworkStatsFactory.java | 379 ++++++++++++++++++ 2 files changed, 456 insertions(+), 8 deletions(-) create mode 100644 core/java/com/android/internal/net/NetworkStatsFactory.java diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e5549753cc..69ac1e71f5 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -229,6 +229,14 @@ public class NetworkStats implements Parcelable { return elapsedRealtime; } + /** + * Return age of this {@link NetworkStats} object with respect to + * {@link SystemClock#elapsedRealtime()}. + */ + public long getElapsedRealtimeAge() { + return SystemClock.elapsedRealtime() - elapsedRealtime; + } + public int size() { return size; } @@ -354,26 +362,59 @@ public class NetworkStats implements Parcelable { * Return total of all fields represented by this snapshot object. */ public Entry getTotal(Entry recycle) { + return getTotal(recycle, null, UID_ALL); + } + + /** + * Return total of all fields represented by this snapshot object matching + * the requested {@link #uid}. + */ + public Entry getTotal(Entry recycle, int limitUid) { + return getTotal(recycle, null, limitUid); + } + + /** + * Return total of all fields represented by this snapshot object matching + * the requested {@link #iface}. + */ + public Entry getTotal(Entry recycle, HashSet limitIface) { + return getTotal(recycle, limitIface, UID_ALL); + } + + /** + * Return total of all fields represented by this snapshot object matching + * the requested {@link #iface} and {@link #uid}. + * + * @param limitIface Set of {@link #iface} to include in total; or {@code + * null} to include all ifaces. + */ + private Entry getTotal(Entry recycle, HashSet limitIface, int limitUid) { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = IFACE_ALL; - entry.uid = UID_ALL; + entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; entry.rxBytes = 0; entry.rxPackets = 0; entry.txBytes = 0; entry.txPackets = 0; + entry.operations = 0; for (int i = 0; i < size; i++) { - // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; + final boolean matchesUid = (limitUid == UID_ALL) || (limitUid == uid[i]); + final boolean matchesIface = (limitIface == null) || (limitIface.contains(iface[i])); - entry.rxBytes += rxBytes[i]; - entry.rxPackets += rxPackets[i]; - entry.txBytes += txBytes[i]; - entry.txPackets += txPackets[i]; - entry.operations += operations[i]; + if (matchesUid && matchesIface) { + // skip specific tags, since already counted in TAG_NONE + if (tag[i] != TAG_NONE) continue; + + entry.rxBytes += rxBytes[i]; + entry.rxPackets += rxPackets[i]; + entry.txBytes += txBytes[i]; + entry.txPackets += txPackets[i]; + entry.operations += operations[i]; + } } return entry; } @@ -495,6 +536,34 @@ public class NetworkStats implements Parcelable { return stats; } + /** + * Return total statistics grouped by {@link #uid}; doesn't mutate the + * original structure. + */ + public NetworkStats groupedByUid() { + final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); + + final Entry entry = new Entry(); + entry.iface = IFACE_ALL; + entry.set = SET_ALL; + entry.tag = TAG_NONE; + + for (int i = 0; i < size; i++) { + // skip specific tags, since already counted in TAG_NONE + if (tag[i] != TAG_NONE) continue; + + entry.uid = uid[i]; + entry.rxBytes = rxBytes[i]; + entry.rxPackets = rxPackets[i]; + entry.txBytes = txBytes[i]; + entry.txPackets = txPackets[i]; + entry.operations = operations[i]; + stats.combineValues(entry); + } + + return stats; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java new file mode 100644 index 0000000000..ee3f23b26e --- /dev/null +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.net; + +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static com.android.server.NetworkManagementSocketTagger.kernelToTag; + +import android.net.NetworkStats; +import android.os.SystemClock; +import android.util.Slog; + +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; +import com.google.android.collect.Sets; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.StringTokenizer; + +import libcore.io.IoUtils; + +/** + * Creates {@link NetworkStats} instances by parsing various {@code /proc/} + * files as needed. + */ +public class NetworkStatsFactory { + private static final String TAG = "NetworkStatsFactory"; + + // TODO: consider moving parsing to native code + + /** Path to {@code /proc/net/dev}. */ + @Deprecated + private final File mStatsIface; + /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */ + @Deprecated + private final File mStatsXtIface; + /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ + private final File mStatsXtIfaceAll; + /** Path to {@code /proc/net/xt_qtaguid/stats}. */ + private final File mStatsXtUid; + + /** {@link #mStatsXtUid} and {@link #mStatsXtIfaceAll} headers. */ + private static final String KEY_IDX = "idx"; + private static final String KEY_IFACE = "iface"; + private static final String KEY_ACTIVE = "active"; + private static final String KEY_UID = "uid_tag_int"; + private static final String KEY_COUNTER_SET = "cnt_set"; + private static final String KEY_TAG_HEX = "acct_tag_hex"; + private static final String KEY_SNAP_RX_BYTES = "snap_rx_bytes"; + private static final String KEY_SNAP_RX_PACKETS = "snap_rx_packets"; + private static final String KEY_SNAP_TX_BYTES = "snap_tx_bytes"; + private static final String KEY_SNAP_TX_PACKETS = "snap_tx_packets"; + private static final String KEY_RX_BYTES = "rx_bytes"; + private static final String KEY_RX_PACKETS = "rx_packets"; + private static final String KEY_TX_BYTES = "tx_bytes"; + private static final String KEY_TX_PACKETS = "tx_packets"; + + public NetworkStatsFactory() { + this(new File("/proc/")); + } + + // @VisibleForTesting + public NetworkStatsFactory(File procRoot) { + mStatsIface = new File(procRoot, "net/dev"); + mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); + mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat"); + mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); + } + + /** + * Parse and return interface-level summary {@link NetworkStats}. Values + * monotonically increase since device boot, and may include details about + * inactive interfaces. + * + * @throws IllegalStateException when problem parsing stats. + */ + public NetworkStats readNetworkStatsSummary() throws IllegalStateException { + if (mStatsXtIfaceAll.exists()) { + return readNetworkStatsSummarySingleFile(); + } else { + return readNetworkStatsSummaryMultipleFiles(); + } + } + + private NetworkStats readNetworkStatsSummarySingleFile() { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + + // TODO: read directly from proc once headers are added + final ArrayList keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES, + KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES, + KEY_RX_PACKETS, KEY_TX_BYTES, KEY_TX_PACKETS); + final ArrayList values = Lists.newArrayList(); + final HashMap parsed = Maps.newHashMap(); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(mStatsXtIfaceAll)); + + String line; + while ((line = reader.readLine()) != null) { + splitLine(line, values); + parseLine(keys, values, parsed); + + entry.iface = parsed.get(KEY_IFACE); + entry.uid = UID_ALL; + entry.set = SET_DEFAULT; + entry.tag = TAG_NONE; + + // always include snapshot values + entry.rxBytes = getParsedLong(parsed, KEY_SNAP_RX_BYTES); + entry.rxPackets = getParsedLong(parsed, KEY_SNAP_RX_PACKETS); + entry.txBytes = getParsedLong(parsed, KEY_SNAP_TX_BYTES); + entry.txPackets = getParsedLong(parsed, KEY_SNAP_TX_PACKETS); + + // fold in active numbers, but only when active + final boolean active = getParsedInt(parsed, KEY_ACTIVE) != 0; + if (active) { + entry.rxBytes += getParsedLong(parsed, KEY_RX_BYTES); + entry.rxPackets += getParsedLong(parsed, KEY_RX_PACKETS); + entry.txBytes += getParsedLong(parsed, KEY_TX_BYTES); + entry.txPackets += getParsedLong(parsed, KEY_TX_PACKETS); + } + + stats.addValues(entry); + } + } catch (NullPointerException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } catch (NumberFormatException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } catch (IOException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } finally { + IoUtils.closeQuietly(reader); + } + return stats; + } + + /** + * @deprecated remove once {@code iface_stat_all} is merged to all kernels. + */ + @Deprecated + private NetworkStats readNetworkStatsSummaryMultipleFiles() { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + + final HashSet knownIfaces = Sets.newHashSet(); + final HashSet activeIfaces = Sets.newHashSet(); + + // collect any historical stats and active state + for (String iface : fileListWithoutNull(mStatsXtIface)) { + final File ifacePath = new File(mStatsXtIface, iface); + + final long active = readSingleLongFromFile(new File(ifacePath, "active")); + if (active == 1) { + knownIfaces.add(iface); + activeIfaces.add(iface); + } else if (active == 0) { + knownIfaces.add(iface); + } else { + continue; + } + + entry.iface = iface; + entry.uid = UID_ALL; + entry.set = SET_DEFAULT; + entry.tag = TAG_NONE; + entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes")); + entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets")); + entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes")); + entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets")); + + stats.addValues(entry); + } + + final ArrayList values = Lists.newArrayList(); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(mStatsIface)); + + // skip first two header lines + reader.readLine(); + reader.readLine(); + + // parse remaining lines + String line; + while ((line = reader.readLine()) != null) { + splitLine(line, values); + + try { + entry.iface = values.get(0); + entry.uid = UID_ALL; + entry.set = SET_DEFAULT; + entry.tag = TAG_NONE; + entry.rxBytes = Long.parseLong(values.get(1)); + entry.rxPackets = Long.parseLong(values.get(2)); + entry.txBytes = Long.parseLong(values.get(9)); + entry.txPackets = Long.parseLong(values.get(10)); + + if (activeIfaces.contains(entry.iface)) { + // combine stats when iface is active + stats.combineValues(entry); + } else if (!knownIfaces.contains(entry.iface)) { + // add stats when iface is unknown + stats.addValues(entry); + } + } catch (NumberFormatException e) { + Slog.w(TAG, "problem parsing stats row '" + line + "': " + e); + } + } + } catch (NullPointerException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } catch (NumberFormatException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } catch (IOException e) { + throw new IllegalStateException("problem parsing stats: " + e); + } finally { + IoUtils.closeQuietly(reader); + } + + return stats; + } + + public NetworkStats readNetworkStatsDetail() { + return readNetworkStatsDetail(UID_ALL); + } + + /** + * Parse and return {@link NetworkStats} with UID-level details. Values + * monotonically increase since device boot. + * + * @throws IllegalStateException when problem parsing stats. + */ + public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + + // TODO: remove knownLines check once 5087722 verified + final HashSet knownLines = Sets.newHashSet(); + // TODO: remove lastIdx check once 5270106 verified + int lastIdx; + + final ArrayList keys = Lists.newArrayList(); + final ArrayList values = Lists.newArrayList(); + final HashMap parsed = Maps.newHashMap(); + + BufferedReader reader = null; + String line = null; + try { + reader = new BufferedReader(new FileReader(mStatsXtUid)); + + // parse first line as header + line = reader.readLine(); + splitLine(line, keys); + lastIdx = 1; + + // parse remaining lines + while ((line = reader.readLine()) != null) { + splitLine(line, values); + parseLine(keys, values, parsed); + + if (!knownLines.add(line)) { + throw new IllegalStateException("duplicate proc entry: " + line); + } + + final int idx = getParsedInt(parsed, KEY_IDX); + if (idx != lastIdx + 1) { + throw new IllegalStateException( + "inconsistent idx=" + idx + " after lastIdx=" + lastIdx); + } + lastIdx = idx; + + entry.iface = parsed.get(KEY_IFACE); + entry.uid = getParsedInt(parsed, KEY_UID); + entry.set = getParsedInt(parsed, KEY_COUNTER_SET); + entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX)); + entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES); + entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS); + entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES); + entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS); + + if (limitUid == UID_ALL || limitUid == entry.uid) { + stats.addValues(entry); + } + } + } catch (NullPointerException e) { + throw new IllegalStateException("problem parsing line: " + line, e); + } catch (NumberFormatException e) { + throw new IllegalStateException("problem parsing line: " + line, e); + } catch (IOException e) { + throw new IllegalStateException("problem parsing line: " + line, e); + } finally { + IoUtils.closeQuietly(reader); + } + return stats; + } + + private static int getParsedInt(HashMap parsed, String key) { + final String value = parsed.get(key); + return value != null ? Integer.parseInt(value) : 0; + } + + private static long getParsedLong(HashMap parsed, String key) { + final String value = parsed.get(key); + return value != null ? Long.parseLong(value) : 0; + } + + /** + * Split given line into {@link ArrayList}. + */ + private static void splitLine(String line, ArrayList outSplit) { + outSplit.clear(); + + final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:"); + while (t.hasMoreTokens()) { + outSplit.add(t.nextToken()); + } + } + + /** + * Zip the two given {@link ArrayList} as key and value pairs into + * {@link HashMap}. + */ + private static void parseLine( + ArrayList keys, ArrayList values, HashMap outParsed) { + outParsed.clear(); + + final int size = Math.min(keys.size(), values.size()); + for (int i = 0; i < size; i++) { + outParsed.put(keys.get(i), values.get(i)); + } + } + + /** + * Utility method to read a single plain-text {@link Long} from the given + * {@link File}, usually from a {@code /proc/} filesystem. + */ + private static long readSingleLongFromFile(File file) { + try { + final byte[] buffer = IoUtils.readFileAsByteArray(file.toString()); + return Long.parseLong(new String(buffer).trim()); + } catch (NumberFormatException e) { + return -1; + } catch (IOException e) { + return -1; + } + } + + /** + * Wrapper for {@link File#list()} that returns empty array instead of + * {@code null}. + */ + private static String[] fileListWithoutNull(File file) { + final String[] list = file.list(); + return list != null ? list : new String[0]; + } +} From 92c7838ca310b1b2cda146b0099da72624068b21 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 14 Oct 2011 18:32:24 -0700 Subject: [PATCH 0095/1150] Validate commands and arguments. Bug: 5465176 Change-Id: I9402054c20ea6cae42781c35bfc2ade90aac31ce --- .../java/com/android/server/NativeDaemonConnector.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 43d938cea3..28013bd7b3 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -207,6 +207,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ private void sendCommandLocked(String command, String argument) throws NativeDaemonConnectorException { + if (command != null && command.indexOf('\0') >= 0) { + throw new IllegalArgumentException("unexpected command: " + command); + } + if (argument != null && argument.indexOf('\0') >= 0) { + throw new IllegalArgumentException("unexpected argument: " + argument); + } + if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); if (mOutputStream == null) { Slog.e(TAG, "No connection to daemon", new IllegalStateException()); From 061658c2c7f62cdaa88a4cad4d026e99638f4d0f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 1 Nov 2011 11:51:27 -0700 Subject: [PATCH 0096/1150] Add cdma_rmnet4 to list of monitored interfaces Lets the data traffic arrows work on LTE device on 1x, but also lets telephony monitor for hung radios on 1X. bug:5531630 Change-Id: I9fa25a5223afaa2e37373668c899ac28a95783fa --- core/jni/android_net_TrafficStats.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index c22b07138c..7a61432262 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -68,6 +68,7 @@ static const char* mobile_iface_list[] = { "rmnet1", "rmnet2", "rmnet3", + "cdma_rmnet4", "ppp0", 0 }; From cd5559a8567656818cdb9214551d430b83dedcde Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 31 Oct 2011 16:37:52 -0700 Subject: [PATCH 0097/1150] Correct proc file reader, optimizations. Moved away from BufferedReader, which only reads the first 8KB of some proc files because it aggresively fills its buffer. Optimized proc parsing, now double the speed. Tests to cover. Log when NetworkStats counters roll backwards when subtracting, and optimizations around findIndex(). When system removes UID, also remove from last stats snapshot to avoid xt counters from rolling backwards. Bug: 5472949, 5458380 Change-Id: I07c08fe5233156fac2b84450f6291868bf9bfaf2 --- core/java/android/net/NetworkStats.java | 121 ++++++++++-------- core/java/android/net/TrafficStats.java | 16 ++- .../internal/net/NetworkStatsFactory.java | 66 +++++----- .../server/net/NetworkStatsService.java | 59 +++++++-- 4 files changed, 155 insertions(+), 107 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 69ac1e71f5..5c6ef1a9ea 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,10 +16,11 @@ package android.net; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.util.Log; import android.util.SparseBooleanArray; import com.android.internal.util.Objects; @@ -54,6 +55,8 @@ public class NetworkStats implements Parcelable { /** {@link #tag} value for total data across all tags. */ public static final int TAG_NONE = 0; + // TODO: move fields to "mVariable" notation + /** * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. @@ -295,8 +298,33 @@ public class NetworkStats implements Parcelable { */ public int findIndex(String iface, int uid, int set, int tag) { for (int i = 0; i < size; i++) { - if (Objects.equal(iface, this.iface[i]) && uid == this.uid[i] && set == this.set[i] - && tag == this.tag[i]) { + if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] + && Objects.equal(iface, this.iface[i])) { + return i; + } + } + return -1; + } + + /** + * Find first stats index that matches the requested parameters, starting + * search around the hinted index as an optimization. + */ + // @VisibleForTesting + public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) { + for (int offset = 0; offset < size; offset++) { + final int halfOffset = offset / 2; + + // search outwards from hint index, alternating forward and backward + final int i; + if (offset % 2 == 0) { + i = (hintIndex + halfOffset) % size; + } else { + i = (size + hintIndex - halfOffset - 1) % size; + } + + if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] + && Objects.equal(iface, this.iface[i])) { return i; } } @@ -423,40 +451,10 @@ public class NetworkStats implements Parcelable { * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. - * - * @throws IllegalArgumentException when given {@link NetworkStats} is - * non-monotonic. */ - public NetworkStats subtract(NetworkStats value) { - return subtract(value, true, false); - } - - /** - * Subtract the given {@link NetworkStats}, effectively leaving the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - *

- * Instead of throwing when counters are non-monotonic, this variant clamps - * results to never be negative. - */ - public NetworkStats subtractClamped(NetworkStats value) { - return subtract(value, false, true); - } - - /** - * Subtract the given {@link NetworkStats}, effectively leaving the delta - * between two snapshots in time. Assumes that statistics rows collect over - * time, and that none of them have disappeared. - * - * @param enforceMonotonic Validate that incoming value is strictly - * monotonic compared to this object. - * @param clampNegative Instead of throwing like {@code enforceMonotonic}, - * clamp resulting counters at 0 to prevent negative values. - */ - private NetworkStats subtract( - NetworkStats value, boolean enforceMonotonic, boolean clampNegative) { + public NetworkStats subtract(NetworkStats value) throws NonMonotonicException { final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; - if (enforceMonotonic && deltaRealtime < 0) { + if (deltaRealtime < 0) { throw new IllegalArgumentException("found non-monotonic realtime"); } @@ -470,7 +468,7 @@ public class NetworkStats implements Parcelable { entry.tag = tag[i]; // find remote row that matches, and subtract - final int j = value.findIndex(entry.iface, entry.uid, entry.set, entry.tag); + final int j = value.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = rxBytes[i]; @@ -485,20 +483,10 @@ public class NetworkStats implements Parcelable { entry.txBytes = txBytes[i] - value.txBytes[j]; entry.txPackets = txPackets[i] - value.txPackets[j]; entry.operations = operations[i] - value.operations[j]; - if (enforceMonotonic - && (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 - || entry.txPackets < 0 || entry.operations < 0)) { - Log.v(TAG, "lhs=" + this); - Log.v(TAG, "rhs=" + value); - throw new IllegalArgumentException( - "found non-monotonic values at lhs[" + i + "] - rhs[" + j + "]"); - } - if (clampNegative) { - entry.rxBytes = Math.max(0, entry.rxBytes); - entry.rxPackets = Math.max(0, entry.rxPackets); - entry.txBytes = Math.max(0, entry.txBytes); - entry.txPackets = Math.max(0, entry.txPackets); - entry.operations = Math.max(0, entry.operations); + + if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 + || entry.txPackets < 0 || entry.operations < 0) { + throw new NonMonotonicException(this, i, value, j); } } @@ -564,6 +552,24 @@ public class NetworkStats implements Parcelable { return stats; } + /** + * Return all rows except those attributed to the requested UID; doesn't + * mutate the original structure. + */ + public NetworkStats withoutUid(int uid) { + final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); + + Entry entry = new Entry(); + for (int i = 0; i < size; i++) { + entry = getValues(i, entry); + if (entry.uid != uid) { + stats.addValues(entry); + } + } + + return stats; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); @@ -625,4 +631,19 @@ public class NetworkStats implements Parcelable { return new NetworkStats[size]; } }; + + public static class NonMonotonicException extends Exception { + public final NetworkStats left; + public final NetworkStats right; + public final int leftIndex; + public final int rightIndex; + + public NonMonotonicException( + NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) { + this.left = checkNotNull(left, "missing left"); + this.right = checkNotNull(right, "missing right"); + this.leftIndex = leftIndex; + this.rightIndex = rightIndex; + } + } } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 18eb9f69da..cd585b20d0 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,6 +20,7 @@ import android.app.DownloadManager; import android.app.backup.BackupManager; import android.content.Context; import android.media.MediaPlayer; +import android.net.NetworkStats.NonMonotonicException; import android.os.RemoteException; import android.os.ServiceManager; @@ -192,12 +193,15 @@ public class TrafficStats { throw new IllegalStateException("not profiling data"); } - // subtract starting values and return delta - final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); - final NetworkStats profilingDelta = profilingStop.subtractClamped( - sActiveProfilingStart); - sActiveProfilingStart = null; - return profilingDelta; + try { + // subtract starting values and return delta + final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); + final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart); + sActiveProfilingStart = null; + return profilingDelta; + } catch (NonMonotonicException e) { + throw new RuntimeException(e); + } } } diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index ee3f23b26e..41993c4128 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -25,12 +25,14 @@ import android.net.NetworkStats; import android.os.SystemClock; import android.util.Slog; +import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; import java.io.BufferedReader; import java.io.File; +import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; @@ -107,6 +109,7 @@ public class NetworkStatsFactory { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); + // TODO: transition to ProcFileReader // TODO: read directly from proc once headers are added final ArrayList keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES, KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES, @@ -257,71 +260,58 @@ public class NetworkStatsFactory { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); final NetworkStats.Entry entry = new NetworkStats.Entry(); - // TODO: remove knownLines check once 5087722 verified - final HashSet knownLines = Sets.newHashSet(); - // TODO: remove lastIdx check once 5270106 verified - int lastIdx; + int idx = 1; + int lastIdx = 1; - final ArrayList keys = Lists.newArrayList(); - final ArrayList values = Lists.newArrayList(); - final HashMap parsed = Maps.newHashMap(); - - BufferedReader reader = null; - String line = null; + ProcFileReader reader = null; try { - reader = new BufferedReader(new FileReader(mStatsXtUid)); + // open and consume header line + reader = new ProcFileReader(new FileInputStream(mStatsXtUid)); + reader.finishLine(); - // parse first line as header - line = reader.readLine(); - splitLine(line, keys); - lastIdx = 1; - - // parse remaining lines - while ((line = reader.readLine()) != null) { - splitLine(line, values); - parseLine(keys, values, parsed); - - if (!knownLines.add(line)) { - throw new IllegalStateException("duplicate proc entry: " + line); - } - - final int idx = getParsedInt(parsed, KEY_IDX); + while (reader.hasMoreData()) { + idx = reader.nextInt(); if (idx != lastIdx + 1) { throw new IllegalStateException( "inconsistent idx=" + idx + " after lastIdx=" + lastIdx); } lastIdx = idx; - entry.iface = parsed.get(KEY_IFACE); - entry.uid = getParsedInt(parsed, KEY_UID); - entry.set = getParsedInt(parsed, KEY_COUNTER_SET); - entry.tag = kernelToTag(parsed.get(KEY_TAG_HEX)); - entry.rxBytes = getParsedLong(parsed, KEY_RX_BYTES); - entry.rxPackets = getParsedLong(parsed, KEY_RX_PACKETS); - entry.txBytes = getParsedLong(parsed, KEY_TX_BYTES); - entry.txPackets = getParsedLong(parsed, KEY_TX_PACKETS); + entry.iface = reader.nextString(); + entry.tag = kernelToTag(reader.nextString()); + entry.uid = reader.nextInt(); + entry.set = reader.nextInt(); + entry.rxBytes = reader.nextLong(); + entry.rxPackets = reader.nextLong(); + entry.txBytes = reader.nextLong(); + entry.txPackets = reader.nextLong(); if (limitUid == UID_ALL || limitUid == entry.uid) { stats.addValues(entry); } + + reader.finishLine(); } } catch (NullPointerException e) { - throw new IllegalStateException("problem parsing line: " + line, e); + throw new IllegalStateException("problem parsing idx " + idx, e); } catch (NumberFormatException e) { - throw new IllegalStateException("problem parsing line: " + line, e); + throw new IllegalStateException("problem parsing idx " + idx, e); } catch (IOException e) { - throw new IllegalStateException("problem parsing line: " + line, e); + throw new IllegalStateException("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); } + return stats; } + @Deprecated private static int getParsedInt(HashMap parsed, String key) { final String value = parsed.get(key); return value != null ? Integer.parseInt(value) : 0; } + @Deprecated private static long getParsedLong(HashMap parsed, String key) { final String value = parsed.get(key); return value != null ? Long.parseLong(value) : 0; @@ -330,6 +320,7 @@ public class NetworkStatsFactory { /** * Split given line into {@link ArrayList}. */ + @Deprecated private static void splitLine(String line, ArrayList outSplit) { outSplit.clear(); @@ -343,6 +334,7 @@ public class NetworkStatsFactory { * Zip the two given {@link ArrayList} as key and value pairs into * {@link HashMap}. */ + @Deprecated private static void parseLine( ArrayList keys, ArrayList values, HashMap outParsed) { outParsed.clear(); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 789681e569..494c655ba0 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -32,7 +32,6 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.randomLong; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; import static android.net.TrafficStats.UID_REMOVED; @@ -49,7 +48,6 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -73,9 +71,11 @@ import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; +import android.net.NetworkStats.NonMonotonicException; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.Binder; +import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; @@ -150,6 +150,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Sample recent usage after each poll event. */ private static final boolean ENABLE_SAMPLE_AFTER_POLL = true; + private static final String TAG_NETSTATS_ERROR = "netstats_error"; + + private static final String DEV = "dev"; + private static final String XT = "xt"; + private static final String UID = "uid"; + private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -160,6 +166,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final PowerManager.WakeLock mWakeLock; private IConnectivityManager mConnManager; + private DropBoxManager mDropBox; // @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = @@ -306,6 +313,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // bootstrap initial stats to prevent double-counting later bootstrapStats(); + + mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); } private void shutdownLocked() { @@ -621,7 +630,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // broadcast. final int uid = intent.getIntExtra(EXTRA_UID, 0); synchronized (mStatsLock) { - // TODO: perform one last stats poll for UID mWakeLock.acquire(); try { removeUidLocked(uid); @@ -829,9 +837,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough network data has occurred final long persistNetworkDevDelta = computeStatsDelta( - mLastPersistNetworkDevSnapshot, networkDevSnapshot, true).getTotalBytes(); + mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, DEV).getTotalBytes(); final long persistNetworkXtDelta = computeStatsDelta( - mLastPersistNetworkXtSnapshot, networkXtSnapshot, true).getTotalBytes(); + mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, XT).getTotalBytes(); final boolean networkOverThreshold = persistNetworkDevDelta > threshold || persistNetworkXtDelta > threshold; if (persistForce || (persistNetwork && networkOverThreshold)) { @@ -842,8 +850,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // persist when enough uid data has occurred - final long persistUidDelta = computeStatsDelta(mLastPersistUidSnapshot, uidSnapshot, true) - .getTotalBytes(); + final long persistUidDelta = computeStatsDelta( + mLastPersistUidSnapshot, uidSnapshot, true, UID).getTotalBytes(); if (persistForce || (persistUid && persistUidDelta > threshold)) { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; @@ -872,7 +880,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkDevSnapshot, networkDevSnapshot, false); + mLastPollNetworkDevSnapshot, networkDevSnapshot, false, DEV); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -902,7 +910,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkXtSnapshot, networkXtSnapshot, false); + mLastPollNetworkXtSnapshot, networkXtSnapshot, false, XT); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -931,9 +939,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { ensureUidStatsLoadedLocked(); - final NetworkStats delta = computeStatsDelta(mLastPollUidSnapshot, uidSnapshot, false); + final NetworkStats delta = computeStatsDelta( + mLastPollUidSnapshot, uidSnapshot, false, UID); final NetworkStats operationsDelta = computeStatsDelta( - mLastPollOperationsSnapshot, mOperations, false); + mLastPollOperationsSnapshot, mOperations, false, UID); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -1014,6 +1023,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void removeUidLocked(int uid) { ensureUidStatsLoadedLocked(); + // perform one last poll before removing + performPollLocked(FLAG_PERSIST_ALL); + final ArrayList knownKeys = Lists.newArrayList(); knownKeys.addAll(mUidStats.keySet()); @@ -1031,6 +1043,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // clear UID from current stats snapshot + mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid); + mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); + // clear kernel stats associated with UID resetKernelUidStats(uid); @@ -1490,10 +1506,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return the delta between two {@link NetworkStats} snapshots, where {@code * before} can be {@code null}. */ - private static NetworkStats computeStatsDelta( - NetworkStats before, NetworkStats current, boolean collectStale) { + private NetworkStats computeStatsDelta( + NetworkStats before, NetworkStats current, boolean collectStale, String type) { if (before != null) { - return current.subtractClamped(before); + try { + return current.subtract(before); + } catch (NonMonotonicException e) { + Log.w(TAG, "found non-monotonic values; saving to dropbox"); + + // record error for debugging + final StringBuilder builder = new StringBuilder(); + builder.append("found non-monotonic " + type + "values at left[" + e.leftIndex + + "] - right[" + e.rightIndex + "]\n"); + builder.append("left=").append(e.left).append('\n'); + builder.append("right=").append(e.right).append('\n'); + mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); + + // return empty delta to avoid recording broken stats + return new NetworkStats(0L, 10); + } } else if (collectStale) { // caller is okay collecting stale stats for first call. return current; From e2de8f08d45b2c384a266108489387316e750a87 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 8 Nov 2011 17:35:28 -0800 Subject: [PATCH 0098/1150] Make operation counts monotonically increase. Bug: 5585704 Change-Id: I5247a68acdb209a4ef0f5aac18944595c295e6ca --- core/java/android/net/NetworkStats.java | 11 +++++++++++ .../com/android/server/net/NetworkStatsService.java | 3 +-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 5c6ef1a9ea..51b290e590 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -165,6 +165,17 @@ public class NetworkStats implements Parcelable { dest.writeLongArray(operations); } + @Override + public NetworkStats clone() { + final NetworkStats clone = new NetworkStats(elapsedRealtime, size); + NetworkStats.Entry entry = null; + for (int i = 0; i < size; i++) { + entry = getValues(i, entry); + clone.addValues(entry); + } + return clone; + } + // @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 494c655ba0..4f87f0d190 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -971,8 +971,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mLastPollUidSnapshot = uidSnapshot; - mLastPollOperationsSnapshot = mOperations; - mOperations = new NetworkStats(0L, 10); + mLastPollOperationsSnapshot = mOperations.clone(); } /** From 29f15bb4b3f699dd14161afa8f308904347dccbb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 8 Nov 2011 18:08:48 -0800 Subject: [PATCH 0099/1150] Bootstrap stats before registering listeners. Also move ISE to handled NonMonotonicException. Bug: 5570872 Change-Id: I793f349287ef5589185f117dfbec6f1fad73a661 --- core/java/android/net/NetworkStats.java | 9 +++++-- .../server/net/NetworkStatsService.java | 26 ++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 5c6ef1a9ea..3924f136ed 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -455,7 +455,7 @@ public class NetworkStats implements Parcelable { public NetworkStats subtract(NetworkStats value) throws NonMonotonicException { final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; if (deltaRealtime < 0) { - throw new IllegalArgumentException("found non-monotonic realtime"); + throw new NonMonotonicException(this, value); } // result will have our rows, and elapsed time between snapshots @@ -575,7 +575,8 @@ public class NetworkStats implements Parcelable { pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); for (int i = 0; i < size; i++) { pw.print(prefix); - pw.print(" iface="); pw.print(iface[i]); + pw.print(" ["); pw.print(i); pw.print("]"); + pw.print(" iface="); pw.print(iface[i]); pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); @@ -638,6 +639,10 @@ public class NetworkStats implements Parcelable { public final int leftIndex; public final int rightIndex; + public NonMonotonicException(NetworkStats left, NetworkStats right) { + this(left, -1, right, -1); + } + public NonMonotonicException( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) { this.left = checkNotNull(left, "missing left"); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 494c655ba0..f948697bec 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -152,10 +152,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG_NETSTATS_ERROR = "netstats_error"; - private static final String DEV = "dev"; - private static final String XT = "xt"; - private static final String UID = "uid"; - private final Context mContext; private final INetworkManagementService mNetworkManager; private final IAlarmManager mAlarmManager; @@ -278,6 +274,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { readNetworkXtStatsLocked(); } + // bootstrap initial stats to prevent double-counting later + bootstrapStats(); + // watch for network interfaces to be claimed final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); @@ -311,9 +310,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerPollAlarmLocked(); registerGlobalAlert(); - // bootstrap initial stats to prevent double-counting later - bootstrapStats(); - mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); } @@ -837,9 +833,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough network data has occurred final long persistNetworkDevDelta = computeStatsDelta( - mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, DEV).getTotalBytes(); + mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes(); final long persistNetworkXtDelta = computeStatsDelta( - mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, XT).getTotalBytes(); + mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes(); final boolean networkOverThreshold = persistNetworkDevDelta > threshold || persistNetworkXtDelta > threshold; if (persistForce || (persistNetwork && networkOverThreshold)) { @@ -851,7 +847,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist when enough uid data has occurred final long persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true, UID).getTotalBytes(); + mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes(); if (persistForce || (persistUid && persistUidDelta > threshold)) { writeUidStatsLocked(); mLastPersistUidSnapshot = uidSnapshot; @@ -880,7 +876,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkDevSnapshot, networkDevSnapshot, false, DEV); + mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -910,7 +906,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HashSet unknownIface = Sets.newHashSet(); final NetworkStats delta = computeStatsDelta( - mLastPollNetworkXtSnapshot, networkXtSnapshot, false, XT); + mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -940,9 +936,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ensureUidStatsLoadedLocked(); final NetworkStats delta = computeStatsDelta( - mLastPollUidSnapshot, uidSnapshot, false, UID); + mLastPollUidSnapshot, uidSnapshot, false, "uid"); final NetworkStats operationsDelta = computeStatsDelta( - mLastPollOperationsSnapshot, mOperations, false, UID); + mLastPollOperationsSnapshot, mOperations, false, "uidop"); final long timeStart = currentTime - delta.getElapsedRealtime(); NetworkStats.Entry entry = null; @@ -1516,7 +1512,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // record error for debugging final StringBuilder builder = new StringBuilder(); - builder.append("found non-monotonic " + type + "values at left[" + e.leftIndex + builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex + "] - right[" + e.rightIndex + "]\n"); builder.append("left=").append(e.left).append('\n'); builder.append("right=").append(e.right).append('\n'); From 42f40436332de5660ebfb8f18efe12e106b1d5d9 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 10 Nov 2011 17:54:23 -0800 Subject: [PATCH 0100/1150] Clamp non-monotonic stats instead of dropping. When encountering non-monotonic stats rows, recover remaining data by clamping to 0. In particular, this avoids edge-case where persisting threshold checks would never trigger. Also recover when tethering snapshots are missing. Bug: 5600785, 5433871, 5600678 Change-Id: I1871954ce3955cc4ac8846f9841bae0066176ffe --- core/java/android/net/NetworkStats.java | 23 ++++++++++++++- .../server/net/NetworkStatsService.java | 29 +++++++++++++++---- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 36056529c3..f6e627c930 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -464,6 +464,19 @@ public class NetworkStats implements Parcelable { * time, and that none of them have disappeared. */ public NetworkStats subtract(NetworkStats value) throws NonMonotonicException { + return subtract(value, false); + } + + /** + * Subtract the given {@link NetworkStats}, effectively leaving the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + * + * @param clampNonMonotonic When non-monotonic stats are found, just clamp + * to 0 instead of throwing {@link NonMonotonicException}. + */ + public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic) + throws NonMonotonicException { final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; if (deltaRealtime < 0) { throw new NonMonotonicException(this, value); @@ -497,7 +510,15 @@ public class NetworkStats implements Parcelable { if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 || entry.operations < 0) { - throw new NonMonotonicException(this, i, value, j); + if (clampNonMonotonic) { + entry.rxBytes = Math.max(entry.rxBytes, 0); + entry.rxPackets = Math.max(entry.rxPackets, 0); + entry.txBytes = Math.max(entry.txBytes, 0); + entry.txPackets = Math.max(entry.txPackets, 0); + entry.operations = Math.max(entry.operations, 0); + } else { + throw new NonMonotonicException(this, i, value, j); + } } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 77b0d96f42..63655258fe 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -806,9 +806,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats networkDevSnapshot; try { // collect any tethering stats - final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); - final NetworkStats tetherSnapshot = mNetworkManager.getNetworkStatsTethering( - tetheredIfacePairs); + final NetworkStats tetherSnapshot = getNetworkStatsTethering(); // record uid stats, folding in tethering stats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); @@ -1505,7 +1503,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStats before, NetworkStats current, boolean collectStale, String type) { if (before != null) { try { - return current.subtract(before); + return current.subtract(before, false); } catch (NonMonotonicException e) { Log.w(TAG, "found non-monotonic values; saving to dropbox"); @@ -1517,8 +1515,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { builder.append("right=").append(e.right).append('\n'); mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); - // return empty delta to avoid recording broken stats - return new NetworkStats(0L, 10); + try { + // return clamped delta to help recover + return current.subtract(before, true); + } catch (NonMonotonicException e1) { + Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1); + return new NetworkStats(0L, 10); + } } } else if (collectStale) { // caller is okay collecting stale stats for first call. @@ -1530,6 +1533,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + /** + * Return snapshot of current tethering statistics. Will return empty + * {@link NetworkStats} if any problems are encountered. + */ + private NetworkStats getNetworkStatsTethering() throws RemoteException { + try { + final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); + return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs); + } catch (IllegalStateException e) { + Log.wtf(TAG, "problem reading network stats", e); + return new NetworkStats(0L, 10); + } + } + private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) { return uidSnapshot.groupedByIface(); } From ee0174da5e30bade4652d35ae6473d46ddee3e95 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 14 Nov 2011 18:02:21 -0800 Subject: [PATCH 0101/1150] Conservatively trim data usage stats. Instead of trusting NTP time alone, use the most-conservative of system clock and NTP. Bug: 5584564 Change-Id: I5dd87fc009959b1cf0a7d660e385a0b1a8be238b --- .../java/com/android/server/net/NetworkStatsService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 63655258fe..28cb983ad1 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1243,7 +1243,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // trim any history beyond max if (mTime.hasCache()) { - final long currentTime = mTime.currentTimeMillis(); + final long currentTime = Math.min( + System.currentTimeMillis(), mTime.currentTimeMillis()); final long maxHistory = mSettings.getNetworkMaxHistory(); for (NetworkStatsHistory history : input.values()) { history.removeBucketsBefore(currentTime - maxHistory); @@ -1287,7 +1288,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // trim any history beyond max if (mTime.hasCache()) { - final long currentTime = mTime.currentTimeMillis(); + final long currentTime = Math.min( + System.currentTimeMillis(), mTime.currentTimeMillis()); final long maxUidHistory = mSettings.getUidMaxHistory(); final long maxTagHistory = mSettings.getTagMaxHistory(); for (UidStatsKey key : mUidStats.keySet()) { From 344b8bfa9e64513140246dabafa00b030713aa1f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 16 Nov 2011 17:46:30 -0800 Subject: [PATCH 0102/1150] Update NTP outside locks, log large trim events. Move NTP updates outside locks to avoid blocking ShutdownThread. Add logging around trim events that remove substantial history. Include history start in sample events. Bug: 5627247, 5584564 Change-Id: If9bbd93842c710efcdec94e68da87e9e42a5f961 --- .../server/net/NetworkStatsService.java | 52 +++++++++++++++---- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 28cb983ad1..b77e67e0fd 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -472,6 +472,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private long getHistoryStartLocked( + NetworkTemplate template, HashMap source) { + long start = Long.MAX_VALUE; + for (NetworkIdentitySet ident : source.keySet()) { + if (templateMatches(template, ident)) { + final NetworkStatsHistory history = source.get(ident); + start = Math.min(start, history.getStart()); + } + } + return start; + } + @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { @@ -771,6 +783,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performPoll(int flags) { synchronized (mStatsLock) { mWakeLock.acquire(); + + // try refreshing time source when stale + if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { + mTime.forceRefresh(); + } + try { performPollLocked(flags); } finally { @@ -791,11 +809,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; - // try refreshing time source when stale - if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { - mTime.forceRefresh(); - } - // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); @@ -981,6 +994,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long start = end - largestBucketSize; final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; + long devHistoryStart = Long.MAX_VALUE; NetworkTemplate template = null; NetworkStats.Entry devTotal = null; @@ -990,24 +1004,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // collect mobile sample template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); + devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats); xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); + EventLogTags.writeNetstatsMobileSample( devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + trustedTime, devHistoryStart); // collect wifi sample template = buildTemplateWifi(); devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); + devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats); xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); EventLogTags.writeNetstatsWifiSample( devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + trustedTime, devHistoryStart); } /** @@ -1243,11 +1260,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // trim any history beyond max if (mTime.hasCache()) { - final long currentTime = Math.min( - System.currentTimeMillis(), mTime.currentTimeMillis()); + final long systemCurrentTime = System.currentTimeMillis(); + final long trustedCurrentTime = mTime.currentTimeMillis(); + + final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime); final long maxHistory = mSettings.getNetworkMaxHistory(); + for (NetworkStatsHistory history : input.values()) { + final int beforeSize = history.size(); history.removeBucketsBefore(currentTime - maxHistory); + final int afterSize = history.size(); + + if (beforeSize > 24 && afterSize < beforeSize / 2) { + // yikes, dropping more than half of significant history + final StringBuilder builder = new StringBuilder(); + builder.append("yikes, dropping more than half of history").append('\n'); + builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n'); + builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n'); + builder.append("maxHistory=").append(maxHistory).append('\n'); + builder.append("beforeSize=").append(beforeSize).append('\n'); + builder.append("afterSize=").append(afterSize).append('\n'); + mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); + } } } From 7047ec62ab82d68d6ef612348db4ec1f31edcc33 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 17 Nov 2011 11:59:29 -0800 Subject: [PATCH 0103/1150] Only write network stats when already loaded. Bug: 5584564 Change-Id: Ife2a68804bf3691e9bccdc167807204bce8a85b2 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index b77e67e0fd..871ed682e6 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -203,6 +203,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of historical {@code xtables} stats for known UIDs. */ private HashMap mUidStats = Maps.newHashMap(); + /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */ + private boolean mNetworkStatsLoaded = false; /** Flag if {@link #mUidStats} have been loaded from disk. */ private boolean mUidStatsLoaded = false; @@ -272,6 +274,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // until actually needed. readNetworkDevStatsLocked(); readNetworkXtStatsLocked(); + mNetworkStatsLoaded = true; } // bootstrap initial stats to prevent double-counting later @@ -322,14 +325,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mTeleManager.listen(mPhoneListener, LISTEN_NONE); - writeNetworkDevStatsLocked(); - writeNetworkXtStatsLocked(); + if (mNetworkStatsLoaded) { + writeNetworkDevStatsLocked(); + writeNetworkXtStatsLocked(); + } if (mUidStatsLoaded) { writeUidStatsLocked(); } mNetworkDevStats.clear(); mNetworkXtStats.clear(); mUidStats.clear(); + mNetworkStatsLoaded = false; mUidStatsLoaded = false; } From cd257fbaafc16e5322cee5ff5f80ef74214639ff Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 18 Nov 2011 17:09:01 -0800 Subject: [PATCH 0104/1150] Move NativeDaemonConnector to varargs. Perform uniform argument escaping inside NativeDaemonConnector, using varargs to separate boundaries. Also move to parsed NativeDaemonEvent instances instead of raw Strings. Bug: 5472606 Change-Id: I1270733e2b2eeb2f6b810240df82ab24d38ebf40 --- .../android/server/NativeDaemonConnector.java | 319 ++++++++++-------- .../NativeDaemonConnectorException.java | 38 ++- .../com/android/server/NativeDaemonEvent.java | 113 +++++++ .../server/NativeDaemonConnectorTest.java | 70 ++++ 4 files changed, 380 insertions(+), 160 deletions(-) create mode 100644 services/java/com/android/server/NativeDaemonEvent.java create mode 100644 services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 28013bd7b3..1e98f938fc 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -24,6 +24,8 @@ import android.os.Message; import android.os.SystemClock; import android.util.Slog; +import com.google.android.collect.Lists; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -32,49 +34,33 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; /** - * Generic connector class for interfacing with a native - * daemon which uses the libsysutils FrameworkListener - * protocol. + * Generic connector class for interfacing with a native daemon which uses the + * {@code libsysutils} FrameworkListener protocol. */ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { - private static final boolean LOCAL_LOGD = false; + private static final boolean LOGD = false; + + private final String TAG; + + private String mSocket; + private OutputStream mOutputStream; + + private final BlockingQueue mResponseQueue; - private BlockingQueue mResponseQueue; - private OutputStream mOutputStream; - private String TAG = "NativeDaemonConnector"; - private String mSocket; private INativeDaemonConnectorCallbacks mCallbacks; - private Handler mCallbackHandler; + private Handler mCallbackHandler; /** Lock held whenever communicating with native daemon. */ - private Object mDaemonLock = new Object(); + private final Object mDaemonLock = new Object(); private final int BUFFER_SIZE = 4096; - class ResponseCode { - public static final int ActionInitiated = 100; - - public static final int CommandOkay = 200; - - // The range of 400 -> 599 is reserved for cmd failures - public static final int OperationFailed = 400; - public static final int CommandSyntaxError = 500; - public static final int CommandParameterError = 501; - - public static final int UnsolicitedInformational = 600; - - // - public static final int FailedRangeStart = 400; - public static final int FailedRangeEnd = 599; - } - - NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, - String socket, int responseQueueSize, String logTag) { + NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, + int responseQueueSize, String logTag) { mCallbacks = callbacks; - if (logTag != null) - TAG = logTag; mSocket = socket; - mResponseQueue = new LinkedBlockingQueue(responseQueueSize); + mResponseQueue = new LinkedBlockingQueue(responseQueueSize); + TAG = logTag != null ? logTag : "NativeDaemonConnector"; } @Override @@ -136,26 +122,26 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo for (int i = 0; i < count; i++) { if (buffer[i] == 0) { - String event = new String(buffer, start, i - start); - if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event)); + final String rawEvent = new String(buffer, start, i - start); + if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent); - String[] tokens = event.split(" ", 2); try { - int code = Integer.parseInt(tokens[0]); - - if (code >= ResponseCode.UnsolicitedInformational) { - mCallbackHandler.sendMessage( - mCallbackHandler.obtainMessage(code, event)); + final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( + rawEvent); + if (event.isClassUnsolicited()) { + mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( + event.getCode(), event.getRawEvent())); } else { try { mResponseQueue.put(event); } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue", ex); + Slog.e(TAG, "Failed to put response onto queue: " + ex); } } - } catch (NumberFormatException nfe) { - Slog.w(TAG, String.format("Bad msg (%s)", event)); + } catch (IllegalArgumentException e) { + Slog.w(TAG, "Problem parsing message: " + rawEvent, e); } + start = i + 1; } } @@ -195,133 +181,174 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } - private void sendCommandLocked(String command) throws NativeDaemonConnectorException { - sendCommandLocked(command, null); - } - /** - * Sends a command to the daemon with a single argument + * Send command to daemon, escaping arguments as needed. * - * @param command The command to send to the daemon - * @param argument The argument to send with the command (or null) + * @return the final command issued. */ - private void sendCommandLocked(String command, String argument) + private String sendCommandLocked(String cmd, Object... args) throws NativeDaemonConnectorException { - if (command != null && command.indexOf('\0') >= 0) { - throw new IllegalArgumentException("unexpected command: " + command); - } - if (argument != null && argument.indexOf('\0') >= 0) { - throw new IllegalArgumentException("unexpected argument: " + argument); + // TODO: eventually enforce that cmd doesn't contain arguments + if (cmd.indexOf('\0') >= 0) { + throw new IllegalArgumentException("unexpected command: " + cmd); } - if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument)); - if (mOutputStream == null) { - Slog.e(TAG, "No connection to daemon", new IllegalStateException()); - throw new NativeDaemonConnectorException("No output stream!"); - } else { - StringBuilder builder = new StringBuilder(command); - if (argument != null) { - builder.append(argument); + final StringBuilder builder = new StringBuilder(cmd); + for (Object arg : args) { + final String argString = String.valueOf(arg); + if (argString.indexOf('\0') >= 0) { + throw new IllegalArgumentException("unexpected argument: " + arg); } - builder.append('\0'); + builder.append(' '); + appendEscaped(builder, argString); + } + + final String unterminated = builder.toString(); + if (LOGD) Slog.d(TAG, "SND -> " + unterminated); + + builder.append('\0'); + + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { try { mOutputStream.write(builder.toString().getBytes()); - } catch (IOException ex) { - Slog.e(TAG, "IOException in sendCommand", ex); - } - } - } - - /** - * Issue a command to the native daemon and return the responses - */ - public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { - synchronized (mDaemonLock) { - return doCommandLocked(cmd); - } - } - - private ArrayList doCommandLocked(String cmd) throws NativeDaemonConnectorException { - mResponseQueue.clear(); - sendCommandLocked(cmd); - - ArrayList response = new ArrayList(); - boolean complete = false; - int code = -1; - - while (!complete) { - try { - // TODO - this should not block forever - String line = mResponseQueue.take(); - if (LOCAL_LOGD) Slog.d(TAG, String.format("RSP <- {%s}", line)); - String[] tokens = line.split(" "); - try { - code = Integer.parseInt(tokens[0]); - } catch (NumberFormatException nfe) { - throw new NativeDaemonConnectorException( - String.format("Invalid response from daemon (%s)", line)); - } - - if ((code >= 200) && (code < 600)) { - complete = true; - } - response.add(line); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to process response", ex); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); } } - if (code >= ResponseCode.FailedRangeStart && - code <= ResponseCode.FailedRangeEnd) { - /* - * Note: The format of the last response in this case is - * "NNN " - */ - throw new NativeDaemonConnectorException( - code, cmd, response.get(response.size()-1).substring(4)); - } - return response; + return unterminated; } /** - * Issues a list command and returns the cooked list + * Issue a command to the native daemon and return the responses. */ - public String[] doListCommand(String cmd, int expectedResponseCode) + public NativeDaemonEvent[] execute(String cmd, Object... args) throws NativeDaemonConnectorException { + synchronized (mDaemonLock) { + return executeLocked(cmd, args); + } + } - ArrayList rsp = doCommand(cmd); - String[] rdata = new String[rsp.size()-1]; - int idx = 0; + private NativeDaemonEvent[] executeLocked(String cmd, Object... args) + throws NativeDaemonConnectorException { + final ArrayList events = Lists.newArrayList(); - for (int i = 0; i < rsp.size(); i++) { - String line = rsp.get(i); + mResponseQueue.clear(); + + final String sentCommand = sendCommandLocked(cmd, args); + + NativeDaemonEvent event = null; + do { try { - String[] tok = line.split(" "); - int code = Integer.parseInt(tok[0]); - if (code == expectedResponseCode) { - rdata[idx++] = line.substring(tok[0].length() + 1); - } else if (code == NativeDaemonConnector.ResponseCode.CommandOkay) { - if (LOCAL_LOGD) Slog.d(TAG, String.format("List terminated with {%s}", line)); - int last = rsp.size() -1; - if (i != last) { - Slog.w(TAG, String.format("Recv'd %d lines after end of list {%s}", (last-i), cmd)); - for (int j = i; j <= last ; j++) { - Slog.w(TAG, String.format("ExtraData <%s>", rsp.get(i))); - } - } - return rdata; - } else { - throw new NativeDaemonConnectorException( - String.format("Expected list response %d, but got %d", - expectedResponseCode, code)); - } - } catch (NumberFormatException nfe) { + event = mResponseQueue.take(); + } catch (InterruptedException e) { + Slog.w(TAG, "interrupted waiting for event line"); + continue; + } + events.add(event); + } while (event.isClassContinue()); + + if (event.isClassClientError()) { + throw new NativeDaemonArgumentException(sentCommand, event); + } + if (event.isClassServerError()) { + throw new NativeDaemonFailureException(sentCommand, event); + } + + return events.toArray(new NativeDaemonEvent[events.size()]); + } + + /** + * Issue a command to the native daemon and return the raw responses. + * + * @deprecated callers should move to {@link #execute(String, Object...)} + * which returns parsed {@link NativeDaemonEvent}. + */ + @Deprecated + public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { + final ArrayList rawEvents = Lists.newArrayList(); + final NativeDaemonEvent[] events = execute(cmd); + for (NativeDaemonEvent event : events) { + rawEvents.add(event.getRawEvent()); + } + return rawEvents; + } + + /** + * Issues a list command and returns the cooked list of all + * {@link NativeDaemonEvent#getMessage()} which match requested code. + */ + public String[] doListCommand(String cmd, int expectedCode) + throws NativeDaemonConnectorException { + final ArrayList list = Lists.newArrayList(); + + final NativeDaemonEvent[] events = execute(cmd); + for (int i = 0; i < events.length - 1; i++) { + final NativeDaemonEvent event = events[i]; + final int code = event.getCode(); + if (code == expectedCode) { + list.add(event.getMessage()); + } else { throw new NativeDaemonConnectorException( - String.format("Error reading code '%s'", line)); + "unexpected list response " + code + " instead of " + expectedCode); } } - throw new NativeDaemonConnectorException("Got an empty response"); + + final NativeDaemonEvent finalEvent = events[events.length - 1]; + if (!finalEvent.isClassOk()) { + throw new NativeDaemonConnectorException("unexpected final event: " + finalEvent); + } + + return list.toArray(new String[list.size()]); + } + + /** + * Append the given argument to {@link StringBuilder}, escaping as needed, + * and surrounding with quotes when it contains spaces. + */ + // @VisibleForTesting + static void appendEscaped(StringBuilder builder, String arg) { + final boolean hasSpaces = arg.indexOf(' ') >= 0; + if (hasSpaces) { + builder.append('"'); + } + + final int length = arg.length(); + for (int i = 0; i < length; i++) { + final char c = arg.charAt(i); + + if (c == '"') { + builder.append("\\\""); + } else if (c == '\\') { + builder.append("\\\\"); + } else { + builder.append(c); + } + } + + if (hasSpaces) { + builder.append('"'); + } + } + + private static class NativeDaemonArgumentException extends NativeDaemonConnectorException { + public NativeDaemonArgumentException(String command, NativeDaemonEvent event) { + super(command, event); + } + + @Override + public IllegalArgumentException rethrowAsParcelableException() { + throw new IllegalArgumentException(getMessage(), this); + } + } + + private static class NativeDaemonFailureException extends NativeDaemonConnectorException { + public NativeDaemonFailureException(String command, NativeDaemonEvent event) { + super(command, event); + } } /** {@inheritDoc} */ diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/java/com/android/server/NativeDaemonConnectorException.java index 426742b1e2..590bbccdbc 100644 --- a/services/java/com/android/server/NativeDaemonConnectorException.java +++ b/services/java/com/android/server/NativeDaemonConnectorException.java @@ -16,33 +16,43 @@ package com.android.server; +import android.os.Parcel; + /** - * An exception that indicates there was an error with a NativeDaemonConnector operation + * An exception that indicates there was an error with a + * {@link NativeDaemonConnector} operation. */ -public class NativeDaemonConnectorException extends RuntimeException -{ - private int mCode = -1; +public class NativeDaemonConnectorException extends Exception { private String mCmd; + private NativeDaemonEvent mEvent; - public NativeDaemonConnectorException() {} - - public NativeDaemonConnectorException(String error) - { - super(error); + public NativeDaemonConnectorException(String detailMessage) { + super(detailMessage); } - public NativeDaemonConnectorException(int code, String cmd, String error) - { - super(String.format("Cmd {%s} failed with code %d : {%s}", cmd, code, error)); - mCode = code; + public NativeDaemonConnectorException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } + + public NativeDaemonConnectorException(String cmd, NativeDaemonEvent event) { + super("command '" + cmd + "' failed with '" + event + "'"); mCmd = cmd; + mEvent = event; } public int getCode() { - return mCode; + return mEvent.getCode(); } public String getCmd() { return mCmd; } + + /** + * Rethrow as a {@link RuntimeException} subclass that is handled by + * {@link Parcel#writeException(Exception)}. + */ + public IllegalArgumentException rethrowAsParcelableException() { + throw new IllegalStateException(getMessage(), this); + } } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java new file mode 100644 index 0000000000..b1d078843d --- /dev/null +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +/** + * Parsed event from native side of {@link NativeDaemonConnector}. + */ +public class NativeDaemonEvent { + + // TODO: keep class ranges in sync with ResponseCode.h + // TODO: swap client and server error ranges to roughly mirror HTTP spec + + private final int mCode; + private final String mMessage; + private final String mRawEvent; + + private NativeDaemonEvent(int code, String message, String rawEvent) { + mCode = code; + mMessage = message; + mRawEvent = rawEvent; + } + + public int getCode() { + return mCode; + } + + public String getMessage() { + return mMessage; + } + + @Deprecated + public String getRawEvent() { + return mRawEvent; + } + + @Override + public String toString() { + return mRawEvent; + } + + /** + * Test if event represents a partial response which is continued in + * additional subsequent events. + */ + public boolean isClassContinue() { + return mCode >= 100 && mCode < 200; + } + + /** + * Test if event represents a command success. + */ + public boolean isClassOk() { + return mCode >= 200 && mCode < 300; + } + + /** + * Test if event represents a remote native daemon error. + */ + public boolean isClassServerError() { + return mCode >= 400 && mCode < 500; + } + + /** + * Test if event represents a command syntax or argument error. + */ + public boolean isClassClientError() { + return mCode >= 500 && mCode < 600; + } + + /** + * Test if event represents an unsolicited event from native daemon. + */ + public boolean isClassUnsolicited() { + return mCode >= 600 && mCode < 700; + } + + /** + * Parse the given raw event into {@link NativeDaemonEvent} instance. + * + * @throws IllegalArgumentException when line doesn't match format expected + * from native side. + */ + public static NativeDaemonEvent parseRawEvent(String rawEvent) { + final int splitIndex = rawEvent.indexOf(' '); + if (splitIndex == -1) { + throw new IllegalArgumentException("unable to find ' ' separator"); + } + + final int code; + try { + code = Integer.parseInt(rawEvent.substring(0, splitIndex)); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("problem parsing code", e); + } + + final String message = rawEvent.substring(splitIndex + 1); + return new NativeDaemonEvent(code, message, rawEvent); + } +} diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java new file mode 100644 index 0000000000..275d807645 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static com.android.server.NativeDaemonConnector.appendEscaped; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.MediumTest; + +/** + * Tests for {@link NativeDaemonConnector}. + */ +@MediumTest +public class NativeDaemonConnectorTest extends AndroidTestCase { + private static final String TAG = "NativeDaemonConnectorTest"; + + public void testArgumentNormal() throws Exception { + final StringBuilder builder = new StringBuilder(); + + builder.setLength(0); + appendEscaped(builder, ""); + assertEquals("", builder.toString()); + + builder.setLength(0); + appendEscaped(builder, "foo"); + assertEquals("foo", builder.toString()); + + builder.setLength(0); + appendEscaped(builder, "foo\"bar"); + assertEquals("foo\\\"bar", builder.toString()); + + builder.setLength(0); + appendEscaped(builder, "foo\\bar\\\"baz"); + assertEquals("foo\\\\bar\\\\\\\"baz", builder.toString()); + } + + public void testArgumentWithSpaces() throws Exception { + final StringBuilder builder = new StringBuilder(); + + builder.setLength(0); + appendEscaped(builder, "foo bar"); + assertEquals("\"foo bar\"", builder.toString()); + + builder.setLength(0); + appendEscaped(builder, "foo\"bar\\baz foo"); + assertEquals("\"foo\\\"bar\\\\baz foo\"", builder.toString()); + } + + public void testArgumentWithUtf() throws Exception { + final StringBuilder builder = new StringBuilder(); + + builder.setLength(0); + appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); + assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); + } +} From 36ff7058f679e4f0ee71e753701f5edbeb115876 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 30 Nov 2011 18:13:54 -0800 Subject: [PATCH 0105/1150] Move native netd calls to varargs. Uses argument escaping inside NativeDaemonConnector, using varargs to separate boundaries. Also introduces Command object to help build argument lists. Bug: 5472606 Change-Id: I357979fc19bb0171a056e690064e01b5a7119501 --- .../android/server/NativeDaemonConnector.java | 89 +++++++++++++++++-- .../com/android/server/NativeDaemonEvent.java | 29 ++++++ 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 1e98f938fc..cc2bcd9235 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -29,6 +29,7 @@ import com.google.android.collect.Lists; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.charset.Charsets; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -122,13 +123,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo for (int i = 0; i < count; i++) { if (buffer[i] == 0) { - final String rawEvent = new String(buffer, start, i - start); + final String rawEvent = new String( + buffer, start, i - start, Charsets.UTF_8); if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent); try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( rawEvent); if (event.isClassUnsolicited()) { + // TODO: migrate to sending NativeDaemonEvent instances mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { @@ -213,7 +216,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new NativeDaemonConnectorException("missing output stream"); } else { try { - mOutputStream.write(builder.toString().getBytes()); + mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } @@ -223,9 +226,62 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** - * Issue a command to the native daemon and return the responses. + * Issue the given command to the native daemon and return a single expected + * response. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. */ - public NativeDaemonEvent[] execute(String cmd, Object... args) + public NativeDaemonEvent execute(Command cmd) throws NativeDaemonConnectorException { + return execute(cmd.mCmd, cmd.mArguments.toArray()); + } + + /** + * Issue the given command to the native daemon and return a single expected + * response. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent execute(String cmd, Object... args) + throws NativeDaemonConnectorException { + final NativeDaemonEvent[] events = executeForList(cmd, args); + if (events.length != 1) { + throw new NativeDaemonConnectorException( + "Expected exactly one response, but received " + events.length); + } + return events[0]; + } + + /** + * Issue the given command to the native daemon and return any + * {@link NativeDaemonEvent#isClassContinue()} responses, including the + * final terminal response. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent[] executeForList(Command cmd) throws NativeDaemonConnectorException { + return executeForList(cmd.mCmd, cmd.mArguments.toArray()); + } + + /** + * Issue the given command to the native daemon and return any + * {@link NativeDaemonEvent#isClassContinue()} responses, including the + * final terminal response. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { synchronized (mDaemonLock) { return executeLocked(cmd, args); @@ -270,7 +326,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo @Deprecated public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { final ArrayList rawEvents = Lists.newArrayList(); - final NativeDaemonEvent[] events = execute(cmd); + final NativeDaemonEvent[] events = executeForList(cmd); for (NativeDaemonEvent event : events) { rawEvents.add(event.getRawEvent()); } @@ -281,11 +337,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * Issues a list command and returns the cooked list of all * {@link NativeDaemonEvent#getMessage()} which match requested code. */ + @Deprecated public String[] doListCommand(String cmd, int expectedCode) throws NativeDaemonConnectorException { final ArrayList list = Lists.newArrayList(); - final NativeDaemonEvent[] events = execute(cmd); + final NativeDaemonEvent[] events = executeForList(cmd); for (int i = 0; i < events.length - 1; i++) { final NativeDaemonEvent event = events[i]; final int code = event.getCode(); @@ -351,6 +408,26 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } + /** + * Command builder that handles argument list building. + */ + public static class Command { + private String mCmd; + private ArrayList mArguments = Lists.newArrayList(); + + public Command(String cmd, Object... args) { + mCmd = cmd; + for (Object arg : args) { + appendArg(arg); + } + } + + public Command appendArg(Object arg) { + mArguments.add(arg); + return this; + } + } + /** {@inheritDoc} */ public void monitor() { synchronized (mDaemonLock) { } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index b1d078843d..62084c072a 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -16,6 +16,10 @@ package com.android.server; +import com.google.android.collect.Lists; + +import java.util.ArrayList; + /** * Parsed event from native side of {@link NativeDaemonConnector}. */ @@ -88,6 +92,17 @@ public class NativeDaemonEvent { return mCode >= 600 && mCode < 700; } + /** + * Verify this event matches the given code. + * + * @throws IllegalStateException if {@link #getCode()} doesn't match. + */ + public void checkCode(int code) { + if (mCode != code) { + throw new IllegalStateException("Expected " + code + " but was: " + this); + } + } + /** * Parse the given raw event into {@link NativeDaemonEvent} instance. * @@ -110,4 +125,18 @@ public class NativeDaemonEvent { final String message = rawEvent.substring(splitIndex + 1); return new NativeDaemonEvent(code, message, rawEvent); } + + /** + * Filter the given {@link NativeDaemonEvent} list, returning + * {@link #getMessage()} for any events matching the requested code. + */ + public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) { + final ArrayList result = Lists.newArrayList(); + for (NativeDaemonEvent event : events) { + if (event.getCode() == matchCode) { + result.add(event.getMessage()); + } + } + return result.toArray(new String[result.size()]); + } } From 3511b086bc35ad44d81828e7a8e7432bd7193c58 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 12 Dec 2011 18:51:26 -0800 Subject: [PATCH 0106/1150] Avoid NPE when missing network stats. Bug: 5750339 Change-Id: I4b739dbd076b270a5a2b2e2a1e0f6e445d8c124e --- .../java/com/android/server/net/NetworkStatsService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 871ed682e6..f6605203f5 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1060,8 +1060,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // clear UID from current stats snapshot - mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid); - mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); + if (mLastPollUidSnapshot != null) { + mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid); + mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); + } // clear kernel stats associated with UID resetKernelUidStats(uid); From 675c43125f5ded14feaae07119cd5fc8532fa622 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 13 Dec 2011 15:38:03 -0800 Subject: [PATCH 0107/1150] Avoid reading network stats when disabled. Bug: 5518868 Change-Id: Idb5c588b018bf735597ad7ff904ecc69224dd0a0 --- .../android/server/net/NetworkStatsService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 871ed682e6..a3decd5f27 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -268,6 +268,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { + if (!isBandwidthControlEnabled()) { + Slog.w(TAG, "bandwidth controls disabled, unable to track stats"); + return; + } + synchronized (mStatsLock) { // read historical network stats from disk, since policy service // might need them right away. we delay loading detailed UID stats @@ -1644,6 +1649,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return telephony.getSubscriberId(); } + private boolean isBandwidthControlEnabled() { + try { + return mNetworkManager.isBandwidthControlEnabled(); + } catch (RemoteException e) { + // ignored; service lives in system_server + return false; + } + } + /** * Key uniquely identifying a {@link NetworkStatsHistory} for a UID. */ From 41a1247dead42889141c7407540f0f6c2a61fc76 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 14 Dec 2011 10:31:54 -0800 Subject: [PATCH 0108/1150] Move NMS to CONNECTIVITY_INTERNAL permission. Change-Id: I6043c1b9cb10aeeafb93d1b5c60da571d2fec5c9 --- .../java/com/android/server/net/NetworkStatsService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 95f825cab1..6a82679516 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -548,7 +548,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: switch to data layer stats once kernel exports // for now, read network layer stats and flatten across all ifaces - final NetworkStats networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + final long token = Binder.clearCallingIdentity(); + final NetworkStats networkLayer; + try { + networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + } finally { + Binder.restoreCallingIdentity(token); + } + final NetworkStats dataLayer = new NetworkStats( networkLayer.getElapsedRealtime(), networkLayer.size()); From 307beecd4114698dacbf8d2a482d5b5953635b54 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Dec 2011 11:52:35 -0800 Subject: [PATCH 0109/1150] Include roaming in NetworkIdentity.hashCode(). Change-Id: I148d95c8d08e3916a90fa78f7efee327d4b7de2a --- core/java/android/net/NetworkIdentity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index aa6400bbf5..1a74abf26c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -45,7 +45,7 @@ public class NetworkIdentity { @Override public int hashCode() { - return Objects.hashCode(mType, mSubType, mSubscriberId); + return Objects.hashCode(mType, mSubType, mSubscriberId, mRoaming); } @Override From dc3b510b35018b5edd660dcaae314e0e5905a0f0 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 Jan 2012 19:20:56 +0000 Subject: [PATCH 0110/1150] Rename (IF_)LOGE(_IF) to (IF_)ALOGE(_IF) DO NOT MERGE See https://android-git.corp.google.com/g/#/c/157220 Bug: 5449033 Change-Id: Ic9c19d30693bd56755f55906127cd6bd7126096c --- core/jni/android_net_TrafficStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 7a61432262..0ab659b238 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -47,13 +47,13 @@ static jlong readNumber(char const* filename) { char buf[80]; int fd = open(filename, O_RDONLY); if (fd < 0) { - if (errno != ENOENT) LOGE("Can't open %s: %s", filename, strerror(errno)); + if (errno != ENOENT) ALOGE("Can't open %s: %s", filename, strerror(errno)); return -1; } int len = read(fd, buf, sizeof(buf) - 1); if (len < 0) { - LOGE("Can't read %s: %s", filename, strerror(errno)); + ALOGE("Can't read %s: %s", filename, strerror(errno)); close(fd); return -1; } @@ -101,7 +101,7 @@ static jlong readTotal(char const* suffix) { char filename[PATH_MAX] = "/sys/class/net/"; DIR *dir = opendir(filename); if (dir == NULL) { - LOGE("Can't list %s: %s", filename, strerror(errno)); + ALOGE("Can't list %s: %s", filename, strerror(errno)); return -1; } From ef7bded3470a4da2d7d74be7354e9ed9dc0eb932 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Jan 2012 17:24:44 -0800 Subject: [PATCH 0111/1150] Move non-monotonic reporting to interface. Report non-monotonic NetworkStats through an observer interface instead of throwing, since those events are still recoverable. Change-Id: Ic0749f4634b0ac05dbe90e95ca490957ec8b2f23 --- core/java/android/net/NetworkStats.java | 96 ++++++++----------- core/java/android/net/TrafficStats.java | 16 ++-- .../server/net/NetworkStatsService.java | 49 +++++----- 3 files changed, 73 insertions(+), 88 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f6e627c930..e8f60b4968 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -40,8 +38,6 @@ import java.util.HashSet; * @hide */ public class NetworkStats implements Parcelable { - private static final String TAG = "NetworkStats"; - /** {@link #iface} value when interface details unavailable. */ public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ @@ -463,62 +459,64 @@ public class NetworkStats implements Parcelable { * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. */ - public NetworkStats subtract(NetworkStats value) throws NonMonotonicException { - return subtract(value, false); + public NetworkStats subtract(NetworkStats right) { + return subtract(this, right, null); } /** - * Subtract the given {@link NetworkStats}, effectively leaving the delta + * Subtract the two given {@link NetworkStats} objects, returning the delta * between two snapshots in time. Assumes that statistics rows collect over * time, and that none of them have disappeared. - * - * @param clampNonMonotonic When non-monotonic stats are found, just clamp - * to 0 instead of throwing {@link NonMonotonicException}. + *

+ * If counters have rolled backwards, they are clamped to {@code 0} and + * reported to the given {@link NonMonotonicObserver}. */ - public NetworkStats subtract(NetworkStats value, boolean clampNonMonotonic) - throws NonMonotonicException { - final long deltaRealtime = this.elapsedRealtime - value.elapsedRealtime; + public static NetworkStats subtract( + NetworkStats left, NetworkStats right, NonMonotonicObserver observer) { + long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; if (deltaRealtime < 0) { - throw new NonMonotonicException(this, value); + if (observer != null) { + observer.foundNonMonotonic(left, -1, right, -1); + } + deltaRealtime = 0; } // result will have our rows, and elapsed time between snapshots final Entry entry = new Entry(); - final NetworkStats result = new NetworkStats(deltaRealtime, size); - for (int i = 0; i < size; i++) { - entry.iface = iface[i]; - entry.uid = uid[i]; - entry.set = set[i]; - entry.tag = tag[i]; + final NetworkStats result = new NetworkStats(deltaRealtime, left.size); + for (int i = 0; i < left.size; i++) { + entry.iface = left.iface[i]; + entry.uid = left.uid[i]; + entry.set = left.set[i]; + entry.tag = left.tag[i]; // find remote row that matches, and subtract - final int j = value.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i); + final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i); if (j == -1) { // newly appearing row, return entire value - entry.rxBytes = rxBytes[i]; - entry.rxPackets = rxPackets[i]; - entry.txBytes = txBytes[i]; - entry.txPackets = txPackets[i]; - entry.operations = operations[i]; + entry.rxBytes = left.rxBytes[i]; + entry.rxPackets = left.rxPackets[i]; + entry.txBytes = left.txBytes[i]; + entry.txPackets = left.txPackets[i]; + entry.operations = left.operations[i]; } else { // existing row, subtract remote value - entry.rxBytes = rxBytes[i] - value.rxBytes[j]; - entry.rxPackets = rxPackets[i] - value.rxPackets[j]; - entry.txBytes = txBytes[i] - value.txBytes[j]; - entry.txPackets = txPackets[i] - value.txPackets[j]; - entry.operations = operations[i] - value.operations[j]; + entry.rxBytes = left.rxBytes[i] - right.rxBytes[j]; + entry.rxPackets = left.rxPackets[i] - right.rxPackets[j]; + entry.txBytes = left.txBytes[i] - right.txBytes[j]; + entry.txPackets = left.txPackets[i] - right.txPackets[j]; + entry.operations = left.operations[i] - right.operations[j]; if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 || entry.operations < 0) { - if (clampNonMonotonic) { - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); - } else { - throw new NonMonotonicException(this, i, value, j); + if (observer != null) { + observer.foundNonMonotonic(left, i, right, j); } + entry.rxBytes = Math.max(entry.rxBytes, 0); + entry.rxPackets = Math.max(entry.rxPackets, 0); + entry.txBytes = Math.max(entry.txBytes, 0); + entry.txPackets = Math.max(entry.txPackets, 0); + entry.operations = Math.max(entry.operations, 0); } } @@ -665,22 +663,8 @@ public class NetworkStats implements Parcelable { } }; - public static class NonMonotonicException extends Exception { - public final NetworkStats left; - public final NetworkStats right; - public final int leftIndex; - public final int rightIndex; - - public NonMonotonicException(NetworkStats left, NetworkStats right) { - this(left, -1, right, -1); - } - - public NonMonotonicException( - NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) { - this.left = checkNotNull(left, "missing left"); - this.right = checkNotNull(right, "missing right"); - this.leftIndex = leftIndex; - this.rightIndex = rightIndex; - } + public interface NonMonotonicObserver { + public void foundNonMonotonic( + NetworkStats left, int leftIndex, NetworkStats right, int rightIndex); } } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index cd585b20d0..8bdb669d58 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -20,7 +20,6 @@ import android.app.DownloadManager; import android.app.backup.BackupManager; import android.content.Context; import android.media.MediaPlayer; -import android.net.NetworkStats.NonMonotonicException; import android.os.RemoteException; import android.os.ServiceManager; @@ -193,15 +192,12 @@ public class TrafficStats { throw new IllegalStateException("not profiling data"); } - try { - // subtract starting values and return delta - final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); - final NetworkStats profilingDelta = profilingStop.subtract(sActiveProfilingStart); - sActiveProfilingStart = null; - return profilingDelta; - } catch (NonMonotonicException e) { - throw new RuntimeException(e); - } + // subtract starting values and return delta + final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); + final NetworkStats profilingDelta = NetworkStats.subtract( + profilingStop, sActiveProfilingStart, null); + sActiveProfilingStart = null; + return profilingDelta; } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 6a82679516..eeb7fec8e1 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -71,7 +71,7 @@ import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicException; +import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.Binder; @@ -1551,6 +1551,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private StatsObserver mStatsObserver = new StatsObserver(); + + private class StatsObserver implements NonMonotonicObserver { + private String mCurrentType; + + public void setCurrentType(String type) { + mCurrentType = type; + } + + /** {@inheritDoc} */ + public void foundNonMonotonic( + NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) { + Log.w(TAG, "found non-monotonic values; saving to dropbox"); + + // record error for debugging + final StringBuilder builder = new StringBuilder(); + builder.append("found non-monotonic " + mCurrentType + " values at left[" + leftIndex + + "] - right[" + rightIndex + "]\n"); + builder.append("left=").append(left).append('\n'); + builder.append("right=").append(right).append('\n'); + mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); + } + } + /** * Return the delta between two {@link NetworkStats} snapshots, where {@code * before} can be {@code null}. @@ -1558,27 +1582,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats computeStatsDelta( NetworkStats before, NetworkStats current, boolean collectStale, String type) { if (before != null) { - try { - return current.subtract(before, false); - } catch (NonMonotonicException e) { - Log.w(TAG, "found non-monotonic values; saving to dropbox"); - - // record error for debugging - final StringBuilder builder = new StringBuilder(); - builder.append("found non-monotonic " + type + " values at left[" + e.leftIndex - + "] - right[" + e.rightIndex + "]\n"); - builder.append("left=").append(e.left).append('\n'); - builder.append("right=").append(e.right).append('\n'); - mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); - - try { - // return clamped delta to help recover - return current.subtract(before, true); - } catch (NonMonotonicException e1) { - Log.wtf(TAG, "found non-monotonic values; returning empty delta", e1); - return new NetworkStats(0L, 10); - } - } + mStatsObserver.setCurrentType(type); + return NetworkStats.subtract(current, before, mStatsObserver); } else if (collectStale) { // caller is okay collecting stale stats for first call. return current; From 2c14cae49e22cabf1b66ff79a05ab8af317a09d2 Mon Sep 17 00:00:00 2001 From: Steve Block Date: Fri, 6 Jan 2012 19:20:56 +0000 Subject: [PATCH 0112/1150] Rename (IF_)LOGE(_IF) to (IF_)ALOGE(_IF) Change-Id: I1de629b4632a4b3187ca1a28d6416daccd35f924 --- core/jni/android_net_TrafficStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 7a61432262..0ab659b238 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -47,13 +47,13 @@ static jlong readNumber(char const* filename) { char buf[80]; int fd = open(filename, O_RDONLY); if (fd < 0) { - if (errno != ENOENT) LOGE("Can't open %s: %s", filename, strerror(errno)); + if (errno != ENOENT) ALOGE("Can't open %s: %s", filename, strerror(errno)); return -1; } int len = read(fd, buf, sizeof(buf) - 1); if (len < 0) { - LOGE("Can't read %s: %s", filename, strerror(errno)); + ALOGE("Can't read %s: %s", filename, strerror(errno)); close(fd); return -1; } @@ -101,7 +101,7 @@ static jlong readTotal(char const* suffix) { char filename[PATH_MAX] = "/sys/class/net/"; DIR *dir = opendir(filename); if (dir == NULL) { - LOGE("Can't list %s: %s", filename, strerror(errno)); + ALOGE("Can't list %s: %s", filename, strerror(errno)); return -1; } From e3a7f729ed0e99606caea321c6f97074a21d23d5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 18 Jan 2012 12:51:15 -0800 Subject: [PATCH 0113/1150] Log netd traffic nicely. Create a LocalLog class for logging within a service for dumping in dumps. Use it in the NativeDaemonConnector so we can get some insight into what is happening in these lockups. bug:5864209 Change-Id: I68ddc58847f3c8de613be9528570f8c3157d8274 --- .../android/server/NativeDaemonConnector.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index cc2bcd9235..f475dd6e33 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -22,14 +22,17 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.SystemClock; +import android.util.LocalLog; import android.util.Slog; import com.google.android.collect.Lists; +import java.nio.charset.Charsets; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.nio.charset.Charsets; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -45,6 +48,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private String mSocket; private OutputStream mOutputStream; + private LocalLog mLocalLog; private final BlockingQueue mResponseQueue; @@ -57,11 +61,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private final int BUFFER_SIZE = 4096; NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag) { + int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new LinkedBlockingQueue(responseQueueSize); TAG = logTag != null ? logTag : "NativeDaemonConnector"; + mLocalLog = new LocalLog(maxLogSize); } @Override @@ -125,7 +130,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (buffer[i] == 0) { final String rawEvent = new String( buffer, start, i - start, Charsets.UTF_8); - if (LOGD) Slog.d(TAG, "RCV <- " + rawEvent); + log("RCV <- {" + rawEvent + "}"); try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( @@ -208,7 +213,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } final String unterminated = builder.toString(); - if (LOGD) Slog.d(TAG, "SND -> " + unterminated); + log("SND -> {" + unterminated + "}"); builder.append('\0'); @@ -432,4 +437,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public void monitor() { synchronized (mDaemonLock) { } } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mLocalLog.dump(fd, pw, args); + } + + private void log(String logstring) { + if (LOGD) Slog.d(TAG, logstring); + mLocalLog.log(logstring); + } } From bfe82685e7e4c2be76d383c7b77a582168b8d2f3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 11 Jan 2012 18:38:16 -0800 Subject: [PATCH 0114/1150] Move network stats to FileRotator pattern. Split existing network stats into two separate classes: a recorder which generates historical data based on periodic counter snapshots, and a collection of historical data with persistance logic. Recorder keeps a pending history in memory until outstanding data crosses a specific threshold. Persisting is handled through a given FileRotator. This pattern significantly reduces disk churn and memory overhead. Separate UID data from UID tag data, enabling a shorter rotation cycle. Migrate existing stats into new structure. Remove "xt" stats until iptables hooks are ready. Avoid consuming Entry values when recording into NetworkStatsHistory. Assign operation counts to default route interface. Introduce "Rewriter" interface in FileRotator with methods to enable rewriteAll(). Introduce IndentingPrintWriter to handle indenting in dump() methods. Bug: 5386531 Change-Id: Ibe086230a17999a197206ca62d45f266225fdff1 --- core/java/android/net/NetworkStats.java | 39 +- .../java/android/net/NetworkStatsHistory.java | 78 +- core/java/android/net/TrafficStats.java | 2 +- .../server/net/NetworkStatsCollection.java | 510 +++++++ .../server/net/NetworkStatsRecorder.java | 341 +++++ .../server/net/NetworkStatsService.java | 1280 ++++------------- 6 files changed, 1217 insertions(+), 1033 deletions(-) create mode 100644 services/java/com/android/server/net/NetworkStatsCollection.java create mode 100644 services/java/com/android/server/net/NetworkStatsRecorder.java diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e8f60b4968..7a1ef6623e 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -102,6 +102,15 @@ public class NetworkStats implements Parcelable { this.operations = operations; } + public boolean isNegative() { + return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0; + } + + public boolean isEmpty() { + return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0 + && operations == 0; + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -343,6 +352,7 @@ public class NetworkStats implements Parcelable { * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, * since operation counts are at data layer. */ + @Deprecated public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]); @@ -397,7 +407,7 @@ public class NetworkStats implements Parcelable { * Return total of all fields represented by this snapshot object. */ public Entry getTotal(Entry recycle) { - return getTotal(recycle, null, UID_ALL); + return getTotal(recycle, null, UID_ALL, false); } /** @@ -405,7 +415,7 @@ public class NetworkStats implements Parcelable { * the requested {@link #uid}. */ public Entry getTotal(Entry recycle, int limitUid) { - return getTotal(recycle, null, limitUid); + return getTotal(recycle, null, limitUid, false); } /** @@ -413,7 +423,11 @@ public class NetworkStats implements Parcelable { * the requested {@link #iface}. */ public Entry getTotal(Entry recycle, HashSet limitIface) { - return getTotal(recycle, limitIface, UID_ALL); + return getTotal(recycle, limitIface, UID_ALL, false); + } + + public Entry getTotalIncludingTags(Entry recycle) { + return getTotal(recycle, null, UID_ALL, true); } /** @@ -423,7 +437,8 @@ public class NetworkStats implements Parcelable { * @param limitIface Set of {@link #iface} to include in total; or {@code * null} to include all ifaces. */ - private Entry getTotal(Entry recycle, HashSet limitIface, int limitUid) { + private Entry getTotal( + Entry recycle, HashSet limitIface, int limitUid, boolean includeTags) { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = IFACE_ALL; @@ -442,7 +457,7 @@ public class NetworkStats implements Parcelable { if (matchesUid && matchesIface) { // skip specific tags, since already counted in TAG_NONE - if (tag[i] != TAG_NONE) continue; + if (tag[i] != TAG_NONE && !includeTags) continue; entry.rxBytes += rxBytes[i]; entry.rxPackets += rxPackets[i]; @@ -460,7 +475,7 @@ public class NetworkStats implements Parcelable { * time, and that none of them have disappeared. */ public NetworkStats subtract(NetworkStats right) { - return subtract(this, right, null); + return subtract(this, right, null, null); } /** @@ -471,12 +486,12 @@ public class NetworkStats implements Parcelable { * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. */ - public static NetworkStats subtract( - NetworkStats left, NetworkStats right, NonMonotonicObserver observer) { + public static NetworkStats subtract( + NetworkStats left, NetworkStats right, NonMonotonicObserver observer, C cookie) { long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; if (deltaRealtime < 0) { if (observer != null) { - observer.foundNonMonotonic(left, -1, right, -1); + observer.foundNonMonotonic(left, -1, right, -1, cookie); } deltaRealtime = 0; } @@ -510,7 +525,7 @@ public class NetworkStats implements Parcelable { if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 || entry.operations < 0) { if (observer != null) { - observer.foundNonMonotonic(left, i, right, j); + observer.foundNonMonotonic(left, i, right, j, cookie); } entry.rxBytes = Math.max(entry.rxBytes, 0); entry.rxPackets = Math.max(entry.rxPackets, 0); @@ -663,8 +678,8 @@ public class NetworkStats implements Parcelable { } }; - public interface NonMonotonicObserver { + public interface NonMonotonicObserver { public void foundNonMonotonic( - NetworkStats left, int leftIndex, NetworkStats right, int rightIndex); + NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); } } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 8c01331595..faf8a3f9fe 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -26,16 +26,18 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; +import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; import android.os.Parcelable; import android.util.MathUtils; +import com.android.internal.util.IndentingPrintWriter; + import java.io.CharArrayWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.io.PrintWriter; import java.net.ProtocolException; import java.util.Arrays; import java.util.Random; @@ -74,6 +76,7 @@ public class NetworkStatsHistory implements Parcelable { private long[] txBytes; private long[] txPackets; private long[] operations; + private long totalBytes; public static class Entry { public static final long UNKNOWN = -1; @@ -106,6 +109,12 @@ public class NetworkStatsHistory implements Parcelable { if ((fields & FIELD_TX_PACKETS) != 0) txPackets = new long[initialSize]; if ((fields & FIELD_OPERATIONS) != 0) operations = new long[initialSize]; bucketCount = 0; + totalBytes = 0; + } + + public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) { + this(bucketDuration, existing.estimateResizeBuckets(bucketDuration)); + recordEntireHistory(existing); } public NetworkStatsHistory(Parcel in) { @@ -118,6 +127,7 @@ public class NetworkStatsHistory implements Parcelable { txPackets = readLongArray(in); operations = readLongArray(in); bucketCount = bucketStart.length; + totalBytes = in.readLong(); } /** {@inheritDoc} */ @@ -130,6 +140,7 @@ public class NetworkStatsHistory implements Parcelable { writeLongArray(out, txBytes, bucketCount); writeLongArray(out, txPackets, bucketCount); writeLongArray(out, operations, bucketCount); + out.writeLong(totalBytes); } public NetworkStatsHistory(DataInputStream in) throws IOException { @@ -144,6 +155,7 @@ public class NetworkStatsHistory implements Parcelable { txPackets = new long[bucketStart.length]; operations = new long[bucketStart.length]; bucketCount = bucketStart.length; + totalBytes = total(rxBytes) + total(txBytes); break; } case VERSION_ADD_PACKETS: @@ -158,6 +170,7 @@ public class NetworkStatsHistory implements Parcelable { txPackets = readVarLongArray(in); operations = readVarLongArray(in); bucketCount = bucketStart.length; + totalBytes = total(rxBytes) + total(txBytes); break; } default: { @@ -207,6 +220,13 @@ public class NetworkStatsHistory implements Parcelable { } } + /** + * Return total bytes represented by this history. + */ + public long getTotalBytes() { + return totalBytes; + } + /** * Return index of bucket that contains or is immediately before the * requested time. @@ -266,13 +286,16 @@ public class NetworkStatsHistory implements Parcelable { * distribute across internal buckets, creating new buckets as needed. */ public void recordData(long start, long end, NetworkStats.Entry entry) { - if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 || entry.txPackets < 0 - || entry.operations < 0) { + long rxBytes = entry.rxBytes; + long rxPackets = entry.rxPackets; + long txBytes = entry.txBytes; + long txPackets = entry.txPackets; + long operations = entry.operations; + + if (entry.isNegative()) { throw new IllegalArgumentException("tried recording negative data"); } - if (entry.rxBytes == 0 && entry.rxPackets == 0 && entry.txBytes == 0 && entry.txPackets == 0 - && entry.operations == 0) { - // nothing to record; skip + if (entry.isEmpty()) { return; } @@ -295,21 +318,23 @@ public class NetworkStatsHistory implements Parcelable { if (overlap <= 0) continue; // integer math each time is faster than floating point - final long fracRxBytes = entry.rxBytes * overlap / duration; - final long fracRxPackets = entry.rxPackets * overlap / duration; - final long fracTxBytes = entry.txBytes * overlap / duration; - final long fracTxPackets = entry.txPackets * overlap / duration; - final long fracOperations = entry.operations * overlap / duration; + final long fracRxBytes = rxBytes * overlap / duration; + final long fracRxPackets = rxPackets * overlap / duration; + final long fracTxBytes = txBytes * overlap / duration; + final long fracTxPackets = txPackets * overlap / duration; + final long fracOperations = operations * overlap / duration; addLong(activeTime, i, overlap); - addLong(rxBytes, i, fracRxBytes); entry.rxBytes -= fracRxBytes; - addLong(rxPackets, i, fracRxPackets); entry.rxPackets -= fracRxPackets; - addLong(txBytes, i, fracTxBytes); entry.txBytes -= fracTxBytes; - addLong(txPackets, i, fracTxPackets); entry.txPackets -= fracTxPackets; - addLong(operations, i, fracOperations); entry.operations -= fracOperations; + addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes; + addLong(this.rxPackets, i, fracRxPackets); rxPackets -= fracRxPackets; + addLong(this.txBytes, i, fracTxBytes); txBytes -= fracTxBytes; + addLong(this.txPackets, i, fracTxPackets); txPackets -= fracTxPackets; + addLong(this.operations, i, fracOperations); operations -= fracOperations; duration -= overlap; } + + totalBytes += entry.rxBytes + entry.txBytes; } /** @@ -394,6 +419,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Remove buckets older than requested cutoff. */ + @Deprecated public void removeBucketsBefore(long cutoff) { int i; for (i = 0; i < bucketCount; i++) { @@ -415,6 +441,8 @@ public class NetworkStatsHistory implements Parcelable { if (txPackets != null) txPackets = Arrays.copyOfRange(txPackets, i, length); if (operations != null) operations = Arrays.copyOfRange(operations, i, length); bucketCount -= i; + + // TODO: subtract removed values from totalBytes } } @@ -527,19 +555,17 @@ public class NetworkStatsHistory implements Parcelable { return (long) (start + (r.nextFloat() * (end - start))); } - public void dump(String prefix, PrintWriter pw, boolean fullHistory) { - pw.print(prefix); + public void dump(IndentingPrintWriter pw, boolean fullHistory) { pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); + pw.increaseIndent(); final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); if (start > 0) { - pw.print(prefix); - pw.print(" (omitting "); pw.print(start); pw.println(" buckets)"); + pw.print("(omitting "); pw.print(start); pw.println(" buckets)"); } for (int i = start; i < bucketCount; i++) { - pw.print(prefix); - pw.print(" bucketStart="); pw.print(bucketStart[i]); + pw.print("bucketStart="); pw.print(bucketStart[i]); if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); } if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); } if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); } @@ -548,12 +574,14 @@ public class NetworkStatsHistory implements Parcelable { if (operations != null) { pw.print(" operations="); pw.print(operations[i]); } pw.println(); } + + pw.decreaseIndent(); } @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); - dump("", new PrintWriter(writer), false); + dump(new IndentingPrintWriter(writer, " "), false); return writer.toString(); } @@ -579,6 +607,10 @@ public class NetworkStatsHistory implements Parcelable { if (array != null) array[i] += value; } + public int estimateResizeBuckets(long newBucketDuration) { + return (int) (size() * getBucketDuration() / newBucketDuration); + } + /** * Utility methods for interacting with {@link DataInputStream} and * {@link DataOutputStream}, mostly dealing with writing partial arrays. diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 8bdb669d58..dfdea383d6 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -195,7 +195,7 @@ public class TrafficStats { // subtract starting values and return delta final NetworkStats profilingStop = getDataLayerSnapshotForUid(context); final NetworkStats profilingDelta = NetworkStats.subtract( - profilingStop, sActiveProfilingStart, null); + profilingStop, sActiveProfilingStart, null, null); sActiveProfilingStart = null; return profilingDelta; } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java new file mode 100644 index 0000000000..70038d93ee --- /dev/null +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -0,0 +1,510 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.SET_ALL; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.TrafficStats.UID_REMOVED; + +import android.net.NetworkIdentity; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.net.TrafficStats; +import android.text.format.DateUtils; + +import com.android.internal.os.AtomicFile; +import com.android.internal.util.FileRotator; +import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.Objects; +import com.google.android.collect.Lists; +import com.google.android.collect.Maps; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.ProtocolException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import libcore.io.IoUtils; + +/** + * Collection of {@link NetworkStatsHistory}, stored based on combined key of + * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. + */ +public class NetworkStatsCollection implements FileRotator.Reader { + private static final String TAG = "NetworkStatsCollection"; + + /** File header magic number: "ANET" */ + private static final int FILE_MAGIC = 0x414E4554; + + private static final int VERSION_NETWORK_INIT = 1; + + private static final int VERSION_UID_INIT = 1; + private static final int VERSION_UID_WITH_IDENT = 2; + private static final int VERSION_UID_WITH_TAG = 3; + private static final int VERSION_UID_WITH_SET = 4; + + private static final int VERSION_UNIFIED_INIT = 16; + + private HashMap mStats = Maps.newHashMap(); + + private long mBucketDuration; + + private long mStartMillis; + private long mEndMillis; + private long mTotalBytes; + private boolean mDirty; + + public NetworkStatsCollection(long bucketDuration) { + mBucketDuration = bucketDuration; + reset(); + } + + public void reset() { + mStats.clear(); + mStartMillis = Long.MAX_VALUE; + mEndMillis = Long.MIN_VALUE; + mTotalBytes = 0; + mDirty = false; + } + + public long getStartMillis() { + return mStartMillis; + } + + public long getEndMillis() { + return mEndMillis; + } + + public long getTotalBytes() { + return mTotalBytes; + } + + public boolean isDirty() { + return mDirty; + } + + public void clearDirty() { + mDirty = false; + } + + public boolean isEmpty() { + return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; + } + + /** + * Combine all {@link NetworkStatsHistory} in this collection which match + * the requested parameters. + */ + public NetworkStatsHistory getHistory( + NetworkTemplate template, int uid, int set, int tag, int fields) { + final NetworkStatsHistory combined = new NetworkStatsHistory( + mBucketDuration, estimateBuckets(), fields); + for (Map.Entry entry : mStats.entrySet()) { + final Key key = entry.getKey(); + final boolean setMatches = set == SET_ALL || key.set == set; + if (key.uid == uid && setMatches && key.tag == tag + && templateMatches(template, key.ident)) { + combined.recordEntireHistory(entry.getValue()); + } + } + return combined; + } + + /** + * Summarize all {@link NetworkStatsHistory} in this collection which match + * the requested parameters. + */ + public NetworkStats getSummary(NetworkTemplate template, long start, long end) { + final long now = System.currentTimeMillis(); + + final NetworkStats stats = new NetworkStats(end - start, 24); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + NetworkStatsHistory.Entry historyEntry = null; + + for (Map.Entry mapEntry : mStats.entrySet()) { + final Key key = mapEntry.getKey(); + if (templateMatches(template, key.ident)) { + final NetworkStatsHistory history = mapEntry.getValue(); + historyEntry = history.getValues(start, end, now, historyEntry); + + entry.iface = IFACE_ALL; + entry.uid = key.uid; + entry.set = key.set; + entry.tag = key.tag; + entry.rxBytes = historyEntry.rxBytes; + entry.rxPackets = historyEntry.rxPackets; + entry.txBytes = historyEntry.txBytes; + entry.txPackets = historyEntry.txPackets; + entry.operations = historyEntry.operations; + + if (!entry.isEmpty()) { + stats.combineValues(entry); + } + } + } + + return stats; + } + + /** + * Record given {@link NetworkStats.Entry} into this collection. + */ + public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, + long end, NetworkStats.Entry entry) { + noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes); + findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry); + } + + /** + * Record given {@link NetworkStatsHistory} into this collection. + */ + private void recordHistory(Key key, NetworkStatsHistory history) { + if (history.size() == 0) return; + noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); + + final NetworkStatsHistory existing = mStats.get(key); + if (existing != null) { + existing.recordEntireHistory(history); + } else { + mStats.put(key, history); + } + } + + /** + * Record all {@link NetworkStatsHistory} contained in the given collection + * into this collection. + */ + public void recordCollection(NetworkStatsCollection another) { + for (Map.Entry entry : another.mStats.entrySet()) { + recordHistory(entry.getKey(), entry.getValue()); + } + } + + private NetworkStatsHistory findOrCreateHistory( + NetworkIdentitySet ident, int uid, int set, int tag) { + final Key key = new Key(ident, uid, set, tag); + final NetworkStatsHistory existing = mStats.get(key); + + // update when no existing, or when bucket duration changed + NetworkStatsHistory updated = null; + if (existing == null) { + updated = new NetworkStatsHistory(mBucketDuration, 10); + } else if (existing.getBucketDuration() != mBucketDuration) { + updated = new NetworkStatsHistory(existing, mBucketDuration); + } + + if (updated != null) { + mStats.put(key, updated); + return updated; + } else { + return existing; + } + } + + /** {@inheritDoc} */ + public void read(InputStream in) throws IOException { + read(new DataInputStream(in)); + } + + public void read(DataInputStream in) throws IOException { + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_UNIFIED_INIT: { + // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) + final int identSize = in.readInt(); + for (int i = 0; i < identSize; i++) { + final NetworkIdentitySet ident = new NetworkIdentitySet(in); + + final int size = in.readInt(); + for (int j = 0; j < size; j++) { + final int uid = in.readInt(); + final int set = in.readInt(); + final int tag = in.readInt(); + + final Key key = new Key(ident, uid, set, tag); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + recordHistory(key, history); + } + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } + + public void write(DataOutputStream out) throws IOException { + // cluster key lists grouped by ident + final HashMap> keysByIdent = Maps.newHashMap(); + for (Key key : mStats.keySet()) { + ArrayList keys = keysByIdent.get(key.ident); + if (keys == null) { + keys = Lists.newArrayList(); + keysByIdent.put(key.ident, keys); + } + keys.add(key); + } + + out.writeInt(FILE_MAGIC); + out.writeInt(VERSION_UNIFIED_INIT); + + out.writeInt(keysByIdent.size()); + for (NetworkIdentitySet ident : keysByIdent.keySet()) { + final ArrayList keys = keysByIdent.get(ident); + ident.writeToStream(out); + + out.writeInt(keys.size()); + for (Key key : keys) { + final NetworkStatsHistory history = mStats.get(key); + out.writeInt(key.uid); + out.writeInt(key.set); + out.writeInt(key.tag); + history.writeToStream(out); + } + } + + out.flush(); + } + + @Deprecated + public void readLegacyNetwork(File file) throws IOException { + final AtomicFile inputFile = new AtomicFile(file); + + DataInputStream in = null; + try { + in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); + + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_NETWORK_INIT: { + // network := size *(NetworkIdentitySet NetworkStatsHistory) + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + final NetworkIdentitySet ident = new NetworkIdentitySet(in); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + + final Key key = new Key(ident, UID_ALL, SET_ALL, TAG_NONE); + recordHistory(key, history); + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } catch (FileNotFoundException e) { + // missing stats is okay, probably first boot + } finally { + IoUtils.closeQuietly(in); + } + } + + @Deprecated + public void readLegacyUid(File file, boolean onlyTags) throws IOException { + final AtomicFile inputFile = new AtomicFile(file); + + DataInputStream in = null; + try { + in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); + + // verify file magic header intact + final int magic = in.readInt(); + if (magic != FILE_MAGIC) { + throw new ProtocolException("unexpected magic: " + magic); + } + + final int version = in.readInt(); + switch (version) { + case VERSION_UID_INIT: { + // uid := size *(UID NetworkStatsHistory) + + // drop this data version, since we don't have a good + // mapping into NetworkIdentitySet. + break; + } + case VERSION_UID_WITH_IDENT: { + // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) + + // drop this data version, since this version only existed + // for a short time. + break; + } + case VERSION_UID_WITH_TAG: + case VERSION_UID_WITH_SET: { + // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) + final int identSize = in.readInt(); + for (int i = 0; i < identSize; i++) { + final NetworkIdentitySet ident = new NetworkIdentitySet(in); + + final int size = in.readInt(); + for (int j = 0; j < size; j++) { + final int uid = in.readInt(); + final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() + : SET_DEFAULT; + final int tag = in.readInt(); + + final Key key = new Key(ident, uid, set, tag); + final NetworkStatsHistory history = new NetworkStatsHistory(in); + + if ((tag == TAG_NONE) != onlyTags) { + recordHistory(key, history); + } + } + } + break; + } + default: { + throw new ProtocolException("unexpected version: " + version); + } + } + } catch (FileNotFoundException e) { + // missing stats is okay, probably first boot + } finally { + IoUtils.closeQuietly(in); + } + } + + /** + * Remove any {@link NetworkStatsHistory} attributed to the requested UID, + * moving any {@link NetworkStats#TAG_NONE} series to + * {@link TrafficStats#UID_REMOVED}. + */ + public void removeUid(int uid) { + final ArrayList knownKeys = Lists.newArrayList(); + knownKeys.addAll(mStats.keySet()); + + // migrate all UID stats into special "removed" bucket + for (Key key : knownKeys) { + if (key.uid == uid) { + // only migrate combined TAG_NONE history + if (key.tag == TAG_NONE) { + final NetworkStatsHistory uidHistory = mStats.get(key); + final NetworkStatsHistory removedHistory = findOrCreateHistory( + key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); + removedHistory.recordEntireHistory(uidHistory); + } + mStats.remove(key); + mDirty = true; + } + } + } + + private void noteRecordedHistory(long startMillis, long endMillis, long totalBytes) { + if (startMillis < mStartMillis) mStartMillis = startMillis; + if (endMillis > mEndMillis) mEndMillis = endMillis; + mTotalBytes += totalBytes; + mDirty = true; + } + + private int estimateBuckets() { + return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5) + / mBucketDuration); + } + + public void dump(IndentingPrintWriter pw) { + final ArrayList keys = Lists.newArrayList(); + keys.addAll(mStats.keySet()); + Collections.sort(keys); + + for (Key key : keys) { + pw.print("ident="); pw.print(key.ident.toString()); + pw.print(" uid="); pw.print(key.uid); + pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); + pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); + + final NetworkStatsHistory history = mStats.get(key); + pw.increaseIndent(); + history.dump(pw, true); + pw.decreaseIndent(); + } + } + + /** + * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} + * in the given {@link NetworkIdentitySet}. + */ + private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { + for (NetworkIdentity ident : identSet) { + if (template.matches(ident)) { + return true; + } + } + return false; + } + + private static class Key implements Comparable { + public final NetworkIdentitySet ident; + public final int uid; + public final int set; + public final int tag; + + private final int hashCode; + + public Key(NetworkIdentitySet ident, int uid, int set, int tag) { + this.ident = ident; + this.uid = uid; + this.set = set; + this.tag = tag; + hashCode = Objects.hashCode(ident, uid, set, tag); + } + + @Override + public int hashCode() { + return hashCode; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Key) { + final Key key = (Key) obj; + return uid == key.uid && set == key.set && tag == key.tag + && Objects.equal(ident, key.ident); + } + return false; + } + + /** {@inheritDoc} */ + public int compareTo(Key another) { + return Integer.compare(uid, another.uid); + } + } +} diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java new file mode 100644 index 0000000000..e7ba35888d --- /dev/null +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -0,0 +1,341 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkStats.TAG_NONE; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.net.NetworkStats; +import android.net.NetworkStats.NonMonotonicObserver; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.net.TrafficStats; +import android.util.Log; +import android.util.Slog; + +import com.android.internal.util.FileRotator; +import com.android.internal.util.IndentingPrintWriter; +import com.google.android.collect.Sets; + +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.ref.WeakReference; +import java.util.HashSet; +import java.util.Map; + +/** + * Logic to record deltas between periodic {@link NetworkStats} snapshots into + * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. + * Keeps pending changes in memory until they pass a specific threshold, in + * bytes. Uses {@link FileRotator} for persistence logic. + *

+ * Not inherently thread safe. + */ +public class NetworkStatsRecorder { + private static final String TAG = "NetworkStatsRecorder"; + private static final boolean LOGD = true; + + private final FileRotator mRotator; + private final NonMonotonicObserver mObserver; + private final String mCookie; + + private final long mBucketDuration; + private final long mPersistThresholdBytes; + private final boolean mOnlyTags; + + private NetworkStats mLastSnapshot; + + private final NetworkStatsCollection mPending; + private final NetworkStatsCollection mSinceBoot; + + private final CombiningRewriter mPendingRewriter; + + private WeakReference mComplete; + + public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, + String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) { + mRotator = checkNotNull(rotator, "missing FileRotator"); + mObserver = checkNotNull(observer, "missing NonMonotonicObserver"); + mCookie = cookie; + + mBucketDuration = bucketDuration; + mPersistThresholdBytes = persistThresholdBytes; + mOnlyTags = onlyTags; + + mPending = new NetworkStatsCollection(bucketDuration); + mSinceBoot = new NetworkStatsCollection(bucketDuration); + + mPendingRewriter = new CombiningRewriter(mPending); + } + + public void resetLocked() { + mLastSnapshot = null; + mPending.reset(); + mSinceBoot.reset(); + mComplete.clear(); + } + + public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { + return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null); + } + + /** + * Load complete history represented by {@link FileRotator}. Caches + * internally as a {@link WeakReference}, and updated with future + * {@link #recordSnapshotLocked(NetworkStats, Map, long)} snapshots as long + * as reference is valid. + */ + public NetworkStatsCollection getOrLoadCompleteLocked() { + NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; + if (complete == null) { + if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie); + try { + complete = new NetworkStatsCollection(mBucketDuration); + mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE); + complete.recordCollection(mPending); + mComplete = new WeakReference(complete); + } catch (IOException e) { + Log.wtf(TAG, "problem completely reading network stats", e); + } + } + return complete; + } + + /** + * Record any delta that occurred since last {@link NetworkStats} snapshot, + * using the given {@link Map} to identify network interfaces. First + * snapshot is considered bootstrap, and is not counted as delta. + */ + public void recordSnapshotLocked(NetworkStats snapshot, + Map ifaceIdent, long currentTimeMillis) { + final HashSet unknownIfaces = Sets.newHashSet(); + + // assume first snapshot is bootstrap and don't record + if (mLastSnapshot == null) { + mLastSnapshot = snapshot; + return; + } + + final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; + + final NetworkStats delta = NetworkStats.subtract( + snapshot, mLastSnapshot, mObserver, mCookie); + final long end = currentTimeMillis; + final long start = end - delta.getElapsedRealtime(); + + NetworkStats.Entry entry = null; + for (int i = 0; i < delta.size(); i++) { + entry = delta.getValues(i, entry); + final NetworkIdentitySet ident = ifaceIdent.get(entry.iface); + if (ident == null) { + unknownIfaces.add(entry.iface); + continue; + } + + // skip when no delta occured + if (entry.isEmpty()) continue; + + // only record tag data when requested + if ((entry.tag == TAG_NONE) != mOnlyTags) { + mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); + + // also record against boot stats when present + if (mSinceBoot != null) { + mSinceBoot.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); + } + + // also record against complete dataset when present + if (complete != null) { + complete.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); + } + } + } + + mLastSnapshot = snapshot; + + if (LOGD && unknownIfaces.size() > 0) { + Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); + } + } + + /** + * Consider persisting any pending deltas, if they are beyond + * {@link #mPersistThresholdBytes}. + */ + public void maybePersistLocked(long currentTimeMillis) { + final long pendingBytes = mPending.getTotalBytes(); + if (pendingBytes >= mPersistThresholdBytes) { + forcePersistLocked(currentTimeMillis); + } else { + mRotator.maybeRotate(currentTimeMillis); + } + } + + /** + * Force persisting any pending deltas. + */ + public void forcePersistLocked(long currentTimeMillis) { + if (mPending.isDirty()) { + if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie); + try { + mRotator.rewriteActive(mPendingRewriter, currentTimeMillis); + mRotator.maybeRotate(currentTimeMillis); + mPending.reset(); + } catch (IOException e) { + Log.wtf(TAG, "problem persisting pending stats", e); + } + } + } + + /** + * Remove the given UID from all {@link FileRotator} history, migrating it + * to {@link TrafficStats#UID_REMOVED}. + */ + public void removeUidLocked(int uid) { + try { + // process all existing data to migrate uid + mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); + } catch (IOException e) { + Log.wtf(TAG, "problem removing UID " + uid, e); + } + + // clear UID from current stats snapshot + if (mLastSnapshot != null) { + mLastSnapshot = mLastSnapshot.withoutUid(uid); + } + } + + /** + * Rewriter that will combine current {@link NetworkStatsCollection} values + * with anything read from disk, and write combined set to disk. Clears the + * original {@link NetworkStatsCollection} when finished writing. + */ + private static class CombiningRewriter implements FileRotator.Rewriter { + private final NetworkStatsCollection mCollection; + + public CombiningRewriter(NetworkStatsCollection collection) { + mCollection = checkNotNull(collection, "missing NetworkStatsCollection"); + } + + /** {@inheritDoc} */ + public void reset() { + // ignored + } + + /** {@inheritDoc} */ + public void read(InputStream in) throws IOException { + mCollection.read(in); + } + + /** {@inheritDoc} */ + public boolean shouldWrite() { + return true; + } + + /** {@inheritDoc} */ + public void write(OutputStream out) throws IOException { + mCollection.write(new DataOutputStream(out)); + mCollection.reset(); + } + } + + /** + * Rewriter that will remove any {@link NetworkStatsHistory} attributed to + * the requested UID, only writing data back when modified. + */ + public static class RemoveUidRewriter implements FileRotator.Rewriter { + private final NetworkStatsCollection mTemp; + private final int mUid; + + public RemoveUidRewriter(long bucketDuration, int uid) { + mTemp = new NetworkStatsCollection(bucketDuration); + mUid = uid; + } + + /** {@inheritDoc} */ + public void reset() { + mTemp.reset(); + } + + /** {@inheritDoc} */ + public void read(InputStream in) throws IOException { + mTemp.read(in); + mTemp.clearDirty(); + mTemp.removeUid(mUid); + } + + /** {@inheritDoc} */ + public boolean shouldWrite() { + return mTemp.isDirty(); + } + + /** {@inheritDoc} */ + public void write(OutputStream out) throws IOException { + mTemp.write(new DataOutputStream(out)); + } + } + + public void importLegacyNetworkLocked(File file) throws IOException { + // legacy file still exists; start empty to avoid double importing + mRotator.deleteAll(); + + final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); + collection.readLegacyNetwork(file); + + final long startMillis = collection.getStartMillis(); + final long endMillis = collection.getEndMillis(); + + if (!collection.isEmpty()) { + // process legacy data, creating active file at starting time, then + // using end time to possibly trigger rotation. + mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); + mRotator.maybeRotate(endMillis); + } + } + + public void importLegacyUidLocked(File file) throws IOException { + // legacy file still exists; start empty to avoid double importing + mRotator.deleteAll(); + + final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); + collection.readLegacyUid(file, mOnlyTags); + + final long startMillis = collection.getStartMillis(); + final long endMillis = collection.getEndMillis(); + + if (!collection.isEmpty()) { + // process legacy data, creating active file at starting time, then + // using end time to possibly trigger rotation. + mRotator.rewriteActive(new CombiningRewriter(collection), startMillis); + mRotator.maybeRotate(endMillis); + } + } + + public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) { + pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); + if (fullHistory) { + pw.println("Complete history:"); + getOrLoadCompleteLocked().dump(pw); + } else { + pw.println("History since boot:"); + mSinceBoot.dump(pw); + } + } +} diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index eeb7fec8e1..c9b79e8e89 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -34,14 +34,18 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; -import static android.net.TrafficStats.UID_REMOVED; -import static android.provider.Settings.Secure.NETSTATS_NETWORK_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_NETWORK_MAX_HISTORY; -import static android.provider.Settings.Secure.NETSTATS_PERSIST_THRESHOLD; +import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; +import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES; +import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE; +import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES; import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Secure.NETSTATS_TAG_MAX_HISTORY; +import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED; +import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_UID_MAX_HISTORY; +import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE; +import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES; +import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE; import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; @@ -61,12 +65,10 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.content.pm.PackageManager.NameNotFoundException; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; +import android.net.LinkProperties; import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; @@ -74,6 +76,7 @@ import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.TrafficStats; import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; @@ -94,32 +97,18 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; -import com.android.internal.os.AtomicFile; -import com.android.internal.util.Objects; +import com.android.internal.util.FileRotator; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.connectivity.Tethering; -import com.google.android.collect.Lists; import com.google.android.collect.Maps; -import com.google.android.collect.Sets; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.FileDescriptor; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; -import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Random; - -import libcore.io.IoUtils; /** * Collect and persist detailed network statistics, and provide this data to @@ -127,16 +116,8 @@ import libcore.io.IoUtils; */ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStats"; - private static final boolean LOGD = false; - private static final boolean LOGV = false; - - /** File header magic number: "ANET" */ - private static final int FILE_MAGIC = 0x414E4554; - private static final int VERSION_NETWORK_INIT = 1; - private static final int VERSION_UID_INIT = 1; - private static final int VERSION_UID_WITH_IDENT = 2; - private static final int VERSION_UID_WITH_TAG = 3; - private static final int VERSION_UID_WITH_SET = 4; + private static final boolean LOGD = true; + private static final boolean LOGV = true; private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; @@ -147,9 +128,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_FORCE = 0x100; - /** Sample recent usage after each poll event. */ - private static final boolean ENABLE_SAMPLE_AFTER_POLL = true; - private static final String TAG_NETSTATS_ERROR = "netstats_error"; private final Context mContext; @@ -159,10 +137,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; + private final File mSystemDir; + private final File mBaseDir; + private final PowerManager.WakeLock mWakeLock; private IConnectivityManager mConnManager; - private DropBoxManager mDropBox; // @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = @@ -172,71 +152,76 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; - // TODO: trim empty history objects entirely - private static final long KB_IN_BYTES = 1024; private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; + private static final String PREFIX_DEV = "dev"; + private static final String PREFIX_UID = "uid"; + private static final String PREFIX_UID_TAG = "uid_tag"; + /** * Settings that can be changed externally. */ public interface NetworkStatsSettings { public long getPollInterval(); - public long getPersistThreshold(); - public long getNetworkBucketDuration(); - public long getNetworkMaxHistory(); - public long getUidBucketDuration(); - public long getUidMaxHistory(); - public long getTagMaxHistory(); public long getTimeCacheMaxAge(); + public long getGlobalAlertBytes(); + public boolean getSampleEnabled(); + + public static class Config { + public final long bucketDuration; + public final long persistBytes; + public final long rotateAgeMillis; + public final long deleteAgeMillis; + + public Config(long bucketDuration, long persistBytes, long rotateAgeMillis, + long deleteAgeMillis) { + this.bucketDuration = bucketDuration; + this.persistBytes = persistBytes; + this.rotateAgeMillis = rotateAgeMillis; + this.deleteAgeMillis = deleteAgeMillis; + } + } + + public Config getDevConfig(); + public Config getUidConfig(); + public Config getUidTagConfig(); } private final Object mStatsLock = new Object(); /** Set of currently active ifaces. */ private HashMap mActiveIfaces = Maps.newHashMap(); - /** Set of historical {@code dev} stats for known networks. */ - private HashMap mNetworkDevStats = Maps.newHashMap(); - /** Set of historical {@code xtables} stats for known networks. */ - private HashMap mNetworkXtStats = Maps.newHashMap(); - /** Set of historical {@code xtables} stats for known UIDs. */ - private HashMap mUidStats = Maps.newHashMap(); + /** Current default active iface. */ + private String mActiveIface; - /** Flag if {@link #mNetworkDevStats} have been loaded from disk. */ - private boolean mNetworkStatsLoaded = false; - /** Flag if {@link #mUidStats} have been loaded from disk. */ - private boolean mUidStatsLoaded = false; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = + new DropBoxNonMonotonicObserver(); - private NetworkStats mLastPollNetworkDevSnapshot; - private NetworkStats mLastPollNetworkXtSnapshot; - private NetworkStats mLastPollUidSnapshot; - private NetworkStats mLastPollOperationsSnapshot; + private NetworkStatsRecorder mDevRecorder; + private NetworkStatsRecorder mUidRecorder; + private NetworkStatsRecorder mUidTagRecorder; - private NetworkStats mLastPersistNetworkDevSnapshot; - private NetworkStats mLastPersistNetworkXtSnapshot; - private NetworkStats mLastPersistUidSnapshot; + /** Cached {@link #mDevRecorder} stats. */ + private NetworkStatsCollection mDevStatsCached; /** Current counter sets for each UID. */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); /** Data layer operation counters for splicing into other structures. */ - private NetworkStats mOperations = new NetworkStats(0L, 10); + private NetworkStats mUidOperations = new NetworkStats(0L, 10); private final HandlerThread mHandlerThread; private final Handler mHandler; - private final AtomicFile mNetworkDevFile; - private final AtomicFile mNetworkXtFile; - private final AtomicFile mUidFile; - public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), - getSystemDir(), new DefaultNetworkStatsSettings(context)); + getDefaultSystemDir(), new DefaultNetworkStatsSettings(context)); } - private static File getSystemDir() { + private static File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -258,9 +243,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerThread.start(); mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); - mNetworkDevFile = new AtomicFile(new File(systemDir, "netstats.bin")); - mNetworkXtFile = new AtomicFile(new File(systemDir, "netstats_xt.bin")); - mUidFile = new AtomicFile(new File(systemDir, "netstats_uid.bin")); + mSystemDir = checkNotNull(systemDir); + mBaseDir = new File(systemDir, "netstats"); + mBaseDir.mkdirs(); } public void bindConnectivityManager(IConnectivityManager connManager) { @@ -273,17 +258,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } - synchronized (mStatsLock) { - // read historical network stats from disk, since policy service - // might need them right away. we delay loading detailed UID stats - // until actually needed. - readNetworkDevStatsLocked(); - readNetworkXtStatsLocked(); - mNetworkStatsLoaded = true; - } + // create data recorders along with historical rotators + mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); + mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); + mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); - // bootstrap initial stats to prevent double-counting later - bootstrapStats(); + synchronized (mStatsLock) { + // upgrade any legacy stats, migrating them to rotated files + maybeUpgradeLegacyStatsLocked(); + + // read historical network stats from disk, since policy service + // might need them right away. + mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked(); + + // bootstrap initial stats to prevent double-counting later + bootstrapStatsLocked(); + } // watch for network interfaces to be claimed final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); @@ -317,8 +307,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerPollAlarmLocked(); registerGlobalAlert(); + } - mDropBox = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); + private NetworkStatsRecorder buildRecorder( + String prefix, NetworkStatsSettings.Config config, boolean includeTags) { + return new NetworkStatsRecorder( + new FileRotator(mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), + mNonMonotonicObserver, prefix, config.bucketDuration, config.persistBytes, + includeTags); } private void shutdownLocked() { @@ -330,18 +326,44 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mTeleManager.listen(mPhoneListener, LISTEN_NONE); - if (mNetworkStatsLoaded) { - writeNetworkDevStatsLocked(); - writeNetworkXtStatsLocked(); + final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() + : System.currentTimeMillis(); + + // persist any pending stats + mDevRecorder.forcePersistLocked(currentTime); + mUidRecorder.forcePersistLocked(currentTime); + mUidTagRecorder.forcePersistLocked(currentTime); + + mDevRecorder = null; + mUidRecorder = null; + mUidTagRecorder = null; + + mDevStatsCached = null; + } + + private void maybeUpgradeLegacyStatsLocked() { + File file; + try { + file = new File(mSystemDir, "netstats.bin"); + if (file.exists()) { + mDevRecorder.importLegacyNetworkLocked(file); + file.delete(); + } + + file = new File(mSystemDir, "netstats_xt.bin"); + if (file.exists()) { + file.delete(); + } + + file = new File(mSystemDir, "netstats_uid.bin"); + if (file.exists()) { + mUidRecorder.importLegacyUidLocked(file); + mUidTagRecorder.importLegacyUidLocked(file); + file.delete(); + } + } catch (IOException e) { + Log.wtf(TAG, "problem during legacy upgrade", e); } - if (mUidStatsLoaded) { - writeUidStatsLocked(); - } - mNetworkDevStats.clear(); - mNetworkXtStats.clear(); - mUidStats.clear(); - mNetworkStatsLoaded = false; - mUidStatsLoaded = false; } /** @@ -372,7 +394,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void registerGlobalAlert() { try { - final long alertBytes = mSettings.getPersistThreshold(); + final long alertBytes = mSettings.getGlobalAlertBytes(); mNetworkManager.setGlobalAlert(alertBytes); } catch (IllegalStateException e) { Slog.w(TAG, "problem registering for global alert: " + e); @@ -383,161 +405,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - return getHistoryForNetworkDev(template, fields); + return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); } - private NetworkStatsHistory getHistoryForNetworkDev(NetworkTemplate template, int fields) { - return getHistoryForNetwork(template, fields, mNetworkDevStats); - } - - private NetworkStatsHistory getHistoryForNetworkXt(NetworkTemplate template, int fields) { - return getHistoryForNetwork(template, fields, mNetworkXtStats); - } - - private NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields, - HashMap source) { - synchronized (mStatsLock) { - // combine all interfaces that match template - final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getNetworkBucketDuration(), estimateNetworkBuckets(), fields); - for (NetworkIdentitySet ident : source.keySet()) { - if (templateMatches(template, ident)) { - final NetworkStatsHistory history = source.get(ident); - if (history != null) { - combined.recordEntireHistory(history); - } - } - } - return combined; - } + @Override + public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { + return mDevStatsCached.getSummary(template, start, end); } @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - - synchronized (mStatsLock) { - ensureUidStatsLoadedLocked(); - - // combine all interfaces that match template - final NetworkStatsHistory combined = new NetworkStatsHistory( - mSettings.getUidBucketDuration(), estimateUidBuckets(), fields); - for (UidStatsKey key : mUidStats.keySet()) { - final boolean setMatches = set == SET_ALL || key.set == set; - if (templateMatches(template, key.ident) && key.uid == uid && setMatches - && key.tag == tag) { - final NetworkStatsHistory history = mUidStats.get(key); - combined.recordEntireHistory(history); - } - } - - return combined; + // TODO: transition to stats sessions to avoid WeakReferences + if (tag == TAG_NONE) { + return mUidRecorder.getOrLoadCompleteLocked().getHistory( + template, uid, set, tag, fields); + } else { + return mUidTagRecorder.getOrLoadCompleteLocked().getHistory( + template, uid, set, tag, fields); } } - @Override - public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - return getSummaryForNetworkDev(template, start, end); - } - - private NetworkStats getSummaryForNetworkDev(NetworkTemplate template, long start, long end) { - return getSummaryForNetwork(template, start, end, mNetworkDevStats); - } - - private NetworkStats getSummaryForNetworkXt(NetworkTemplate template, long start, long end) { - return getSummaryForNetwork(template, start, end, mNetworkXtStats); - } - - private NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end, - HashMap source) { - synchronized (mStatsLock) { - // use system clock to be externally consistent - final long now = System.currentTimeMillis(); - - final NetworkStats stats = new NetworkStats(end - start, 1); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - - // combine total from all interfaces that match template - for (NetworkIdentitySet ident : source.keySet()) { - if (templateMatches(template, ident)) { - final NetworkStatsHistory history = source.get(ident); - historyEntry = history.getValues(start, end, now, historyEntry); - - entry.iface = IFACE_ALL; - entry.uid = UID_ALL; - entry.tag = TAG_NONE; - entry.rxBytes = historyEntry.rxBytes; - entry.rxPackets = historyEntry.rxPackets; - entry.txBytes = historyEntry.txBytes; - entry.txPackets = historyEntry.txPackets; - - stats.combineValues(entry); - } - } - - return stats; - } - } - - private long getHistoryStartLocked( - NetworkTemplate template, HashMap source) { - long start = Long.MAX_VALUE; - for (NetworkIdentitySet ident : source.keySet()) { - if (templateMatches(template, ident)) { - final NetworkStatsHistory history = source.get(ident); - start = Math.min(start, history.getStart()); - } - } - return start; - } - @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - - synchronized (mStatsLock) { - ensureUidStatsLoadedLocked(); - - // use system clock to be externally consistent - final long now = System.currentTimeMillis(); - - final NetworkStats stats = new NetworkStats(end - start, 24); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - - for (UidStatsKey key : mUidStats.keySet()) { - if (templateMatches(template, key.ident)) { - // always include summary under TAG_NONE, and include - // other tags when requested. - if (key.tag == TAG_NONE || includeTags) { - final NetworkStatsHistory history = mUidStats.get(key); - historyEntry = history.getValues(start, end, now, historyEntry); - - entry.iface = IFACE_ALL; - entry.uid = key.uid; - entry.set = key.set; - entry.tag = key.tag; - entry.rxBytes = historyEntry.rxBytes; - entry.rxPackets = historyEntry.rxPackets; - entry.txBytes = historyEntry.txBytes; - entry.txPackets = historyEntry.txPackets; - entry.operations = historyEntry.operations; - - if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 - || entry.txPackets > 0 || entry.operations > 0) { - stats.combineValues(entry); - } - } - } - } - - return stats; + // TODO: transition to stats sessions to avoid WeakReferences + final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary( + template, start, end); + if (includeTags) { + final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary( + template, start, end); + stats.combineAllValues(tagStats); } + return stats; } @Override @@ -567,7 +467,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // splice in operation counts - dataLayer.spliceOperationsFrom(mOperations); + dataLayer.spliceOperationsFrom(mUidOperations); return dataLayer; } @@ -586,8 +486,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { final int set = mActiveUidCounterSet.get(uid, SET_DEFAULT); - mOperations.combineValues(IFACE_ALL, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); - mOperations.combineValues(IFACE_ALL, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); + mUidOperations.combineValues( + mActiveIface, uid, set, tag, 0L, 0L, 0L, 0L, operationCount); + mUidOperations.combineValues( + mActiveIface, uid, set, TAG_NONE, 0L, 0L, 0L, 0L, operationCount); } } @@ -755,13 +657,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPollLocked(FLAG_PERSIST_NETWORK); final NetworkState[] states; + final LinkProperties activeLink; try { states = mConnManager.getAllNetworkState(); + activeLink = mConnManager.getActiveLinkProperties(); } catch (RemoteException e) { // ignored; service lives in system_server return; } + mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; + // rebuild active interfaces based on connected networks mActiveIfaces.clear(); @@ -785,12 +691,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Bootstrap initial stats snapshot, usually during {@link #systemReady()} * so we have baseline values without double-counting. */ - private void bootstrapStats() { + private void bootstrapStatsLocked() { + final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() + : System.currentTimeMillis(); + try { - mLastPollUidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - mLastPollNetworkDevSnapshot = mNetworkManager.getNetworkStatsSummary(); - mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); - mLastPollOperationsSnapshot = new NetworkStats(0L, 0); + // snapshot and record current counters; read UID stats first to + // avoid overcounting dev stats. + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats devSnapshot = getNetworkStatsSummary(); + + mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); + } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { @@ -830,27 +744,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: consider marking "untrusted" times in historical stats final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long threshold = mSettings.getPersistThreshold(); - final NetworkStats uidSnapshot; - final NetworkStats networkXtSnapshot; - final NetworkStats networkDevSnapshot; try { - // collect any tethering stats - final NetworkStats tetherSnapshot = getNetworkStatsTethering(); + // snapshot and record current counters; read UID stats first to + // avoid overcounting dev stats. + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats devSnapshot = getNetworkStatsSummary(); - // record uid stats, folding in tethering stats - uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - uidSnapshot.combineAllValues(tetherSnapshot); - performUidPollLocked(uidSnapshot, currentTime); - - // record dev network stats - networkDevSnapshot = mNetworkManager.getNetworkStatsSummary(); - performNetworkDevPollLocked(networkDevSnapshot, currentTime); - - // record xt network stats - networkXtSnapshot = computeNetworkXtSnapshotFromUid(uidSnapshot); - performNetworkXtPollLocked(networkXtSnapshot, currentTime); + mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); @@ -860,26 +763,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } - // persist when enough network data has occurred - final long persistNetworkDevDelta = computeStatsDelta( - mLastPersistNetworkDevSnapshot, networkDevSnapshot, true, "devp").getTotalBytes(); - final long persistNetworkXtDelta = computeStatsDelta( - mLastPersistNetworkXtSnapshot, networkXtSnapshot, true, "xtp").getTotalBytes(); - final boolean networkOverThreshold = persistNetworkDevDelta > threshold - || persistNetworkXtDelta > threshold; - if (persistForce || (persistNetwork && networkOverThreshold)) { - writeNetworkDevStatsLocked(); - writeNetworkXtStatsLocked(); - mLastPersistNetworkDevSnapshot = networkDevSnapshot; - mLastPersistNetworkXtSnapshot = networkXtSnapshot; - } - - // persist when enough uid data has occurred - final long persistUidDelta = computeStatsDelta( - mLastPersistUidSnapshot, uidSnapshot, true, "uidp").getTotalBytes(); - if (persistForce || (persistUid && persistUidDelta > threshold)) { - writeUidStatsLocked(); - mLastPersistUidSnapshot = uidSnapshot; + // persist any pending data depending on requested flags + if (persistForce) { + mDevRecorder.forcePersistLocked(currentTime); + mUidRecorder.forcePersistLocked(currentTime); + mUidTagRecorder.forcePersistLocked(currentTime); + } else { + if (persistNetwork) { + mDevRecorder.maybePersistLocked(currentTime); + } + if (persistUid) { + mUidRecorder.maybePersistLocked(currentTime); + mUidTagRecorder.maybePersistLocked(currentTime); + } } if (LOGV) { @@ -887,9 +783,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Slog.v(TAG, "performPollLocked() took " + duration + "ms"); } - if (ENABLE_SAMPLE_AFTER_POLL) { + if (mSettings.getSampleEnabled()) { // sample stats after each full poll - performSample(); + performSampleLocked(); } // finally, dispatch updated event to any listeners @@ -898,512 +794,59 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY); } - /** - * Update {@link #mNetworkDevStats} historical usage. - */ - private void performNetworkDevPollLocked(NetworkStats networkDevSnapshot, long currentTime) { - final HashSet unknownIface = Sets.newHashSet(); - - final NetworkStats delta = computeStatsDelta( - mLastPollNetworkDevSnapshot, networkDevSnapshot, false, "dev"); - final long timeStart = currentTime - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); - if (ident == null) { - unknownIface.add(entry.iface); - continue; - } - - final NetworkStatsHistory history = findOrCreateNetworkDevStatsLocked(ident); - history.recordData(timeStart, currentTime, entry); - } - - mLastPollNetworkDevSnapshot = networkDevSnapshot; - - if (LOGD && unknownIface.size() > 0) { - Slog.w(TAG, "unknown dev interfaces " + unknownIface + ", ignoring those stats"); - } - } - - /** - * Update {@link #mNetworkXtStats} historical usage. - */ - private void performNetworkXtPollLocked(NetworkStats networkXtSnapshot, long currentTime) { - final HashSet unknownIface = Sets.newHashSet(); - - final NetworkStats delta = computeStatsDelta( - mLastPollNetworkXtSnapshot, networkXtSnapshot, false, "xt"); - final long timeStart = currentTime - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); - if (ident == null) { - unknownIface.add(entry.iface); - continue; - } - - final NetworkStatsHistory history = findOrCreateNetworkXtStatsLocked(ident); - history.recordData(timeStart, currentTime, entry); - } - - mLastPollNetworkXtSnapshot = networkXtSnapshot; - - if (LOGD && unknownIface.size() > 0) { - Slog.w(TAG, "unknown xt interfaces " + unknownIface + ", ignoring those stats"); - } - } - - /** - * Update {@link #mUidStats} historical usage. - */ - private void performUidPollLocked(NetworkStats uidSnapshot, long currentTime) { - ensureUidStatsLoadedLocked(); - - final NetworkStats delta = computeStatsDelta( - mLastPollUidSnapshot, uidSnapshot, false, "uid"); - final NetworkStats operationsDelta = computeStatsDelta( - mLastPollOperationsSnapshot, mOperations, false, "uidop"); - final long timeStart = currentTime - delta.getElapsedRealtime(); - - NetworkStats.Entry entry = null; - NetworkStats.Entry operationsEntry = null; - for (int i = 0; i < delta.size(); i++) { - entry = delta.getValues(i, entry); - final NetworkIdentitySet ident = mActiveIfaces.get(entry.iface); - if (ident == null) { - if (entry.rxBytes > 0 || entry.rxPackets > 0 || entry.txBytes > 0 - || entry.txPackets > 0) { - Log.w(TAG, "dropping UID delta from unknown iface: " + entry); - } - continue; - } - - // splice in operation counts since last poll - final int j = operationsDelta.findIndex(IFACE_ALL, entry.uid, entry.set, entry.tag); - if (j != -1) { - operationsEntry = operationsDelta.getValues(j, operationsEntry); - entry.operations = operationsEntry.operations; - } - - final NetworkStatsHistory history = findOrCreateUidStatsLocked( - ident, entry.uid, entry.set, entry.tag); - history.recordData(timeStart, currentTime, entry); - } - - mLastPollUidSnapshot = uidSnapshot; - mLastPollOperationsSnapshot = mOperations.clone(); - } - /** * Sample recent statistics summary into {@link EventLog}. */ - private void performSample() { - final long largestBucketSize = Math.max( - mSettings.getNetworkBucketDuration(), mSettings.getUidBucketDuration()); - - // take sample as atomic buckets - final long now = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - final long end = now - (now % largestBucketSize) + largestBucketSize; - final long start = end - largestBucketSize; - + private void performSampleLocked() { + // TODO: migrate trustedtime fixes to separate binary log events final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; - long devHistoryStart = Long.MAX_VALUE; - NetworkTemplate template = null; - NetworkStats.Entry devTotal = null; - NetworkStats.Entry xtTotal = null; - NetworkStats.Entry uidTotal = null; + NetworkTemplate template; + NetworkStats.Entry devTotal; + NetworkStats.Entry xtTotal; + NetworkStats.Entry uidTotal; // collect mobile sample template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); - devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); - devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats); - xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); - uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); + devTotal = mDevRecorder.getTotalSinceBootLocked(template); + xtTotal = new NetworkStats.Entry(); + uidTotal = mUidRecorder.getTotalSinceBootLocked(template); EventLogTags.writeNetstatsMobileSample( devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime, devHistoryStart); + trustedTime); // collect wifi sample template = buildTemplateWifi(); - devTotal = getSummaryForNetworkDev(template, start, end).getTotal(devTotal); - devHistoryStart = getHistoryStartLocked(template, mNetworkDevStats); - xtTotal = getSummaryForNetworkXt(template, start, end).getTotal(xtTotal); - uidTotal = getSummaryForAllUid(template, start, end, false).getTotal(uidTotal); + devTotal = mDevRecorder.getTotalSinceBootLocked(template); + xtTotal = new NetworkStats.Entry(); + uidTotal = mUidRecorder.getTotalSinceBootLocked(template); + EventLogTags.writeNetstatsWifiSample( devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime, devHistoryStart); + trustedTime); } /** - * Clean up {@link #mUidStats} after UID is removed. + * Clean up {@link #mUidRecorder} after UID is removed. */ private void removeUidLocked(int uid) { - ensureUidStatsLoadedLocked(); - // perform one last poll before removing performPollLocked(FLAG_PERSIST_ALL); - final ArrayList knownKeys = Lists.newArrayList(); - knownKeys.addAll(mUidStats.keySet()); - - // migrate all UID stats into special "removed" bucket - for (UidStatsKey key : knownKeys) { - if (key.uid == uid) { - // only migrate combined TAG_NONE history - if (key.tag == TAG_NONE) { - final NetworkStatsHistory uidHistory = mUidStats.get(key); - final NetworkStatsHistory removedHistory = findOrCreateUidStatsLocked( - key.ident, UID_REMOVED, SET_DEFAULT, TAG_NONE); - removedHistory.recordEntireHistory(uidHistory); - } - mUidStats.remove(key); - } - } - - // clear UID from current stats snapshot - if (mLastPollUidSnapshot != null) { - mLastPollUidSnapshot = mLastPollUidSnapshot.withoutUid(uid); - mLastPollNetworkXtSnapshot = computeNetworkXtSnapshotFromUid(mLastPollUidSnapshot); - } + mUidRecorder.removeUidLocked(uid); + mUidTagRecorder.removeUidLocked(uid); // clear kernel stats associated with UID resetKernelUidStats(uid); - - // since this was radical rewrite, push to disk - writeUidStatsLocked(); - } - - private NetworkStatsHistory findOrCreateNetworkXtStatsLocked(NetworkIdentitySet ident) { - return findOrCreateNetworkStatsLocked(ident, mNetworkXtStats); - } - - private NetworkStatsHistory findOrCreateNetworkDevStatsLocked(NetworkIdentitySet ident) { - return findOrCreateNetworkStatsLocked(ident, mNetworkDevStats); - } - - private NetworkStatsHistory findOrCreateNetworkStatsLocked( - NetworkIdentitySet ident, HashMap source) { - final NetworkStatsHistory existing = source.get(ident); - - // update when no existing, or when bucket duration changed - final long bucketDuration = mSettings.getNetworkBucketDuration(); - NetworkStatsHistory updated = null; - if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration, 10); - } else if (existing.getBucketDuration() != bucketDuration) { - updated = new NetworkStatsHistory( - bucketDuration, estimateResizeBuckets(existing, bucketDuration)); - updated.recordEntireHistory(existing); - } - - if (updated != null) { - source.put(ident, updated); - return updated; - } else { - return existing; - } - } - - private NetworkStatsHistory findOrCreateUidStatsLocked( - NetworkIdentitySet ident, int uid, int set, int tag) { - ensureUidStatsLoadedLocked(); - - final UidStatsKey key = new UidStatsKey(ident, uid, set, tag); - final NetworkStatsHistory existing = mUidStats.get(key); - - // update when no existing, or when bucket duration changed - final long bucketDuration = mSettings.getUidBucketDuration(); - NetworkStatsHistory updated = null; - if (existing == null) { - updated = new NetworkStatsHistory(bucketDuration, 10); - } else if (existing.getBucketDuration() != bucketDuration) { - updated = new NetworkStatsHistory( - bucketDuration, estimateResizeBuckets(existing, bucketDuration)); - updated.recordEntireHistory(existing); - } - - if (updated != null) { - mUidStats.put(key, updated); - return updated; - } else { - return existing; - } - } - - private void readNetworkDevStatsLocked() { - if (LOGV) Slog.v(TAG, "readNetworkDevStatsLocked()"); - readNetworkStats(mNetworkDevFile, mNetworkDevStats); - } - - private void readNetworkXtStatsLocked() { - if (LOGV) Slog.v(TAG, "readNetworkXtStatsLocked()"); - readNetworkStats(mNetworkXtFile, mNetworkXtStats); - } - - private static void readNetworkStats( - AtomicFile inputFile, HashMap output) { - // clear any existing stats and read from disk - output.clear(); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(inputFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_NETWORK_INIT: { - // network := size *(NetworkIdentitySet NetworkStatsHistory) - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - output.put(ident, history); - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } catch (IOException e) { - Log.wtf(TAG, "problem reading network stats", e); - } finally { - IoUtils.closeQuietly(in); - } - } - - private void ensureUidStatsLoadedLocked() { - if (!mUidStatsLoaded) { - readUidStatsLocked(); - mUidStatsLoaded = true; - } - } - - private void readUidStatsLocked() { - if (LOGV) Slog.v(TAG, "readUidStatsLocked()"); - - // clear any existing stats and read from disk - mUidStats.clear(); - - DataInputStream in = null; - try { - in = new DataInputStream(new BufferedInputStream(mUidFile.openRead())); - - // verify file magic header intact - final int magic = in.readInt(); - if (magic != FILE_MAGIC) { - throw new ProtocolException("unexpected magic: " + magic); - } - - final int version = in.readInt(); - switch (version) { - case VERSION_UID_INIT: { - // uid := size *(UID NetworkStatsHistory) - - // drop this data version, since we don't have a good - // mapping into NetworkIdentitySet. - break; - } - case VERSION_UID_WITH_IDENT: { - // uid := size *(NetworkIdentitySet size *(UID NetworkStatsHistory)) - - // drop this data version, since this version only existed - // for a short time. - break; - } - case VERSION_UID_WITH_TAG: - case VERSION_UID_WITH_SET: { - // uid := size *(NetworkIdentitySet size *(uid set tag NetworkStatsHistory)) - final int identSize = in.readInt(); - for (int i = 0; i < identSize; i++) { - final NetworkIdentitySet ident = new NetworkIdentitySet(in); - - final int size = in.readInt(); - for (int j = 0; j < size; j++) { - final int uid = in.readInt(); - final int set = (version >= VERSION_UID_WITH_SET) ? in.readInt() - : SET_DEFAULT; - final int tag = in.readInt(); - - final UidStatsKey key = new UidStatsKey(ident, uid, set, tag); - final NetworkStatsHistory history = new NetworkStatsHistory(in); - mUidStats.put(key, history); - } - } - break; - } - default: { - throw new ProtocolException("unexpected version: " + version); - } - } - } catch (FileNotFoundException e) { - // missing stats is okay, probably first boot - } catch (IOException e) { - Log.wtf(TAG, "problem reading uid stats", e); - } finally { - IoUtils.closeQuietly(in); - } - } - - private void writeNetworkDevStatsLocked() { - if (LOGV) Slog.v(TAG, "writeNetworkDevStatsLocked()"); - writeNetworkStats(mNetworkDevStats, mNetworkDevFile); - } - - private void writeNetworkXtStatsLocked() { - if (LOGV) Slog.v(TAG, "writeNetworkXtStatsLocked()"); - writeNetworkStats(mNetworkXtStats, mNetworkXtFile); - } - - private void writeNetworkStats( - HashMap input, AtomicFile outputFile) { - // TODO: consider duplicating stats and releasing lock while writing - - // trim any history beyond max - if (mTime.hasCache()) { - final long systemCurrentTime = System.currentTimeMillis(); - final long trustedCurrentTime = mTime.currentTimeMillis(); - - final long currentTime = Math.min(systemCurrentTime, trustedCurrentTime); - final long maxHistory = mSettings.getNetworkMaxHistory(); - - for (NetworkStatsHistory history : input.values()) { - final int beforeSize = history.size(); - history.removeBucketsBefore(currentTime - maxHistory); - final int afterSize = history.size(); - - if (beforeSize > 24 && afterSize < beforeSize / 2) { - // yikes, dropping more than half of significant history - final StringBuilder builder = new StringBuilder(); - builder.append("yikes, dropping more than half of history").append('\n'); - builder.append("systemCurrentTime=").append(systemCurrentTime).append('\n'); - builder.append("trustedCurrentTime=").append(trustedCurrentTime).append('\n'); - builder.append("maxHistory=").append(maxHistory).append('\n'); - builder.append("beforeSize=").append(beforeSize).append('\n'); - builder.append("afterSize=").append(afterSize).append('\n'); - mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); - } - } - } - - FileOutputStream fos = null; - try { - fos = outputFile.startWrite(); - final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); - - out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_NETWORK_INIT); - - out.writeInt(input.size()); - for (NetworkIdentitySet ident : input.keySet()) { - final NetworkStatsHistory history = input.get(ident); - ident.writeToStream(out); - history.writeToStream(out); - } - - out.flush(); - outputFile.finishWrite(fos); - } catch (IOException e) { - Log.wtf(TAG, "problem writing stats", e); - if (fos != null) { - outputFile.failWrite(fos); - } - } - } - - private void writeUidStatsLocked() { - if (LOGV) Slog.v(TAG, "writeUidStatsLocked()"); - - if (!mUidStatsLoaded) { - Slog.w(TAG, "asked to write UID stats when not loaded; skipping"); - return; - } - - // TODO: consider duplicating stats and releasing lock while writing - - // trim any history beyond max - if (mTime.hasCache()) { - final long currentTime = Math.min( - System.currentTimeMillis(), mTime.currentTimeMillis()); - final long maxUidHistory = mSettings.getUidMaxHistory(); - final long maxTagHistory = mSettings.getTagMaxHistory(); - for (UidStatsKey key : mUidStats.keySet()) { - final NetworkStatsHistory history = mUidStats.get(key); - - // detailed tags are trimmed sooner than summary in TAG_NONE - if (key.tag == TAG_NONE) { - history.removeBucketsBefore(currentTime - maxUidHistory); - } else { - history.removeBucketsBefore(currentTime - maxTagHistory); - } - } - } - - // build UidStatsKey lists grouped by ident - final HashMap> keysByIdent = Maps.newHashMap(); - for (UidStatsKey key : mUidStats.keySet()) { - ArrayList keys = keysByIdent.get(key.ident); - if (keys == null) { - keys = Lists.newArrayList(); - keysByIdent.put(key.ident, keys); - } - keys.add(key); - } - - FileOutputStream fos = null; - try { - fos = mUidFile.startWrite(); - final DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos)); - - out.writeInt(FILE_MAGIC); - out.writeInt(VERSION_UID_WITH_SET); - - out.writeInt(keysByIdent.size()); - for (NetworkIdentitySet ident : keysByIdent.keySet()) { - final ArrayList keys = keysByIdent.get(ident); - ident.writeToStream(out); - - out.writeInt(keys.size()); - for (UidStatsKey key : keys) { - final NetworkStatsHistory history = mUidStats.get(key); - out.writeInt(key.uid); - out.writeInt(key.set); - out.writeInt(key.tag); - history.writeToStream(out); - } - } - - out.flush(); - mUidFile.finishWrite(fos); - } catch (IOException e) { - Log.wtf(TAG, "problem writing stats", e); - if (fos != null) { - mUidFile.failWrite(fos); - } - } } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); final HashSet argSet = new HashSet(); @@ -1411,187 +854,68 @@ public class NetworkStatsService extends INetworkStatsService.Stub { argSet.add(arg); } - final boolean fullHistory = argSet.contains("full"); + // usage: dumpsys netstats --full --uid --tag + final boolean poll = argSet.contains("--poll") || argSet.contains("poll"); + final boolean fullHistory = argSet.contains("--full") || argSet.contains("full"); + final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); + final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); + + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); synchronized (mStatsLock) { - // TODO: remove this testing code, since it corrupts stats - if (argSet.contains("generate")) { - generateRandomLocked(args); - pw.println("Generated stub stats"); - return; - } - - if (argSet.contains("poll")) { + if (poll) { performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); return; } pw.println("Active interfaces:"); + pw.increaseIndent(); for (String iface : mActiveIfaces.keySet()) { final NetworkIdentitySet ident = mActiveIfaces.get(iface); - pw.print(" iface="); pw.print(iface); + pw.print("iface="); pw.print(iface); pw.print(" ident="); pw.println(ident.toString()); } + pw.decreaseIndent(); - pw.println("Known historical dev stats:"); - for (NetworkIdentitySet ident : mNetworkDevStats.keySet()) { - final NetworkStatsHistory history = mNetworkDevStats.get(ident); - pw.print(" ident="); pw.println(ident.toString()); - history.dump(" ", pw, fullHistory); + pw.println("Dev stats:"); + pw.increaseIndent(); + mDevRecorder.dumpLocked(pw, fullHistory); + pw.decreaseIndent(); + + if (includeUid) { + pw.println("UID stats:"); + pw.increaseIndent(); + mUidRecorder.dumpLocked(pw, fullHistory); + pw.decreaseIndent(); } - pw.println("Known historical xt stats:"); - for (NetworkIdentitySet ident : mNetworkXtStats.keySet()) { - final NetworkStatsHistory history = mNetworkXtStats.get(ident); - pw.print(" ident="); pw.println(ident.toString()); - history.dump(" ", pw, fullHistory); - } - - if (argSet.contains("detail")) { - // since explicitly requested with argument, we're okay to load - // from disk if not already in memory. - ensureUidStatsLoadedLocked(); - - final ArrayList keys = Lists.newArrayList(); - keys.addAll(mUidStats.keySet()); - Collections.sort(keys); - - pw.println("Detailed UID stats:"); - for (UidStatsKey key : keys) { - pw.print(" ident="); pw.print(key.ident.toString()); - pw.print(" uid="); pw.print(key.uid); - pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); - pw.print(" tag="); pw.println(NetworkStats.tagToString(key.tag)); - - final NetworkStatsHistory history = mUidStats.get(key); - history.dump(" ", pw, fullHistory); - } + if (includeTag) { + pw.println("UID tag stats:"); + pw.increaseIndent(); + mUidTagRecorder.dumpLocked(pw, fullHistory); + pw.decreaseIndent(); } } } + private NetworkStats getNetworkStatsSummary() throws RemoteException { + return mNetworkManager.getNetworkStatsSummary(); + } + /** - * @deprecated only for temporary testing + * Return snapshot of current UID statistics, including any + * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. */ - @Deprecated - private void generateRandomLocked(String[] args) { - final long totalBytes = Long.parseLong(args[1]); - final long totalTime = Long.parseLong(args[2]); - - final PackageManager pm = mContext.getPackageManager(); - final ArrayList specialUidList = Lists.newArrayList(); - for (int i = 3; i < args.length; i++) { - try { - specialUidList.add(pm.getApplicationInfo(args[i], 0).uid); - } catch (NameNotFoundException e) { - throw new RuntimeException(e); - } - } + private NetworkStats getNetworkStatsUidDetail() throws RemoteException { + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); - final HashSet otherUidSet = Sets.newHashSet(); - for (ApplicationInfo info : pm.getInstalledApplications(0)) { - if (pm.checkPermission(android.Manifest.permission.INTERNET, info.packageName) - == PackageManager.PERMISSION_GRANTED && !specialUidList.contains(info.uid)) { - otherUidSet.add(info.uid); - } - } + // fold tethering stats and operations into uid snapshot + final NetworkStats tetherSnapshot = getNetworkStatsTethering(); + uidSnapshot.combineAllValues(tetherSnapshot); + uidSnapshot.combineAllValues(mUidOperations); - final ArrayList otherUidList = new ArrayList(otherUidSet); - - final long end = System.currentTimeMillis(); - final long start = end - totalTime; - - mNetworkDevStats.clear(); - mNetworkXtStats.clear(); - mUidStats.clear(); - - final Random r = new Random(); - for (NetworkIdentitySet ident : mActiveIfaces.values()) { - final NetworkStatsHistory devHistory = findOrCreateNetworkDevStatsLocked(ident); - final NetworkStatsHistory xtHistory = findOrCreateNetworkXtStatsLocked(ident); - - final ArrayList uidList = new ArrayList(); - uidList.addAll(specialUidList); - - if (uidList.size() == 0) { - Collections.shuffle(otherUidList); - uidList.addAll(otherUidList); - } - - boolean first = true; - long remainingBytes = totalBytes; - for (int uid : uidList) { - final NetworkStatsHistory defaultHistory = findOrCreateUidStatsLocked( - ident, uid, SET_DEFAULT, TAG_NONE); - final NetworkStatsHistory foregroundHistory = findOrCreateUidStatsLocked( - ident, uid, SET_FOREGROUND, TAG_NONE); - - final long uidBytes = totalBytes / uidList.size(); - - final float fractionDefault = r.nextFloat(); - final long defaultBytes = (long) (uidBytes * fractionDefault); - final long foregroundBytes = (long) (uidBytes * (1 - fractionDefault)); - - defaultHistory.generateRandom(start, end, defaultBytes); - foregroundHistory.generateRandom(start, end, foregroundBytes); - - if (first) { - final long bumpTime = (start + end) / 2; - defaultHistory.recordData( - bumpTime, bumpTime + DAY_IN_MILLIS, 200 * MB_IN_BYTES, 0); - first = false; - } - - devHistory.recordEntireHistory(defaultHistory); - devHistory.recordEntireHistory(foregroundHistory); - xtHistory.recordEntireHistory(defaultHistory); - xtHistory.recordEntireHistory(foregroundHistory); - } - } - } - - private StatsObserver mStatsObserver = new StatsObserver(); - - private class StatsObserver implements NonMonotonicObserver { - private String mCurrentType; - - public void setCurrentType(String type) { - mCurrentType = type; - } - - /** {@inheritDoc} */ - public void foundNonMonotonic( - NetworkStats left, int leftIndex, NetworkStats right, int rightIndex) { - Log.w(TAG, "found non-monotonic values; saving to dropbox"); - - // record error for debugging - final StringBuilder builder = new StringBuilder(); - builder.append("found non-monotonic " + mCurrentType + " values at left[" + leftIndex - + "] - right[" + rightIndex + "]\n"); - builder.append("left=").append(left).append('\n'); - builder.append("right=").append(right).append('\n'); - mDropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); - } - } - - /** - * Return the delta between two {@link NetworkStats} snapshots, where {@code - * before} can be {@code null}. - */ - private NetworkStats computeStatsDelta( - NetworkStats before, NetworkStats current, boolean collectStale, String type) { - if (before != null) { - mStatsObserver.setCurrentType(type); - return NetworkStats.subtract(current, before, mStatsObserver); - } else if (collectStale) { - // caller is okay collecting stale stats for first call. - return current; - } else { - // this is first snapshot; to prevent from double-counting we only - // observe traffic occuring between known snapshots. - return new NetworkStats(0L, 10); - } + return uidSnapshot; } /** @@ -1608,35 +932,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private static NetworkStats computeNetworkXtSnapshotFromUid(NetworkStats uidSnapshot) { - return uidSnapshot.groupedByIface(); - } - - private int estimateNetworkBuckets() { - return (int) (mSettings.getNetworkMaxHistory() / mSettings.getNetworkBucketDuration()); - } - - private int estimateUidBuckets() { - return (int) (mSettings.getUidMaxHistory() / mSettings.getUidBucketDuration()); - } - - private static int estimateResizeBuckets(NetworkStatsHistory existing, long newBucketDuration) { - return (int) (existing.size() * existing.getBucketDuration() / newBucketDuration); - } - - /** - * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} - * in the given {@link NetworkIdentitySet}. - */ - private static boolean templateMatches(NetworkTemplate template, NetworkIdentitySet identSet) { - for (NetworkIdentity ident : identSet) { - if (template.matches(ident)) { - return true; - } - } - return false; - } - private Handler.Callback mHandlerCallback = new Handler.Callback() { /** {@inheritDoc} */ public boolean handleMessage(Message msg) { @@ -1672,40 +967,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - /** - * Key uniquely identifying a {@link NetworkStatsHistory} for a UID. - */ - private static class UidStatsKey implements Comparable { - public final NetworkIdentitySet ident; - public final int uid; - public final int set; - public final int tag; - - public UidStatsKey(NetworkIdentitySet ident, int uid, int set, int tag) { - this.ident = ident; - this.uid = uid; - this.set = set; - this.tag = tag; - } - - @Override - public int hashCode() { - return Objects.hashCode(ident, uid, set, tag); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof UidStatsKey) { - final UidStatsKey key = (UidStatsKey) obj; - return Objects.equal(ident, key.ident) && uid == key.uid && set == key.set - && tag == key.tag; - } - return false; - } - + private class DropBoxNonMonotonicObserver implements NonMonotonicObserver { /** {@inheritDoc} */ - public int compareTo(UidStatsKey another) { - return Integer.compare(uid, another.uid); + public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, + int rightIndex, String cookie) { + Log.w(TAG, "found non-monotonic values; saving to dropbox"); + + // record error for debugging + final StringBuilder builder = new StringBuilder(); + builder.append("found non-monotonic " + cookie + " values at left[" + leftIndex + + "] - right[" + rightIndex + "]\n"); + builder.append("left=").append(left).append('\n'); + builder.append("right=").append(right).append('\n'); + + final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( + Context.DROPBOX_SERVICE); + dropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); } } @@ -1731,26 +1008,35 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } - public long getPersistThreshold() { - return getSecureLong(NETSTATS_PERSIST_THRESHOLD, 2 * MB_IN_BYTES); - } - public long getNetworkBucketDuration() { - return getSecureLong(NETSTATS_NETWORK_BUCKET_DURATION, HOUR_IN_MILLIS); - } - public long getNetworkMaxHistory() { - return getSecureLong(NETSTATS_NETWORK_MAX_HISTORY, 90 * DAY_IN_MILLIS); - } - public long getUidBucketDuration() { - return getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS); - } - public long getUidMaxHistory() { - return getSecureLong(NETSTATS_UID_MAX_HISTORY, 90 * DAY_IN_MILLIS); - } - public long getTagMaxHistory() { - return getSecureLong(NETSTATS_TAG_MAX_HISTORY, 30 * DAY_IN_MILLIS); - } public long getTimeCacheMaxAge() { - return DAY_IN_MILLIS; + return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); + } + public long getGlobalAlertBytes() { + return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES); + } + public boolean getSampleEnabled() { + return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true); + } + + public Config getDevConfig() { + return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), + getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES), + getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), + getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); + } + + public Config getUidConfig() { + return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), + getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), + getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS), + getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); + } + + public Config getUidTagConfig() { + return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), + getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), + getSecureLong(NETSTATS_UID_ROTATE_AGE, 5 * DAY_IN_MILLIS), + getSecureLong(NETSTATS_UID_DELETE_AGE, 15 * DAY_IN_MILLIS)); } } } From 0d038b7949933c5f681d209fdde2df6031df51d7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 24 Jan 2012 15:37:07 -0800 Subject: [PATCH 0115/1150] Match WIFI_P2P data usage. Bug: 5405891 Change-Id: I5b815d6fc25a2f26a86c39a43fde305fcc3fb65c --- core/java/android/net/NetworkTemplate.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 418b82fdea..8ebfd8d0aa 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.scrubSubscriberId; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; @@ -231,10 +232,13 @@ public class NetworkTemplate implements Parcelable { * Check if matches Wi-Fi network template. */ private boolean matchesWifi(NetworkIdentity ident) { - if (ident.mType == TYPE_WIFI) { - return true; + switch (ident.mType) { + case TYPE_WIFI: + case TYPE_WIFI_P2P: + return true; + default: + return false; } - return false; } /** From 2ed12477de26cbbf79e185a600ff0a197b8b6636 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 31 Jan 2012 17:12:53 -0800 Subject: [PATCH 0116/1150] Clear identity when updating network stats. Bug: 5945461 Change-Id: Ie51ea3f107a705c395b65684f21bf4c28c7f4d33 --- .../java/com/android/server/net/NetworkStatsService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index c9b79e8e89..7930caf847 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -510,7 +510,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - performPoll(FLAG_PERSIST_ALL); + + final long token = Binder.clearCallingIdentity(); + try { + performPoll(FLAG_PERSIST_ALL); + } finally { + Binder.restoreCallingIdentity(token); + } } /** From 9a21249a6c86cc37f915be7830715981c8bf691a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 2 Feb 2012 13:07:47 -0800 Subject: [PATCH 0117/1150] Avoid NDC deadlock when re-arming network alert. When NDC delivers limitReached() event, NMS re-arms the alert, which makes another call back to NDC. If NDC already started processing another call, this causes deadlock. Fix this by re-arming on a handler thread. Bug: 5879848 Change-Id: I46fa78fe1f1122c5f31dd6020483e5ae89a9f39d --- .../java/com/android/server/net/NetworkStatsService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 7930caf847..414ed1e2ad 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -121,6 +121,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; + private static final int MSG_REGISTER_GLOBAL_ALERT = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -600,7 +601,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); // re-arm global alert for next update - registerGlobalAlert(); + mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget(); } } }; @@ -951,6 +952,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { updateIfaces(); return true; } + case MSG_REGISTER_GLOBAL_ALERT: { + registerGlobalAlert(); + return true; + } default: { return false; } From 43dc9a2d93a3b5abf5c547cbd5f74ab3203bcb85 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 20 Jan 2012 16:33:15 -0800 Subject: [PATCH 0118/1150] Add some logging to NDC. We're getting some lockups of netd and this can help point us in the right direction. bug:5864209 Change-Id: Id8bdb0a758c5b161e0143de61b5f39c3a982e329 --- .../java/com/android/server/NativeDaemonConnector.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index f475dd6e33..308661f1b0 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -153,6 +153,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo start = i + 1; } } + if (start == 0) { + final String rawEvent = new String(buffer, start, count, Charsets.UTF_8); + log("RCV incomplete <- {" + rawEvent + "}"); + } // We should end at the amount we read. If not, compact then // buffer and read again. @@ -297,7 +301,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throws NativeDaemonConnectorException { final ArrayList events = Lists.newArrayList(); - mResponseQueue.clear(); + while (mResponseQueue.size() > 0) { + try { + log("ignoring {" + mResponseQueue.take() + "}"); + } catch (Exception e) {} + } final String sentCommand = sendCommandLocked(cmd, args); From 94a315cec5be3922d094881011c1867060e33018 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 3 Feb 2012 14:50:07 -0800 Subject: [PATCH 0119/1150] Unify shorthand for byte-based units. Change-Id: If990859dee3f0973e1d4c48f05312c84071b3328 --- core/java/android/net/TrafficStats.java | 7 +++++++ .../java/com/android/server/net/NetworkStatsService.java | 5 +---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index dfdea383d6..973fac1909 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -44,6 +44,13 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; + /** @hide */ + public static final long KB_IN_BYTES = 1024; + /** @hide */ + public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; + /** @hide */ + public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; + /** * Special UID value used when collecting {@link NetworkStatsHistory} for * removed applications. diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 414ed1e2ad..c9b67fc9e0 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; import static android.net.NetworkTemplate.buildTemplateWifi; +import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES; @@ -153,10 +154,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; - private static final long KB_IN_BYTES = 1024; - private static final long MB_IN_BYTES = 1024 * KB_IN_BYTES; - private static final long GB_IN_BYTES = 1024 * MB_IN_BYTES; - private static final String PREFIX_DEV = "dev"; private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; From 25e3ec70aad243ed95b253f3c79e3533db349aa0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 6 Feb 2012 17:35:07 -0800 Subject: [PATCH 0120/1150] List rotated netstats files during --checkin dump. Also disable verbose logging. Change-Id: I4c51e05d695eac43f0d9c28f9699f1655c642a99 --- .../android/server/net/NetworkStatsService.java | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index c9b67fc9e0..13c0640e5f 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -117,8 +117,7 @@ import java.util.HashSet; */ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG = "NetworkStats"; - private static final boolean LOGD = true; - private static final boolean LOGV = true; + private static final boolean LOGV = false; private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; @@ -858,8 +857,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { argSet.add(arg); } - // usage: dumpsys netstats --full --uid --tag + // usage: dumpsys netstats --full --uid --tag --poll --checkin final boolean poll = argSet.contains("--poll") || argSet.contains("poll"); + final boolean checkin = argSet.contains("--checkin"); final boolean fullHistory = argSet.contains("--full") || argSet.contains("full"); final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); @@ -873,6 +873,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + if (checkin) { + // list current stats files to verify rotation + pw.println("Current files:"); + pw.increaseIndent(); + for (String file : mBaseDir.list()) { + pw.println(file); + } + pw.decreaseIndent(); + return; + } + pw.println("Active interfaces:"); pw.increaseIndent(); for (String iface : mActiveIfaces.keySet()) { From ff81c2eebc1426921afd08e06e540677bbaf72ea Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 7 Feb 2012 12:05:43 -0800 Subject: [PATCH 0121/1150] Send broadcast when changing restrict background. When changing global restrict background status, send connectivity change broadcast, since it radically changes DISCONNECTED/BLOCKED status system-wide. Also reduce verbose stats logging. Bug: 5854466 Change-Id: I3b612c520f50cc3000a3a569b7e0ab5f691cc2bd --- services/java/com/android/server/net/NetworkStatsRecorder.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index e7ba35888d..240cc1c875 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -51,6 +51,7 @@ import java.util.Map; public class NetworkStatsRecorder { private static final String TAG = "NetworkStatsRecorder"; private static final boolean LOGD = true; + private static final boolean LOGV = false; private final FileRotator mRotator; private final NonMonotonicObserver mObserver; @@ -170,7 +171,7 @@ public class NetworkStatsRecorder { mLastSnapshot = snapshot; - if (LOGD && unknownIfaces.size() > 0) { + if (LOGV && unknownIfaces.size() > 0) { Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); } } From 5c7de0b4ec0322ba357d323fa3ae76d3d982d974 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 7 Feb 2012 11:36:55 -0800 Subject: [PATCH 0122/1150] Make NDC not block forever and handle restart. Need changes in core. Still possible for netd to get wedged but system won't die because of it. Leads the way to having forking netd - then only individual commands would wedge, promoting stability. bug:5864209 Change-Id: Ifcd37511c8239fe3df7e9070869b63a9c5649bd2 --- .../android/server/NativeDaemonConnector.java | 227 ++++++++++++++---- .../com/android/server/NativeDaemonEvent.java | 26 +- 2 files changed, 195 insertions(+), 58 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 308661f1b0..5319432710 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -34,8 +34,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.LinkedList; /** * Generic connector class for interfacing with a native daemon which uses the @@ -50,11 +50,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private OutputStream mOutputStream; private LocalLog mLocalLog; - private final BlockingQueue mResponseQueue; + private final ResponseQueue mResponseQueue; private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; + private AtomicInteger mSequenceNumber; + + private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ + /** Lock held whenever communicating with native daemon. */ private final Object mDaemonLock = new Object(); @@ -64,7 +68,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; mSocket = socket; - mResponseQueue = new LinkedBlockingQueue(responseQueueSize); + mResponseQueue = new ResponseQueue(responseQueueSize); + mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); } @@ -79,7 +84,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo try { listenToSocket(); } catch (Exception e) { - Slog.e(TAG, "Error in NativeDaemonConnector", e); + loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } @@ -90,12 +95,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { - Slog.w(TAG, String.format( - "Unhandled event '%s'", event)); + log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { - Slog.e(TAG, String.format( - "Error handling '%s'", event), e); + loge("Error handling '" + event + "': " + e); } return true; } @@ -111,7 +114,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.connect(address); InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); + synchronized (mDaemonLock) { + mOutputStream = socket.getOutputStream(); + } mCallbacks.onDaemonConnected(); @@ -120,7 +125,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) break; + if (count < 0) { + loge("got " + count + " reading with start = " + start); + break; + } // Add our starting point to the count and reset the start. count += start; @@ -140,14 +148,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue: " + ex); - } + mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { - Slog.w(TAG, "Problem parsing message: " + rawEvent, e); + log("Problem parsing message: " + rawEvent + " - " + e); } start = i + 1; @@ -169,15 +173,16 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } } catch (IOException ex) { - Slog.e(TAG, "Communications error", ex); + loge("Communications error: " + ex); throw ex; } finally { synchronized (mDaemonLock) { if (mOutputStream != null) { try { + loge("closing stream for " + mSocket); mOutputStream.close(); } catch (IOException e) { - Slog.w(TAG, "Failed closing output stream", e); + loge("Failed closing output stream: " + e); } mOutputStream = null; } @@ -188,17 +193,17 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.close(); } } catch (IOException ex) { - Slog.w(TAG, "Failed closing socket", ex); + loge("Failed closing socket: " + ex); } } } /** - * Send command to daemon, escaping arguments as needed. + * Make command for daemon, escaping arguments as needed. * - * @return the final command issued. + * @return the final command. */ - private String sendCommandLocked(String cmd, Object... args) + private StringBuilder makeCommand(String cmd, Object... args) throws NativeDaemonConnectorException { // TODO: eventually enforce that cmd doesn't contain arguments if (cmd.indexOf('\0') >= 0) { @@ -216,22 +221,33 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo appendEscaped(builder, argString); } - final String unterminated = builder.toString(); - log("SND -> {" + unterminated + "}"); + return builder; + } + + private int sendCommand(StringBuilder builder) + throws NativeDaemonConnectorException { + + int sequenceNumber = mSequenceNumber.incrementAndGet(); + + builder.insert(0, Integer.toString(sequenceNumber) + " "); + + if (LOGD) log("SND -> {" + builder.toString() + "}"); builder.append('\0'); - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); + synchronized (mDaemonLock) { + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { + try { + mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); + } } } - return unterminated; + return sequenceNumber; } /** @@ -292,39 +308,41 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { - synchronized (mDaemonLock) { - return executeLocked(cmd, args); - } + return execute(DEFAULT_TIMEOUT, cmd, args); } - private NativeDaemonEvent[] executeLocked(String cmd, Object... args) + /** + * Issue the given command to the native daemon and return any + * {@linke NativeDaemonEvent@isClassContinue()} responses, including the + * final terminal response. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList events = Lists.newArrayList(); - - while (mResponseQueue.size() > 0) { - try { - log("ignoring {" + mResponseQueue.take() + "}"); - } catch (Exception e) {} - } - - final String sentCommand = sendCommandLocked(cmd, args); + final StringBuilder sentCommand = makeCommand(cmd, args); + final int cmdNumber = sendCommand(sentCommand); NativeDaemonEvent event = null; + cmd = sentCommand.toString(); do { - try { - event = mResponseQueue.take(); - } catch (InterruptedException e) { - Slog.w(TAG, "interrupted waiting for event line"); - continue; + event = mResponseQueue.remove(cmdNumber, timeout, cmd); + if (event == null) { + loge("timed-out waiting for response to " + cmdNumber + " " + cmd); + throw new NativeDaemonFailureException(cmd, event); } events.add(event); } while (event.isClassContinue()); if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(sentCommand, event); + throw new NativeDaemonArgumentException(cmd, event); } if (event.isClassServerError()) { - throw new NativeDaemonFailureException(sentCommand, event); + throw new NativeDaemonFailureException(cmd, event); } return events.toArray(new NativeDaemonEvent[events.size()]); @@ -448,10 +466,115 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mLocalLog.dump(fd, pw, args); + pw.println(); + mResponseQueue.dump(fd, pw, args); } private void log(String logstring) { if (LOGD) Slog.d(TAG, logstring); mLocalLog.log(logstring); } + + private void loge(String logstring) { + Slog.e(TAG, logstring); + mLocalLog.log(logstring); + } + + private static class ResponseQueue { + + private static class Response { + public int cmdNum; + public LinkedList responses = new LinkedList(); + public String request; + public Response(int c, String r) {cmdNum = c; request = r;} + } + + private final LinkedList mResponses; + private int mMaxCount; + + ResponseQueue(int maxCount) { + mResponses = new LinkedList(); + mMaxCount = maxCount; + } + + public void add(int cmdNum, NativeDaemonEvent response) { + Response found = null; + synchronized (mResponses) { + for (Response r : mResponses) { + if (r.cmdNum == cmdNum) { + found = r; + break; + } + } + if (found == null) { + // didn't find it - make sure our queue isn't too big before adding + // another.. + while (mResponses.size() >= mMaxCount) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "more buffered than allowed: " + mResponses.size() + + " >= " + mMaxCount); + mResponses.remove(); + } + found = new Response(cmdNum, null); + mResponses.add(found); + } + found.responses.add(response); + } + synchronized (found) { + found.notify(); + } + } + + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + long endTime = SystemClock.uptimeMillis() + timeoutMs; + long nowTime; + Response found = null; + while (true) { + synchronized (mResponses) { + for (Response response : mResponses) { + if (response.cmdNum == cmdNum) { + found = response; + // how many response fragments are left + switch (response.responses.size()) { + case 0: // haven't got any - must wait + break; + case 1: // last one - remove this from the master list + mResponses.remove(response); // fall through + default: // take one and move on + response.request = origCmd; + return response.responses.remove(); + } + } + } + nowTime = SystemClock.uptimeMillis(); + if (endTime <= nowTime) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "Timeout waiting for response"); + return null; + } + /* pre-allocate so we have something unique to wait on */ + if (found == null) { + found = new Response(cmdNum, origCmd); + mResponses.add(found); + } + } + try { + synchronized (found) { + found.wait(endTime - nowTime); + } + } catch (InterruptedException e) { + // loop around to check if we're done or if it's time to stop waiting + } + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Pending requests:"); + synchronized (mResponses) { + for (Response response : mResponses) { + pw.println(" Cmd " + response.cmdNum + " - " + response.request); + } + } + } + } } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index 62084c072a..50ba6d19a7 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -28,16 +28,22 @@ public class NativeDaemonEvent { // TODO: keep class ranges in sync with ResponseCode.h // TODO: swap client and server error ranges to roughly mirror HTTP spec + private final int mCmdNumber; private final int mCode; private final String mMessage; private final String mRawEvent; - private NativeDaemonEvent(int code, String message, String rawEvent) { + private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { + mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; } + public int getCmdNumber() { + return mCmdNumber; + } + public int getCode() { return mCode; } @@ -110,20 +116,28 @@ public class NativeDaemonEvent { * from native side. */ public static NativeDaemonEvent parseRawEvent(String rawEvent) { - final int splitIndex = rawEvent.indexOf(' '); - if (splitIndex == -1) { + final String[] parsed = rawEvent.split(" "); + if (parsed.length < 3) { throw new IllegalArgumentException("unable to find ' ' separator"); } + final int cmdNumber; + try { + cmdNumber = Integer.parseInt(parsed[0]); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("problem parsing cmdNumber", e); + } + final int code; try { - code = Integer.parseInt(rawEvent.substring(0, splitIndex)); + code = Integer.parseInt(parsed[1]); } catch (NumberFormatException e) { throw new IllegalArgumentException("problem parsing code", e); } - final String message = rawEvent.substring(splitIndex + 1); - return new NativeDaemonEvent(code, message, rawEvent); + final String message = rawEvent.substring(parsed[0].length() + parsed[1].length() + 2); + + return new NativeDaemonEvent(cmdNumber, code, message, rawEvent); } /** From 8fa213f4c53eb4654e7535ee9ace3d3d5a144143 Mon Sep 17 00:00:00 2001 From: Guang Zhu Date: Tue, 7 Feb 2012 19:14:02 -0800 Subject: [PATCH 0123/1150] Revert "Make NDC not block forever and handle restart." Reverting because it seems to break `adb reboot` This reverts commit 5c7de0b4ec0322ba357d323fa3ae76d3d982d974. Change-Id: I75d827664a08799de15369c24c84cc3f49a8f297 --- .../android/server/NativeDaemonConnector.java | 227 ++++-------------- .../com/android/server/NativeDaemonEvent.java | 26 +- 2 files changed, 58 insertions(+), 195 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 5319432710..308661f1b0 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -34,8 +34,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.LinkedList; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; /** * Generic connector class for interfacing with a native daemon which uses the @@ -50,15 +50,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private OutputStream mOutputStream; private LocalLog mLocalLog; - private final ResponseQueue mResponseQueue; + private final BlockingQueue mResponseQueue; private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; - private AtomicInteger mSequenceNumber; - - private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ - /** Lock held whenever communicating with native daemon. */ private final Object mDaemonLock = new Object(); @@ -68,8 +64,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; mSocket = socket; - mResponseQueue = new ResponseQueue(responseQueueSize); - mSequenceNumber = new AtomicInteger(0); + mResponseQueue = new LinkedBlockingQueue(responseQueueSize); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); } @@ -84,7 +79,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo try { listenToSocket(); } catch (Exception e) { - loge("Error in NativeDaemonConnector: " + e); + Slog.e(TAG, "Error in NativeDaemonConnector", e); SystemClock.sleep(5000); } } @@ -95,10 +90,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { - log(String.format("Unhandled event '%s'", event)); + Slog.w(TAG, String.format( + "Unhandled event '%s'", event)); } } catch (Exception e) { - loge("Error handling '" + event + "': " + e); + Slog.e(TAG, String.format( + "Error handling '%s'", event), e); } return true; } @@ -114,9 +111,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.connect(address); InputStream inputStream = socket.getInputStream(); - synchronized (mDaemonLock) { - mOutputStream = socket.getOutputStream(); - } + mOutputStream = socket.getOutputStream(); mCallbacks.onDaemonConnected(); @@ -125,10 +120,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) { - loge("got " + count + " reading with start = " + start); - break; - } + if (count < 0) break; // Add our starting point to the count and reset the start. count += start; @@ -148,10 +140,14 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { - mResponseQueue.add(event.getCmdNumber(), event); + try { + mResponseQueue.put(event); + } catch (InterruptedException ex) { + Slog.e(TAG, "Failed to put response onto queue: " + ex); + } } } catch (IllegalArgumentException e) { - log("Problem parsing message: " + rawEvent + " - " + e); + Slog.w(TAG, "Problem parsing message: " + rawEvent, e); } start = i + 1; @@ -173,16 +169,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } } catch (IOException ex) { - loge("Communications error: " + ex); + Slog.e(TAG, "Communications error", ex); throw ex; } finally { synchronized (mDaemonLock) { if (mOutputStream != null) { try { - loge("closing stream for " + mSocket); mOutputStream.close(); } catch (IOException e) { - loge("Failed closing output stream: " + e); + Slog.w(TAG, "Failed closing output stream", e); } mOutputStream = null; } @@ -193,17 +188,17 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.close(); } } catch (IOException ex) { - loge("Failed closing socket: " + ex); + Slog.w(TAG, "Failed closing socket", ex); } } } /** - * Make command for daemon, escaping arguments as needed. + * Send command to daemon, escaping arguments as needed. * - * @return the final command. + * @return the final command issued. */ - private StringBuilder makeCommand(String cmd, Object... args) + private String sendCommandLocked(String cmd, Object... args) throws NativeDaemonConnectorException { // TODO: eventually enforce that cmd doesn't contain arguments if (cmd.indexOf('\0') >= 0) { @@ -221,33 +216,22 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo appendEscaped(builder, argString); } - return builder; - } - - private int sendCommand(StringBuilder builder) - throws NativeDaemonConnectorException { - - int sequenceNumber = mSequenceNumber.incrementAndGet(); - - builder.insert(0, Integer.toString(sequenceNumber) + " "); - - if (LOGD) log("SND -> {" + builder.toString() + "}"); + final String unterminated = builder.toString(); + log("SND -> {" + unterminated + "}"); builder.append('\0'); - synchronized (mDaemonLock) { - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { + try { + mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); } } - return sequenceNumber; + return unterminated; } /** @@ -308,41 +292,39 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { - return execute(DEFAULT_TIMEOUT, cmd, args); + synchronized (mDaemonLock) { + return executeLocked(cmd, args); + } } - /** - * Issue the given command to the native daemon and return any - * {@linke NativeDaemonEvent@isClassContinue()} responses, including the - * final terminal response. - * - * @throws NativeDaemonConnectorException when problem communicating with - * native daemon, or if the response matches - * {@link NativeDaemonEvent#isClassClientError()} or - * {@link NativeDaemonEvent#isClassServerError()}. - */ - public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) + private NativeDaemonEvent[] executeLocked(String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList events = Lists.newArrayList(); - final StringBuilder sentCommand = makeCommand(cmd, args); - final int cmdNumber = sendCommand(sentCommand); + + while (mResponseQueue.size() > 0) { + try { + log("ignoring {" + mResponseQueue.take() + "}"); + } catch (Exception e) {} + } + + final String sentCommand = sendCommandLocked(cmd, args); NativeDaemonEvent event = null; - cmd = sentCommand.toString(); do { - event = mResponseQueue.remove(cmdNumber, timeout, cmd); - if (event == null) { - loge("timed-out waiting for response to " + cmdNumber + " " + cmd); - throw new NativeDaemonFailureException(cmd, event); + try { + event = mResponseQueue.take(); + } catch (InterruptedException e) { + Slog.w(TAG, "interrupted waiting for event line"); + continue; } events.add(event); } while (event.isClassContinue()); if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(cmd, event); + throw new NativeDaemonArgumentException(sentCommand, event); } if (event.isClassServerError()) { - throw new NativeDaemonFailureException(cmd, event); + throw new NativeDaemonFailureException(sentCommand, event); } return events.toArray(new NativeDaemonEvent[events.size()]); @@ -466,115 +448,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mLocalLog.dump(fd, pw, args); - pw.println(); - mResponseQueue.dump(fd, pw, args); } private void log(String logstring) { if (LOGD) Slog.d(TAG, logstring); mLocalLog.log(logstring); } - - private void loge(String logstring) { - Slog.e(TAG, logstring); - mLocalLog.log(logstring); - } - - private static class ResponseQueue { - - private static class Response { - public int cmdNum; - public LinkedList responses = new LinkedList(); - public String request; - public Response(int c, String r) {cmdNum = c; request = r;} - } - - private final LinkedList mResponses; - private int mMaxCount; - - ResponseQueue(int maxCount) { - mResponses = new LinkedList(); - mMaxCount = maxCount; - } - - public void add(int cmdNum, NativeDaemonEvent response) { - Response found = null; - synchronized (mResponses) { - for (Response r : mResponses) { - if (r.cmdNum == cmdNum) { - found = r; - break; - } - } - if (found == null) { - // didn't find it - make sure our queue isn't too big before adding - // another.. - while (mResponses.size() >= mMaxCount) { - Slog.e("NativeDaemonConnector.ResponseQueue", - "more buffered than allowed: " + mResponses.size() + - " >= " + mMaxCount); - mResponses.remove(); - } - found = new Response(cmdNum, null); - mResponses.add(found); - } - found.responses.add(response); - } - synchronized (found) { - found.notify(); - } - } - - public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { - long endTime = SystemClock.uptimeMillis() + timeoutMs; - long nowTime; - Response found = null; - while (true) { - synchronized (mResponses) { - for (Response response : mResponses) { - if (response.cmdNum == cmdNum) { - found = response; - // how many response fragments are left - switch (response.responses.size()) { - case 0: // haven't got any - must wait - break; - case 1: // last one - remove this from the master list - mResponses.remove(response); // fall through - default: // take one and move on - response.request = origCmd; - return response.responses.remove(); - } - } - } - nowTime = SystemClock.uptimeMillis(); - if (endTime <= nowTime) { - Slog.e("NativeDaemonConnector.ResponseQueue", - "Timeout waiting for response"); - return null; - } - /* pre-allocate so we have something unique to wait on */ - if (found == null) { - found = new Response(cmdNum, origCmd); - mResponses.add(found); - } - } - try { - synchronized (found) { - found.wait(endTime - nowTime); - } - } catch (InterruptedException e) { - // loop around to check if we're done or if it's time to stop waiting - } - } - } - - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - pw.println("Pending requests:"); - synchronized (mResponses) { - for (Response response : mResponses) { - pw.println(" Cmd " + response.cmdNum + " - " + response.request); - } - } - } - } } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index 50ba6d19a7..62084c072a 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -28,22 +28,16 @@ public class NativeDaemonEvent { // TODO: keep class ranges in sync with ResponseCode.h // TODO: swap client and server error ranges to roughly mirror HTTP spec - private final int mCmdNumber; private final int mCode; private final String mMessage; private final String mRawEvent; - private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { - mCmdNumber = cmdNumber; + private NativeDaemonEvent(int code, String message, String rawEvent) { mCode = code; mMessage = message; mRawEvent = rawEvent; } - public int getCmdNumber() { - return mCmdNumber; - } - public int getCode() { return mCode; } @@ -116,28 +110,20 @@ public class NativeDaemonEvent { * from native side. */ public static NativeDaemonEvent parseRawEvent(String rawEvent) { - final String[] parsed = rawEvent.split(" "); - if (parsed.length < 3) { + final int splitIndex = rawEvent.indexOf(' '); + if (splitIndex == -1) { throw new IllegalArgumentException("unable to find ' ' separator"); } - final int cmdNumber; - try { - cmdNumber = Integer.parseInt(parsed[0]); - } catch (NumberFormatException e) { - throw new IllegalArgumentException("problem parsing cmdNumber", e); - } - final int code; try { - code = Integer.parseInt(parsed[1]); + code = Integer.parseInt(rawEvent.substring(0, splitIndex)); } catch (NumberFormatException e) { throw new IllegalArgumentException("problem parsing code", e); } - final String message = rawEvent.substring(parsed[0].length() + parsed[1].length() + 2); - - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent); + final String message = rawEvent.substring(splitIndex + 1); + return new NativeDaemonEvent(code, message, rawEvent); } /** From 00b8bb6e791ed72d07563084ece3d55eeebf0556 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 27 Feb 2012 17:42:34 -0800 Subject: [PATCH 0124/1150] Suppress StrictMode when reading /proc/ files. Bug: 6077051 Change-Id: If4f23e947d8b91f9f124baa0460600a6b9353732 --- .../com/android/internal/net/NetworkStatsFactory.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 41993c4128..4e3d9650f8 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -22,6 +22,7 @@ import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.net.NetworkStats; +import android.os.StrictMode; import android.os.SystemClock; import android.util.Slog; @@ -106,6 +107,8 @@ public class NetworkStatsFactory { } private NetworkStats readNetworkStatsSummarySingleFile() { + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); @@ -156,6 +159,7 @@ public class NetworkStatsFactory { throw new IllegalStateException("problem parsing stats: " + e); } finally { IoUtils.closeQuietly(reader); + StrictMode.setThreadPolicy(savedPolicy); } return stats; } @@ -165,6 +169,8 @@ public class NetworkStatsFactory { */ @Deprecated private NetworkStats readNetworkStatsSummaryMultipleFiles() { + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); @@ -241,6 +247,7 @@ public class NetworkStatsFactory { throw new IllegalStateException("problem parsing stats: " + e); } finally { IoUtils.closeQuietly(reader); + StrictMode.setThreadPolicy(savedPolicy); } return stats; @@ -257,6 +264,8 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException { + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); final NetworkStats.Entry entry = new NetworkStats.Entry(); @@ -300,6 +309,7 @@ public class NetworkStatsFactory { throw new IllegalStateException("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); + StrictMode.setThreadPolicy(savedPolicy); } return stats; From be68c7c5c70cb875cbc42c1e0ae22f04d876180b Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 27 Feb 2012 18:08:01 -0800 Subject: [PATCH 0125/1150] Move NetworkStatsFactory to faster ProcFileReader. Less GC overhead, and about 8x faster parse times. Verified that tests pass. Change-Id: Iff1d374f36103395a193176a88a57eebffa93c56 --- .../internal/net/NetworkStatsFactory.java | 85 ++++--------------- 1 file changed, 15 insertions(+), 70 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 4e3d9650f8..ccd27632b9 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -28,7 +28,6 @@ import android.util.Slog; import com.android.internal.util.ProcFileReader; import com.google.android.collect.Lists; -import com.google.android.collect.Maps; import com.google.android.collect.Sets; import java.io.BufferedReader; @@ -37,7 +36,6 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; -import java.util.HashMap; import java.util.HashSet; import java.util.StringTokenizer; @@ -63,22 +61,6 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; - /** {@link #mStatsXtUid} and {@link #mStatsXtIfaceAll} headers. */ - private static final String KEY_IDX = "idx"; - private static final String KEY_IFACE = "iface"; - private static final String KEY_ACTIVE = "active"; - private static final String KEY_UID = "uid_tag_int"; - private static final String KEY_COUNTER_SET = "cnt_set"; - private static final String KEY_TAG_HEX = "acct_tag_hex"; - private static final String KEY_SNAP_RX_BYTES = "snap_rx_bytes"; - private static final String KEY_SNAP_RX_PACKETS = "snap_rx_packets"; - private static final String KEY_SNAP_TX_BYTES = "snap_tx_bytes"; - private static final String KEY_SNAP_TX_PACKETS = "snap_tx_packets"; - private static final String KEY_RX_BYTES = "rx_bytes"; - private static final String KEY_RX_PACKETS = "rx_packets"; - private static final String KEY_TX_BYTES = "tx_bytes"; - private static final String KEY_TX_PACKETS = "tx_packets"; - public NetworkStatsFactory() { this(new File("/proc/")); } @@ -112,44 +94,34 @@ public class NetworkStatsFactory { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); - // TODO: transition to ProcFileReader - // TODO: read directly from proc once headers are added - final ArrayList keys = Lists.newArrayList(KEY_IFACE, KEY_ACTIVE, KEY_SNAP_RX_BYTES, - KEY_SNAP_RX_PACKETS, KEY_SNAP_TX_BYTES, KEY_SNAP_TX_PACKETS, KEY_RX_BYTES, - KEY_RX_PACKETS, KEY_TX_BYTES, KEY_TX_PACKETS); - final ArrayList values = Lists.newArrayList(); - final HashMap parsed = Maps.newHashMap(); - - BufferedReader reader = null; + ProcFileReader reader = null; try { - reader = new BufferedReader(new FileReader(mStatsXtIfaceAll)); + reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceAll)); - String line; - while ((line = reader.readLine()) != null) { - splitLine(line, values); - parseLine(keys, values, parsed); - - entry.iface = parsed.get(KEY_IFACE); + while (reader.hasMoreData()) { + entry.iface = reader.nextString(); entry.uid = UID_ALL; entry.set = SET_DEFAULT; entry.tag = TAG_NONE; + final boolean active = reader.nextInt() != 0; + // always include snapshot values - entry.rxBytes = getParsedLong(parsed, KEY_SNAP_RX_BYTES); - entry.rxPackets = getParsedLong(parsed, KEY_SNAP_RX_PACKETS); - entry.txBytes = getParsedLong(parsed, KEY_SNAP_TX_BYTES); - entry.txPackets = getParsedLong(parsed, KEY_SNAP_TX_PACKETS); + entry.rxBytes = reader.nextLong(); + entry.rxPackets = reader.nextLong(); + entry.txBytes = reader.nextLong(); + entry.txPackets = reader.nextLong(); // fold in active numbers, but only when active - final boolean active = getParsedInt(parsed, KEY_ACTIVE) != 0; if (active) { - entry.rxBytes += getParsedLong(parsed, KEY_RX_BYTES); - entry.rxPackets += getParsedLong(parsed, KEY_RX_PACKETS); - entry.txBytes += getParsedLong(parsed, KEY_TX_BYTES); - entry.txPackets += getParsedLong(parsed, KEY_TX_PACKETS); + entry.rxBytes += reader.nextLong(); + entry.rxPackets += reader.nextLong(); + entry.txBytes += reader.nextLong(); + entry.txPackets += reader.nextLong(); } stats.addValues(entry); + reader.finishLine(); } } catch (NullPointerException e) { throw new IllegalStateException("problem parsing stats: " + e); @@ -315,18 +287,6 @@ public class NetworkStatsFactory { return stats; } - @Deprecated - private static int getParsedInt(HashMap parsed, String key) { - final String value = parsed.get(key); - return value != null ? Integer.parseInt(value) : 0; - } - - @Deprecated - private static long getParsedLong(HashMap parsed, String key) { - final String value = parsed.get(key); - return value != null ? Long.parseLong(value) : 0; - } - /** * Split given line into {@link ArrayList}. */ @@ -340,21 +300,6 @@ public class NetworkStatsFactory { } } - /** - * Zip the two given {@link ArrayList} as key and value pairs into - * {@link HashMap}. - */ - @Deprecated - private static void parseLine( - ArrayList keys, ArrayList values, HashMap outParsed) { - outParsed.clear(); - - final int size = Math.min(keys.size(), values.size()); - for (int i = 0; i < size; i++) { - outParsed.put(keys.get(i), values.get(i)); - } - } - /** * Utility method to read a single plain-text {@link Long} from the given * {@link File}, usually from a {@code /proc/} filesystem. From 30aab0989d9ead95d06a35f03877f9a8f71a7c0d Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 28 Feb 2012 15:13:08 -0800 Subject: [PATCH 0126/1150] Disable verbose NetworkStats logging. Bug: 6076584 Change-Id: I4efcda2b474f623f4fe70db8b43b0aa69017d749 --- services/java/com/android/server/net/NetworkStatsRecorder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 240cc1c875..290bd2cc49 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -50,7 +50,7 @@ import java.util.Map; */ public class NetworkStatsRecorder { private static final String TAG = "NetworkStatsRecorder"; - private static final boolean LOGD = true; + private static final boolean LOGD = false; private static final boolean LOGV = false; private final FileRotator mRotator; From 7f03e4444357486f9f9271b6862930b47fb0443a Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 7 Feb 2012 11:36:55 -0800 Subject: [PATCH 0127/1150] Make NDC not block forever and handle restart. Still possible for netd to get wedged but system won't die because of it. Leads the way to having forking netd - then only individual commands would wedge, promoting stability. bug:5864209 bug:6019952 Change-Id: I43e4c5072863b8b812d4fe24d30d92eb1a11651a --- .../android/server/NativeDaemonConnector.java | 233 ++++++++++++++---- .../com/android/server/NativeDaemonEvent.java | 43 +++- 2 files changed, 216 insertions(+), 60 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 308661f1b0..6593a0f43d 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -34,8 +34,8 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.concurrent.BlockingQueue; -import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.LinkedList; /** * Generic connector class for interfacing with a native daemon which uses the @@ -50,11 +50,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private OutputStream mOutputStream; private LocalLog mLocalLog; - private final BlockingQueue mResponseQueue; + private final ResponseQueue mResponseQueue; private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; + private AtomicInteger mSequenceNumber; + + private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ + /** Lock held whenever communicating with native daemon. */ private final Object mDaemonLock = new Object(); @@ -64,7 +68,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo int responseQueueSize, String logTag, int maxLogSize) { mCallbacks = callbacks; mSocket = socket; - mResponseQueue = new LinkedBlockingQueue(responseQueueSize); + mResponseQueue = new ResponseQueue(responseQueueSize); + mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); } @@ -79,7 +84,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo try { listenToSocket(); } catch (Exception e) { - Slog.e(TAG, "Error in NativeDaemonConnector", e); + loge("Error in NativeDaemonConnector: " + e); SystemClock.sleep(5000); } } @@ -90,12 +95,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo String event = (String) msg.obj; try { if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { - Slog.w(TAG, String.format( - "Unhandled event '%s'", event)); + log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { - Slog.e(TAG, String.format( - "Error handling '%s'", event), e); + loge("Error handling '" + event + "': " + e); } return true; } @@ -111,7 +114,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.connect(address); InputStream inputStream = socket.getInputStream(); - mOutputStream = socket.getOutputStream(); + synchronized (mDaemonLock) { + mOutputStream = socket.getOutputStream(); + } mCallbacks.onDaemonConnected(); @@ -120,7 +125,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo while (true) { int count = inputStream.read(buffer, start, BUFFER_SIZE - start); - if (count < 0) break; + if (count < 0) { + loge("got " + count + " reading with start = " + start); + break; + } // Add our starting point to the count and reset the start. count += start; @@ -140,14 +148,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { - try { - mResponseQueue.put(event); - } catch (InterruptedException ex) { - Slog.e(TAG, "Failed to put response onto queue: " + ex); - } + mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { - Slog.w(TAG, "Problem parsing message: " + rawEvent, e); + log("Problem parsing message: " + rawEvent + " - " + e); } start = i + 1; @@ -169,15 +173,16 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } } catch (IOException ex) { - Slog.e(TAG, "Communications error", ex); + loge("Communications error: " + ex); throw ex; } finally { synchronized (mDaemonLock) { if (mOutputStream != null) { try { + loge("closing stream for " + mSocket); mOutputStream.close(); } catch (IOException e) { - Slog.w(TAG, "Failed closing output stream", e); + loge("Failed closing output stream: " + e); } mOutputStream = null; } @@ -188,17 +193,17 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo socket.close(); } } catch (IOException ex) { - Slog.w(TAG, "Failed closing socket", ex); + loge("Failed closing socket: " + ex); } } } /** - * Send command to daemon, escaping arguments as needed. + * Make command for daemon, escaping arguments as needed. * - * @return the final command issued. + * @return the final command. */ - private String sendCommandLocked(String cmd, Object... args) + private StringBuilder makeCommand(String cmd, Object... args) throws NativeDaemonConnectorException { // TODO: eventually enforce that cmd doesn't contain arguments if (cmd.indexOf('\0') >= 0) { @@ -216,22 +221,33 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo appendEscaped(builder, argString); } - final String unterminated = builder.toString(); - log("SND -> {" + unterminated + "}"); + return builder; + } + + private int sendCommand(StringBuilder builder) + throws NativeDaemonConnectorException { + + int sequenceNumber = mSequenceNumber.incrementAndGet(); + + builder.insert(0, Integer.toString(sequenceNumber) + " "); + + log("SND -> {" + builder.toString() + "}"); builder.append('\0'); - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); + synchronized (mDaemonLock) { + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { + try { + mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); + } } } - return unterminated; + return sequenceNumber; } /** @@ -292,39 +308,42 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { - synchronized (mDaemonLock) { - return executeLocked(cmd, args); - } + return execute(DEFAULT_TIMEOUT, cmd, args); } - private NativeDaemonEvent[] executeLocked(String cmd, Object... args) + /** + * Issue the given command to the native daemon and return any + * {@linke NativeDaemonEvent@isClassContinue()} responses, including the + * final terminal response. Note that the timeout does not count time in + * deep sleep. + * + * @throws NativeDaemonConnectorException when problem communicating with + * native daemon, or if the response matches + * {@link NativeDaemonEvent#isClassClientError()} or + * {@link NativeDaemonEvent#isClassServerError()}. + */ + public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList events = Lists.newArrayList(); - - while (mResponseQueue.size() > 0) { - try { - log("ignoring {" + mResponseQueue.take() + "}"); - } catch (Exception e) {} - } - - final String sentCommand = sendCommandLocked(cmd, args); + final StringBuilder sentCommand = makeCommand(cmd, args); + final int cmdNumber = sendCommand(sentCommand); NativeDaemonEvent event = null; + cmd = sentCommand.toString(); do { - try { - event = mResponseQueue.take(); - } catch (InterruptedException e) { - Slog.w(TAG, "interrupted waiting for event line"); - continue; + event = mResponseQueue.remove(cmdNumber, timeout, cmd); + if (event == null) { + loge("timed-out waiting for response to " + cmdNumber + " " + cmd); + throw new NativeDaemonFailureException(cmd, event); } events.add(event); } while (event.isClassContinue()); if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(sentCommand, event); + throw new NativeDaemonArgumentException(cmd, event); } if (event.isClassServerError()) { - throw new NativeDaemonFailureException(sentCommand, event); + throw new NativeDaemonFailureException(cmd, event); } return events.toArray(new NativeDaemonEvent[events.size()]); @@ -448,10 +467,120 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mLocalLog.dump(fd, pw, args); + pw.println(); + mResponseQueue.dump(fd, pw, args); } private void log(String logstring) { if (LOGD) Slog.d(TAG, logstring); mLocalLog.log(logstring); } + + private void loge(String logstring) { + Slog.e(TAG, logstring); + mLocalLog.log(logstring); + } + + private static class ResponseQueue { + + private static class Response { + public int cmdNum; + public LinkedList responses = new LinkedList(); + public String request; + public Response(int c, String r) {cmdNum = c; request = r;} + } + + private final LinkedList mResponses; + private int mMaxCount; + + ResponseQueue(int maxCount) { + mResponses = new LinkedList(); + mMaxCount = maxCount; + } + + public void add(int cmdNum, NativeDaemonEvent response) { + Response found = null; + synchronized (mResponses) { + for (Response r : mResponses) { + if (r.cmdNum == cmdNum) { + found = r; + break; + } + } + if (found == null) { + // didn't find it - make sure our queue isn't too big before adding + // another.. + while (mResponses.size() >= mMaxCount) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "more buffered than allowed: " + mResponses.size() + + " >= " + mMaxCount); + // let any waiter timeout waiting for this + Response r = mResponses.remove(); + Slog.e("NativeDaemonConnector.ResponseQueue", + "Removing request: " + r.request + " (" + r.cmdNum + ")"); + } + found = new Response(cmdNum, null); + mResponses.add(found); + } + found.responses.add(response); + } + synchronized (found) { + found.notify(); + } + } + + // note that the timeout does not count time in deep sleep. If you don't want + // the device to sleep, hold a wakelock + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + long endTime = SystemClock.uptimeMillis() + timeoutMs; + long nowTime; + Response found = null; + while (true) { + synchronized (mResponses) { + for (Response response : mResponses) { + if (response.cmdNum == cmdNum) { + found = response; + // how many response fragments are left + switch (response.responses.size()) { + case 0: // haven't got any - must wait + break; + case 1: // last one - remove this from the master list + mResponses.remove(response); // fall through + default: // take one and move on + response.request = origCmd; + return response.responses.remove(); + } + } + } + nowTime = SystemClock.uptimeMillis(); + if (endTime <= nowTime) { + Slog.e("NativeDaemonConnector.ResponseQueue", + "Timeout waiting for response"); + return null; + } + /* pre-allocate so we have something unique to wait on */ + if (found == null) { + found = new Response(cmdNum, origCmd); + mResponses.add(found); + } + } + try { + synchronized (found) { + found.wait(endTime - nowTime); + } + } catch (InterruptedException e) { + // loop around to check if we're done or if it's time to stop waiting + } + } + } + + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.println("Pending requests:"); + synchronized (mResponses) { + for (Response response : mResponses) { + pw.println(" Cmd " + response.cmdNum + " - " + response.request); + } + } + } + } } diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index 62084c072a..d5e9f66027 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -28,16 +28,22 @@ public class NativeDaemonEvent { // TODO: keep class ranges in sync with ResponseCode.h // TODO: swap client and server error ranges to roughly mirror HTTP spec + private final int mCmdNumber; private final int mCode; private final String mMessage; private final String mRawEvent; - private NativeDaemonEvent(int code, String message, String rawEvent) { + private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { + mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; } + public int getCmdNumber() { + return mCmdNumber; + } + public int getCode() { return mCode; } @@ -89,7 +95,11 @@ public class NativeDaemonEvent { * Test if event represents an unsolicited event from native daemon. */ public boolean isClassUnsolicited() { - return mCode >= 600 && mCode < 700; + return isClassUnsolicited(mCode); + } + + private static boolean isClassUnsolicited(int code) { + return code >= 600 && code < 700; } /** @@ -110,20 +120,37 @@ public class NativeDaemonEvent { * from native side. */ public static NativeDaemonEvent parseRawEvent(String rawEvent) { - final int splitIndex = rawEvent.indexOf(' '); - if (splitIndex == -1) { - throw new IllegalArgumentException("unable to find ' ' separator"); + final String[] parsed = rawEvent.split(" "); + if (parsed.length < 2) { + throw new IllegalArgumentException("Insufficient arguments"); } + int skiplength = 0; + final int code; try { - code = Integer.parseInt(rawEvent.substring(0, splitIndex)); + code = Integer.parseInt(parsed[0]); + skiplength = parsed[0].length() + 1; } catch (NumberFormatException e) { throw new IllegalArgumentException("problem parsing code", e); } - final String message = rawEvent.substring(splitIndex + 1); - return new NativeDaemonEvent(code, message, rawEvent); + int cmdNumber = -1; + if (isClassUnsolicited(code) == false) { + if (parsed.length < 3) { + throw new IllegalArgumentException("Insufficient arguemnts"); + } + try { + cmdNumber = Integer.parseInt(parsed[1]); + skiplength += parsed[1].length() + 1; + } catch (NumberFormatException e) { + throw new IllegalArgumentException("problem parsing cmdNumber", e); + } + } + + final String message = rawEvent.substring(skiplength); + + return new NativeDaemonEvent(cmdNumber, code, message, rawEvent); } /** From 0097f853482eb34dad5fe991babc4e61ed251031 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 6 Mar 2012 19:59:57 -0800 Subject: [PATCH 0128/1150] Avoid updating network stats after shutdown. Bug: 6109476 Change-Id: I9a3a8b182c8fa56d83ddc755d204d5b267c9bc5d --- .../java/com/android/server/net/NetworkStatsService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 13c0640e5f..fd8d411842 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -212,6 +212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final HandlerThread mHandlerThread; private final Handler mHandler; + private boolean mSystemReady; + public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), @@ -250,6 +252,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { + mSystemReady = true; + if (!isBandwidthControlEnabled()) { Slog.w(TAG, "bandwidth controls disabled, unable to track stats"); return; @@ -336,6 +340,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidTagRecorder = null; mDevStatsCached = null; + + mSystemReady = false; } private void maybeUpgradeLegacyStatsLocked() { @@ -649,6 +655,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ private void updateIfacesLocked() { + if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); // take one last stats snapshot before updating iface mapping. this @@ -737,7 +744,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkStatsHistory}. */ private void performPollLocked(int flags) { + if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); + final long startRealtime = SystemClock.elapsedRealtime(); final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; From 69e1f3ae657a88fda818b19b337061c5604c5565 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 12 Mar 2012 15:37:40 -0700 Subject: [PATCH 0129/1150] Record the trimmed cmd string for logs The over the wire command includes a \0 that mangles log messages. bug:6149176 Change-Id: I77d4e443f1966bff060f1b97570851f7549fee8e --- .../android/server/NativeDaemonConnector.java | 71 ++++++++----------- 1 file changed, 31 insertions(+), 40 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 6593a0f43d..0b5eaffe7f 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -200,17 +200,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo /** * Make command for daemon, escaping arguments as needed. - * - * @return the final command. */ - private StringBuilder makeCommand(String cmd, Object... args) + private void makeCommand(StringBuilder builder, String cmd, Object... args) throws NativeDaemonConnectorException { // TODO: eventually enforce that cmd doesn't contain arguments if (cmd.indexOf('\0') >= 0) { throw new IllegalArgumentException("unexpected command: " + cmd); } - final StringBuilder builder = new StringBuilder(cmd); + builder.append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { @@ -220,34 +218,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo builder.append(' '); appendEscaped(builder, argString); } - - return builder; - } - - private int sendCommand(StringBuilder builder) - throws NativeDaemonConnectorException { - - int sequenceNumber = mSequenceNumber.incrementAndGet(); - - builder.insert(0, Integer.toString(sequenceNumber) + " "); - - log("SND -> {" + builder.toString() + "}"); - - builder.append('\0'); - - synchronized (mDaemonLock) { - if (mOutputStream == null) { - throw new NativeDaemonConnectorException("missing output stream"); - } else { - try { - mOutputStream.write(builder.toString().getBytes(Charsets.UTF_8)); - } catch (IOException e) { - throw new NativeDaemonConnectorException("problem sending command", e); - } - } - } - - return sequenceNumber; } /** @@ -325,25 +295,46 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { final ArrayList events = Lists.newArrayList(); - final StringBuilder sentCommand = makeCommand(cmd, args); - final int cmdNumber = sendCommand(sentCommand); + + final int sequenceNumber = mSequenceNumber.incrementAndGet(); + final StringBuilder cmdBuilder = + new StringBuilder(Integer.toString(sequenceNumber)).append(' '); + + makeCommand(cmdBuilder, cmd, args); + + final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ + log("SND -> {" + logCmd + "}"); + + cmdBuilder.append('\0'); + final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ + + synchronized (mDaemonLock) { + if (mOutputStream == null) { + throw new NativeDaemonConnectorException("missing output stream"); + } else { + try { + mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + } catch (IOException e) { + throw new NativeDaemonConnectorException("problem sending command", e); + } + } + } NativeDaemonEvent event = null; - cmd = sentCommand.toString(); do { - event = mResponseQueue.remove(cmdNumber, timeout, cmd); + event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); if (event == null) { - loge("timed-out waiting for response to " + cmdNumber + " " + cmd); - throw new NativeDaemonFailureException(cmd, event); + loge("timed-out waiting for response to " + logCmd); + throw new NativeDaemonFailureException(logCmd, event); } events.add(event); } while (event.isClassContinue()); if (event.isClassClientError()) { - throw new NativeDaemonArgumentException(cmd, event); + throw new NativeDaemonArgumentException(logCmd, event); } if (event.isClassServerError()) { - throw new NativeDaemonFailureException(cmd, event); + throw new NativeDaemonFailureException(logCmd, event); } return events.toArray(new NativeDaemonEvent[events.size()]); From 8e38f3ddde611b6c3bcdc5a1654f800500db6903 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Mar 2012 11:11:54 -0700 Subject: [PATCH 0130/1150] Combine network subtypes by default. Subtype controls (3G-vs-4G) aren't exposed in the UI, so tracking data with that granularity creates unnecessary overhead. For example, some GSM networks can regularly flap between two subtypes. Bug: 6118868 Change-Id: Id098891dba52336d00d0f96632a7924e228b4713 --- core/java/android/net/NetworkIdentity.java | 20 +++++++++++++------ core/java/android/net/NetworkTemplate.java | 12 +++++++++++ .../server/net/NetworkStatsService.java | 9 +++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1a74abf26c..ee12989a00 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -31,6 +31,14 @@ import com.android.internal.util.Objects; * @hide */ public class NetworkIdentity { + /** + * When enabled, combine all {@link #mSubType} together under + * {@link #SUBTYPE_COMBINED}. + */ + public static final boolean COMBINE_SUBTYPE_ENABLED = true; + + public static final int SUBTYPE_COMBINED = -1; + final int mType; final int mSubType; final String mSubscriberId; @@ -38,7 +46,7 @@ public class NetworkIdentity { public NetworkIdentity(int type, int subType, String subscriberId, boolean roaming) { this.mType = type; - this.mSubType = subType; + this.mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; this.mSubscriberId = subscriberId; this.mRoaming = roaming; } @@ -52,9 +60,8 @@ public class NetworkIdentity { public boolean equals(Object obj) { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; - return mType == ident.mType && mSubType == ident.mSubType - && Objects.equal(mSubscriberId, ident.mSubscriberId) - && mRoaming == ident.mRoaming; + return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming + && Objects.equal(mSubscriberId, ident.mSubscriberId); } return false; } @@ -63,7 +70,9 @@ public class NetworkIdentity { public String toString() { final String typeName = ConnectivityManager.getNetworkTypeName(mType); final String subTypeName; - if (ConnectivityManager.isNetworkTypeMobile(mType)) { + if (COMBINE_SUBTYPE_ENABLED) { + subTypeName = "COMBINED"; + } else if (ConnectivityManager.isNetworkTypeMobile(mType)) { subTypeName = TelephonyManager.getNetworkTypeName(mSubType); } else { subTypeName = Integer.toString(mSubType); @@ -130,5 +139,4 @@ public class NetworkIdentity { } return new NetworkIdentity(type, subType, subscriberId, roaming); } - } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 8ebfd8d0aa..204ef7654e 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.scrubSubscriberId; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -77,6 +78,7 @@ public class NetworkTemplate implements Parcelable { * uses statistics for requested IMSI. */ public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { + ensureSubtypeAvailable(); return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId); } @@ -86,6 +88,7 @@ public class NetworkTemplate implements Parcelable { * requested IMSI. */ public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { + ensureSubtypeAvailable(); return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId); } @@ -199,6 +202,7 @@ public class NetworkTemplate implements Parcelable { * Check if mobile network classified 3G or lower with matching IMSI. */ private boolean matchesMobile3gLower(NetworkIdentity ident) { + ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { return false; } else if (matchesMobile(ident)) { @@ -216,6 +220,7 @@ public class NetworkTemplate implements Parcelable { * Check if mobile network classified 4G with matching IMSI. */ private boolean matchesMobile4g(NetworkIdentity ident) { + ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { // TODO: consider matching against WiMAX subscriber identity return true; @@ -268,6 +273,13 @@ public class NetworkTemplate implements Parcelable { } } + private static void ensureSubtypeAvailable() { + if (COMBINE_SUBTYPE_ENABLED) { + throw new IllegalArgumentException( + "Unable to enforce 3G_LOWER template on combined data."); + } + } + public static final Creator CREATOR = new Creator() { public NetworkTemplate createFromParcel(Parcel in) { return new NetworkTemplate(in); diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index fd8d411842..8796afc06a 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -304,7 +305,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // watch for networkType changes that aren't broadcast through // CONNECTIVITY_ACTION_IMMEDIATE above. - mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); + } registerPollAlarmLocked(); registerGlobalAlert(); @@ -325,7 +328,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); From e4474c8bfeba099f403bf796a537a2ad35ba68ac Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Mar 2012 11:54:01 -0700 Subject: [PATCH 0131/1150] Remove network subtype check when building template. Change-Id: I069d82a77d27dae6bfffe3b7e65d73b63f258ad9 --- core/java/android/net/NetworkTemplate.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 204ef7654e..e1fbdcc705 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -78,7 +78,6 @@ public class NetworkTemplate implements Parcelable { * uses statistics for requested IMSI. */ public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { - ensureSubtypeAvailable(); return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId); } @@ -88,7 +87,6 @@ public class NetworkTemplate implements Parcelable { * requested IMSI. */ public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { - ensureSubtypeAvailable(); return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId); } From 77ec5581edbb8dba043fc69bf81e1d1dbeee5f6c Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 22 Mar 2012 17:01:39 -0700 Subject: [PATCH 0132/1150] Add initial framework for DNS service discovery Change-Id: I53c0b7ebfd75e520ebb7553612f1aa8413b6b79b --- core/java/android/net/nsd/INsdManager.aidl | 29 ++ core/java/android/net/nsd/NsdManager.java | 394 ++++++++++++++++++ .../java/com/android/server/NsdService.java | 269 ++++++++++++ 3 files changed, 692 insertions(+) create mode 100644 core/java/android/net/nsd/INsdManager.aidl create mode 100644 core/java/android/net/nsd/NsdManager.java create mode 100644 services/java/com/android/server/NsdService.java diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl new file mode 100644 index 0000000000..077a675a14 --- /dev/null +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2012, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +import android.os.Messenger; + +/** + * Interface that NsdService implements + * + * {@hide} + */ +interface INsdManager +{ + Messenger getMessenger(); +} diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java new file mode 100644 index 0000000000..a109a983fd --- /dev/null +++ b/core/java/android/net/nsd/NsdManager.java @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +import android.content.Context; +import android.os.Binder; +import android.os.IBinder; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.RemoteException; +import android.os.Messenger; +import android.util.Log; + +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; + +/** + * The Network Service Discovery Manager class provides the API for service + * discovery. Service discovery enables applications to discover and connect with services + * on a network. Example applications include a game application discovering another instance + * of the game application or a printer application discovering other printers on a network. + * + *

The API is asynchronous and responses to requests from an application are on listener + * callbacks provided by the application. The application needs to do an initialization with + * {@link #initialize} before doing any operation. + * + *

Android currently supports DNS based service discovery and it is limited to a local + * network with the use of multicast DNS. In future, this class will be + * extended to support other service discovery mechanisms. + * + * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) + * Context.getSystemService(Context.NSD_SERVICE)}. + * @hide + * + */ +public class NsdManager { + private static final String TAG = "NsdManager"; + INsdManager mService; + + private static final int BASE = Protocol.BASE_NSD_MANAGER; + + /** @hide */ + public static final int DISCOVER_SERVICES = BASE + 1; + /** @hide */ + public static final int DISCOVER_SERVICES_STARTED = BASE + 2; + /** @hide */ + public static final int DISCOVER_SERVICES_FAILED = BASE + 3; + /** @hide */ + public static final int SERVICE_FOUND = BASE + 4; + /** @hide */ + public static final int SERVICE_LOST = BASE + 5; + + /** @hide */ + public static final int STOP_DISCOVERY = BASE + 6; + /** @hide */ + public static final int STOP_DISCOVERY_FAILED = BASE + 7; + /** @hide */ + public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8; + + /** @hide */ + public static final int REGISTER_SERVICE = BASE + 9; + /** @hide */ + public static final int REGISTER_SERVICE_FAILED = BASE + 10; + /** @hide */ + public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11; + + /** @hide */ + public static final int UPDATE_SERVICE = BASE + 12; + /** @hide */ + public static final int UPDATE_SERVICE_FAILED = BASE + 13; + /** @hide */ + public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 14; + + /** @hide */ + public static final int RESOLVE_SERVICE = BASE + 15; + /** @hide */ + public static final int RESOLVE_SERVICE_FAILED = BASE + 16; + /** @hide */ + public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17; + + /** + * Create a new Nsd instance. Applications use + * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve + * {@link android.content.Context#NSD_SERVICE Context.NSD_SERVICE}. + * @param service the Binder interface + * @hide - hide this because it takes in a parameter of type INsdManager, which + * is a system private class. + */ + public NsdManager(INsdManager service) { + mService = service; + } + + /** + * Indicates that the operation failed due to an internal error. + */ + public static final int ERROR = 0; + + /** + * Indicates that the operation failed because service discovery is unsupported on the device. + */ + public static final int UNSUPPORTED = 1; + + /** + * Indicates that the operation failed because the framework is busy and + * unable to service the request + */ + public static final int BUSY = 2; + + /** Interface for callback invocation when framework channel is connected or lost */ + public interface ChannelListener { + public void onChannelConnected(Channel c); + /** + * The channel to the framework has been disconnected. + * Application could try re-initializing using {@link #initialize} + */ + public void onChannelDisconnected(); + } + + public interface ActionListener { + + public void onFailure(int errorCode); + + public void onSuccess(); + } + + public interface DnsSdDiscoveryListener { + + public void onFailure(int errorCode); + + public void onStarted(String registrationType); + + public void onServiceFound(DnsSdServiceInfo serviceInfo); + + public void onServiceLost(DnsSdServiceInfo serviceInfo); + + } + + public interface DnsSdRegisterListener { + + public void onFailure(int errorCode); + + public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo); + } + + public interface DnsSdUpdateRegistrationListener { + + public void onFailure(int errorCode); + + public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord); + } + + public interface DnsSdResolveListener { + + public void onFailure(int errorCode); + + public void onServiceResolved(DnsSdServiceInfo serviceInfo); + } + + /** + * A channel that connects the application to the NetworkService framework. + * Most service operations require a Channel as an argument. An instance of Channel is obtained + * by doing a call on {@link #initialize} + */ + public static class Channel { + Channel(Looper looper, ChannelListener l) { + mAsyncChannel = new AsyncChannel(); + mHandler = new ServiceHandler(looper); + mChannelListener = l; + } + private ChannelListener mChannelListener; + private DnsSdDiscoveryListener mDnsSdDiscoveryListener; + private ActionListener mDnsSdStopDiscoveryListener; + private DnsSdRegisterListener mDnsSdRegisterListener; + private DnsSdUpdateRegistrationListener mDnsSdUpdateListener; + private DnsSdResolveListener mDnsSdResolveListener; + + AsyncChannel mAsyncChannel; + ServiceHandler mHandler; + class ServiceHandler extends Handler { + ServiceHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + switch (message.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + break; + case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: + if (mChannelListener != null) { + mChannelListener.onChannelConnected(Channel.this); + } + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (mChannelListener != null) { + mChannelListener.onChannelDisconnected(); + mChannelListener = null; + } + break; + case DISCOVER_SERVICES_STARTED: + if (mDnsSdDiscoveryListener != null) { + mDnsSdDiscoveryListener.onStarted((String) message.obj); + } + break; + case DISCOVER_SERVICES_FAILED: + if (mDnsSdDiscoveryListener != null) { + mDnsSdDiscoveryListener.onFailure(message.arg1); + } + break; + case SERVICE_FOUND: + if (mDnsSdDiscoveryListener != null) { + mDnsSdDiscoveryListener.onServiceFound( + (DnsSdServiceInfo) message.obj); + } + break; + case SERVICE_LOST: + if (mDnsSdDiscoveryListener != null) { + mDnsSdDiscoveryListener.onServiceLost( + (DnsSdServiceInfo) message.obj); + } + break; + case STOP_DISCOVERY_FAILED: + if (mDnsSdStopDiscoveryListener != null) { + mDnsSdStopDiscoveryListener.onFailure(message.arg1); + } + break; + case STOP_DISCOVERY_SUCCEEDED: + if (mDnsSdStopDiscoveryListener != null) { + mDnsSdStopDiscoveryListener.onSuccess(); + } + break; + case REGISTER_SERVICE_FAILED: + if (mDnsSdRegisterListener != null) { + mDnsSdRegisterListener.onFailure(message.arg1); + } + break; + case REGISTER_SERVICE_SUCCEEDED: + if (mDnsSdRegisterListener != null) { + mDnsSdRegisterListener.onServiceRegistered(message.arg1, + (DnsSdServiceInfo) message.obj); + } + break; + case UPDATE_SERVICE_FAILED: + if (mDnsSdUpdateListener != null) { + mDnsSdUpdateListener.onFailure(message.arg1); + } + break; + case UPDATE_SERVICE_SUCCEEDED: + if (mDnsSdUpdateListener != null) { + mDnsSdUpdateListener.onServiceUpdated(message.arg1, + (DnsSdTxtRecord) message.obj); + } + break; + case RESOLVE_SERVICE_FAILED: + if (mDnsSdResolveListener != null) { + mDnsSdResolveListener.onFailure(message.arg1); + } + break; + case RESOLVE_SERVICE_SUCCEEDED: + if (mDnsSdResolveListener != null) { + mDnsSdResolveListener.onServiceResolved( + (DnsSdServiceInfo) message.obj); + } + break; + default: + Log.d(TAG, "Ignored " + message); + break; + } + } + } + } + + /** + * Registers the application with the service discovery framework. This function + * must be the first to be called before any other operations are performed. No service + * discovery operations must be performed until the ChannelListener callback notifies + * that the channel is connected + * + * @param srcContext is the context of the source + * @param srcLooper is the Looper on which the callbacks are receivied + * @param listener for callback at loss of framework communication. + */ + public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { + Messenger messenger = getMessenger(); + if (messenger == null) throw new RuntimeException("Failed to initialize"); + if (listener == null) throw new IllegalArgumentException("ChannelListener cannot be null"); + + Channel c = new Channel(srcLooper, listener); + c.mAsyncChannel.connect(srcContext, c.mHandler, messenger); + } + + /** + * Set the listener for service discovery. Can be null. + */ + public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdDiscoveryListener = b; + } + + /** + * Set the listener for stop service discovery. Can be null. + */ + public void setStopDiscoveryListener(Channel c, ActionListener a) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdStopDiscoveryListener = a; + } + + /** + * Set the listener for service registration. Can be null. + */ + public void setRegisterListener(Channel c, DnsSdRegisterListener b) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdRegisterListener = b; + } + + /** + * Set the listener for service registration. Can be null. + */ + public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdUpdateListener = b; + } + + /** + * Set the listener for service resolution. Can be null. + */ + public void setResolveListener(Channel c, DnsSdResolveListener b) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdResolveListener = b; + } + + public void registerService(Channel c, DnsSdServiceInfo serviceInfo) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo"); + c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo); + } + + public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord); + } + + public void discoverServices(Channel c, String serviceType) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + if (c.mDnsSdDiscoveryListener == null) throw new + IllegalStateException("Discovery listener needs to be set first"); + DnsSdServiceInfo s = new DnsSdServiceInfo(); + s.setServiceType(serviceType); + c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s); + } + + public void stopServiceDiscovery(Channel c) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mAsyncChannel.sendMessage(STOP_DISCOVERY); + } + + public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo"); + if (c.mDnsSdResolveListener == null) throw new + IllegalStateException("Resolve listener needs to be set first"); + c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo); + } + + /** + * Get a reference to NetworkService handler. This is used to establish + * an AsyncChannel communication with the service + * + * @return Messenger pointing to the NetworkService handler + */ + private Messenger getMessenger() { + try { + return mService.getMessenger(); + } catch (RemoteException e) { + return null; + } + } +} diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java new file mode 100644 index 0000000000..768be7df41 --- /dev/null +++ b/services/java/com/android/server/NsdService.java @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.net.nsd.DnsSdServiceInfo; +import android.net.nsd.DnsSdTxtRecord; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; +import android.os.Binder; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.Message; +import android.os.Messenger; +import android.os.IBinder; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; +import java.util.List; + +import com.android.internal.app.IBatteryStats; +import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.AsyncChannel; +import com.android.server.am.BatteryStatsService; +import com.android.server.NativeDaemonConnector.Command; +import com.android.internal.R; + +/** + * Network Service Discovery Service handles remote service discovery operation requests by + * implementing the INsdManager interface. + * + * @hide + */ +public class NsdService extends INsdManager.Stub { + private static final String TAG = "NsdService"; + private static final String MDNS_TAG = "mDnsConnector"; + + private static final boolean DBG = true; + + private Context mContext; + + /** + * Clients receiving asynchronous messages + */ + private List mClients = new ArrayList(); + + private AsyncChannel mReplyChannel = new AsyncChannel(); + + /** + * Handles client(app) connections + */ + private class AsyncServiceHandler extends Handler { + + AsyncServiceHandler(android.os.Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + AsyncChannel c = (AsyncChannel) msg.obj; + if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); + c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); + mClients.add(c); + } else { + Slog.e(TAG, "Client connection failure, error=" + msg.arg1); + } + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.e(TAG, "Send failed, client connection lost"); + } else { + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove((AsyncChannel) msg.obj); + break; + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: + AsyncChannel ac = new AsyncChannel(); + ac.connect(mContext, this, msg.replyTo); + break; + case NsdManager.DISCOVER_SERVICES: + if (DBG) Slog.d(TAG, "Discover services"); + DnsSdServiceInfo s = (DnsSdServiceInfo) msg.obj; + discoverServices(1, s.getServiceType()); + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + break; + case NsdManager.STOP_DISCOVERY: + if (DBG) Slog.d(TAG, "Stop service discovery"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED); + break; + case NsdManager.REGISTER_SERVICE: + if (DBG) Slog.d(TAG, "Register service"); + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED); + break; + case NsdManager.UPDATE_SERVICE: + if (DBG) Slog.d(TAG, "Update service"); + mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); + break; + default: + Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg); + break; + } + } + } + private AsyncServiceHandler mAsyncServiceHandler; + + private NativeDaemonConnector mNativeConnector; + private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); + + private NsdService(Context context) { + mContext = context; + + HandlerThread nsdThread = new HandlerThread("NsdService"); + nsdThread.start(); + mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper()); + + /* + mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, + MDNS_TAG, 25); + Thread th = new Thread(mNativeConnector, MDNS_TAG); + th.start(); + */ + } + + public static NsdService create(Context context) throws InterruptedException { + NsdService service = new NsdService(context); + /* service.mNativeDaemonConnected.await(); */ + return service; + } + + public Messenger getMessenger() { + return new Messenger(mAsyncServiceHandler); + } + + /* These should be in sync with system/netd/mDnsResponseCode.h */ + class NativeResponseCode { + public static final int SERVICE_FOUND = 101; + public static final int SERVICE_LOST = 102; + public static final int SERVICE_DISCOVERY_FAILED = 103; + + public static final int SERVICE_REGISTERED = 104; + public static final int SERVICE_REGISTRATION_FAILED = 105; + + public static final int SERVICE_UPDATED = 106; + public static final int SERVICE_UPDATE_FAILED = 107; + + public static final int SERVICE_RESOLVED = 108; + public static final int SERVICE_RESOLUTION_FAILED = 109; + } + + + class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { + public void onDaemonConnected() { + mNativeDaemonConnected.countDown(); + } + + public boolean onEvent(int code, String raw, String[] cooked) { + switch (code) { + case NativeResponseCode.SERVICE_FOUND: + /* NNN uniqueId serviceName regType */ + break; + case NativeResponseCode.SERVICE_LOST: + /* NNN uniqueId serviceName regType */ + break; + case NativeResponseCode.SERVICE_DISCOVERY_FAILED: + /* NNN uniqueId errorCode */ + break; + case NativeResponseCode.SERVICE_REGISTERED: + /* NNN regId serviceName regType */ + break; + case NativeResponseCode.SERVICE_REGISTRATION_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_UPDATED: + /* NNN regId */ + break; + case NativeResponseCode.SERVICE_UPDATE_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_RESOLVED: + /* NNN resolveId fullName hostName port txtlen txtdata */ + break; + case NativeResponseCode.SERVICE_RESOLUTION_FAILED: + /* NNN resovleId errorCode */ + break; + default: + break; + } + return false; + } + } + + private void registerService(int regId, DnsSdServiceInfo service) { + try { + //Add txtlen and txtdata + mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(), + service.getServiceType(), service.getPort()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to execute registerService"); + } + } + + private void updateService(int regId, DnsSdTxtRecord t) { + try { + if (t == null) return; + mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to updateServices"); + } + } + + private void discoverServices(int discoveryId, String serviceType) { + try { + mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to discoverServices"); + } + } + + private void stopServiceDiscovery(int discoveryId) { + try { + mNativeConnector.execute("mdnssd", "stopdiscover", discoveryId); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to stopServiceDiscovery"); + } + } + + private void resolveService(DnsSdServiceInfo service) { + try { + mNativeConnector.execute("mdnssd", "resolve", service.getServiceName(), + service.getServiceType()); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to resolveService"); + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid=" + + Binder.getCallingPid() + + ", uid=" + Binder.getCallingUid()); + return; + } + + pw.println("Internal state:"); + } +} From f3f68819df8a12bc1b7cf40e5e171d97a5357dfd Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 4 Apr 2012 13:18:17 -0700 Subject: [PATCH 0133/1150] Fix build Add missing file Change-Id: I5ed1827e1183c37741675ce4d198d3e200c5fb94 --- .../android/net/nsd/DnsSdServiceInfo.java | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 core/java/android/net/nsd/DnsSdServiceInfo.java diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java new file mode 100644 index 0000000000..47d6ec609f --- /dev/null +++ b/core/java/android/net/nsd/DnsSdServiceInfo.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +import android.os.Parcelable; +import android.os.Parcel; + +/** + * Defines a service based on DNS service discovery + * {@hide} + */ +public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { + + private String mServiceName; + + private String mRegistrationType; + + private DnsSdTxtRecord mTxtRecord; + + private String mHostname; + + private int mPort; + + DnsSdServiceInfo() { + } + + DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { + mServiceName = sn; + mRegistrationType = rt; + mTxtRecord = tr; + } + + @Override + /** @hide */ + public String getServiceName() { + return mServiceName; + } + + @Override + /** @hide */ + public void setServiceName(String s) { + mServiceName = s; + } + + @Override + /** @hide */ + public String getServiceType() { + return mRegistrationType; + } + + @Override + /** @hide */ + public void setServiceType(String s) { + mRegistrationType = s; + } + + public DnsSdTxtRecord getTxtRecord() { + return mTxtRecord; + } + + public void setTxtRecord(DnsSdTxtRecord t) { + mTxtRecord = new DnsSdTxtRecord(t); + } + + public String getHostName() { + return mHostname; + } + + public void setHostName(String s) { + mHostname = s; + } + + public int getPort() { + return mPort; + } + + public void setPort(int p) { + mPort = p; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append("name: ").append(mServiceName). + append("type: ").append(mRegistrationType). + append("txtRecord: ").append(mTxtRecord); + return sb.toString(); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mServiceName); + dest.writeString(mRegistrationType); + dest.writeParcelable(mTxtRecord, flags); + dest.writeString(mHostname); + dest.writeInt(mPort); + } + + /** Implement the Parcelable interface */ + public static final Creator CREATOR = + new Creator() { + public DnsSdServiceInfo createFromParcel(Parcel in) { + DnsSdServiceInfo info = new DnsSdServiceInfo(); + info.mServiceName = in.readString(); + info.mRegistrationType = in.readString(); + info.mTxtRecord = in.readParcelable(null); + info.mHostname = in.readString(); + info.mPort = in.readInt(); + return info; + } + + public DnsSdServiceInfo[] newArray(int size) { + return new DnsSdServiceInfo[size]; + } + }; + +} From 3bd888f411149bb781c5a8da8b1b8b63fe8353ba Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 4 Apr 2012 20:40:58 -0700 Subject: [PATCH 0134/1150] Support metered Wi-Fi NetworkPolicy. Add networkId field to NetworkIdentity to identify Wi-Fi networks by SSID. Add support for policies without usage cycles. Only apply mobile policies when SIM state is ready, which is cleaner than just checking for airplane mode. Also avoids creating no-op default policies when subscriberId is null. Bug: 3001465, 3291052 Change-Id: I1f8aaa49a5db306df022c402ea7f3f5d4bc0cfc7 --- core/java/android/net/NetworkIdentity.java | 74 ++++++++++----- core/java/android/net/NetworkTemplate.java | 95 ++++++++++++------- .../internal/net/NetworkStatsFactory.java | 8 +- .../server/net/NetworkIdentitySet.java | 47 +++++---- .../server/net/NetworkStatsService.java | 4 +- 5 files changed, 139 insertions(+), 89 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index ee12989a00..4ac5e76472 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -16,9 +16,13 @@ package android.net; +import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeMobile; import android.content.Context; +import android.net.wifi.WifiInfo; +import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; @@ -42,18 +46,21 @@ public class NetworkIdentity { final int mType; final int mSubType; final String mSubscriberId; + final String mNetworkId; final boolean mRoaming; - public NetworkIdentity(int type, int subType, String subscriberId, boolean roaming) { - this.mType = type; - this.mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; - this.mSubscriberId = subscriberId; - this.mRoaming = roaming; + public NetworkIdentity( + int type, int subType, String subscriberId, String networkId, boolean roaming) { + mType = type; + mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; + mSubscriberId = subscriberId; + mNetworkId = networkId; + mRoaming = roaming; } @Override public int hashCode() { - return Objects.hashCode(mType, mSubType, mSubscriberId, mRoaming); + return Objects.hashCode(mType, mSubType, mSubscriberId, mNetworkId, mRoaming); } @Override @@ -61,27 +68,34 @@ public class NetworkIdentity { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming - && Objects.equal(mSubscriberId, ident.mSubscriberId); + && Objects.equal(mSubscriberId, ident.mSubscriberId) + && Objects.equal(mNetworkId, ident.mNetworkId); } return false; } @Override public String toString() { - final String typeName = ConnectivityManager.getNetworkTypeName(mType); - final String subTypeName; + final StringBuilder builder = new StringBuilder("["); + builder.append("type=").append(getNetworkTypeName(mType)); + builder.append(", subType="); if (COMBINE_SUBTYPE_ENABLED) { - subTypeName = "COMBINED"; + builder.append("COMBINED"); } else if (ConnectivityManager.isNetworkTypeMobile(mType)) { - subTypeName = TelephonyManager.getNetworkTypeName(mSubType); + builder.append(TelephonyManager.getNetworkTypeName(mSubType)); } else { - subTypeName = Integer.toString(mSubType); + builder.append(mSubType); } - - final String scrubSubscriberId = scrubSubscriberId(mSubscriberId); - final String roaming = mRoaming ? ", ROAMING" : ""; - return "[type=" + typeName + ", subType=" + subTypeName + ", subscriberId=" - + scrubSubscriberId + roaming + "]"; + if (mSubscriberId != null) { + builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + } + if (mNetworkId != null) { + builder.append(", networkId=").append(mNetworkId); + } + if (mRoaming) { + builder.append(", ROAMING"); + } + return builder.append("]").toString(); } public int getType() { @@ -96,6 +110,10 @@ public class NetworkIdentity { return mSubscriberId; } + public String getNetworkId() { + return mNetworkId; + } + public boolean getRoaming() { return mRoaming; } @@ -106,8 +124,11 @@ public class NetworkIdentity { public static String scrubSubscriberId(String subscriberId) { if ("eng".equals(Build.TYPE)) { return subscriberId; + } else if (subscriberId != null) { + // TODO: parse this as MCC+MNC instead of hard-coding + return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "..."; } else { - return subscriberId != null ? "valid" : "null"; + return "null"; } } @@ -122,8 +143,10 @@ public class NetworkIdentity { // TODO: consider moving subscriberId over to LinkCapabilities, so it // comes from an authoritative source. - final String subscriberId; - final boolean roaming; + String subscriberId = null; + String networkId = null; + boolean roaming = false; + if (isNetworkTypeMobile(type)) { final TelephonyManager telephony = (TelephonyManager) context.getSystemService( Context.TELEPHONY_SERVICE); @@ -133,10 +156,13 @@ public class NetworkIdentity { } else { subscriberId = telephony.getSubscriberId(); } - } else { - subscriberId = null; - roaming = false; + + } else if (type == TYPE_WIFI) { + final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + final WifiInfo info = wifi.getConnectionInfo(); + networkId = info != null ? info.getSSID() : null; } - return new NetworkIdentity(type, subType, subscriberId, roaming); + + return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index e1fbdcc705..50432a14d0 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -43,15 +43,10 @@ import com.android.internal.util.Objects; */ public class NetworkTemplate implements Parcelable { - /** {@hide} */ public static final int MATCH_MOBILE_ALL = 1; - /** {@hide} */ public static final int MATCH_MOBILE_3G_LOWER = 2; - /** {@hide} */ public static final int MATCH_MOBILE_4G = 3; - /** {@hide} */ public static final int MATCH_WIFI = 4; - /** {@hide} */ public static final int MATCH_ETHERNET = 5; /** @@ -65,37 +60,50 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together. Only uses statistics for requested IMSI. + * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with + * the given IMSI. */ public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId); + return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null); } /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that roughly meet a "3G" definition, or lower. Only - * uses statistics for requested IMSI. + * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with + * the given IMSI that roughly meet a "3G" definition, or lower. */ + @Deprecated public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId); + return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null); } /** - * Template to combine all {@link ConnectivityManager#TYPE_MOBILE} style - * networks together that meet a "4G" definition. Only uses statistics for - * requested IMSI. + * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with + * the given IMSI that roughly meet a "4G" definition. */ + @Deprecated public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId); + return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null); } /** - * Template to combine all {@link ConnectivityManager#TYPE_WIFI} style - * networks together. + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, + * regardless of SSID. */ + public static NetworkTemplate buildTemplateWifiWildcard() { + return new NetworkTemplate(MATCH_WIFI, null, null); + } + + @Deprecated public static NetworkTemplate buildTemplateWifi() { - return new NetworkTemplate(MATCH_WIFI, null); + return buildTemplateWifiWildcard(); + } + + /** + * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the + * given SSID. + */ + public static NetworkTemplate buildTemplateWifi(String networkId) { + return new NetworkTemplate(MATCH_WIFI, null, networkId); } /** @@ -103,44 +111,53 @@ public class NetworkTemplate implements Parcelable { * networks together. */ public static NetworkTemplate buildTemplateEthernet() { - return new NetworkTemplate(MATCH_ETHERNET, null); + return new NetworkTemplate(MATCH_ETHERNET, null, null); } private final int mMatchRule; private final String mSubscriberId; + private final String mNetworkId; - /** {@hide} */ - public NetworkTemplate(int matchRule, String subscriberId) { - this.mMatchRule = matchRule; - this.mSubscriberId = subscriberId; + public NetworkTemplate(int matchRule, String subscriberId, String networkId) { + mMatchRule = matchRule; + mSubscriberId = subscriberId; + mNetworkId = networkId; } private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); mSubscriberId = in.readString(); + mNetworkId = in.readString(); } - /** {@inheritDoc} */ + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); + dest.writeString(mNetworkId); } - /** {@inheritDoc} */ + @Override public int describeContents() { return 0; } @Override public String toString() { - final String scrubSubscriberId = scrubSubscriberId(mSubscriberId); - return "NetworkTemplate: matchRule=" + getMatchRuleName(mMatchRule) + ", subscriberId=" - + scrubSubscriberId; + final StringBuilder builder = new StringBuilder("NetworkTemplate: "); + builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); + if (mSubscriberId != null) { + builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + } + if (mNetworkId != null) { + builder.append(", networkId=").append(mNetworkId); + } + return builder.toString(); } @Override public int hashCode() { - return Objects.hashCode(mMatchRule, mSubscriberId); + return Objects.hashCode(mMatchRule, mSubscriberId, mNetworkId); } @Override @@ -148,21 +165,24 @@ public class NetworkTemplate implements Parcelable { if (obj instanceof NetworkTemplate) { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule - && Objects.equal(mSubscriberId, other.mSubscriberId); + && Objects.equal(mSubscriberId, other.mSubscriberId) + && Objects.equal(mNetworkId, other.mNetworkId); } return false; } - /** {@hide} */ public int getMatchRule() { return mMatchRule; } - /** {@hide} */ public String getSubscriberId() { return mSubscriberId; } + public String getNetworkId() { + return mNetworkId; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ @@ -237,8 +257,13 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: + if (mNetworkId == null) { + return true; + } else { + return Objects.equal(mNetworkId, ident.mNetworkId); + } case TYPE_WIFI_P2P: - return true; + return mNetworkId == null; default: return false; } @@ -279,10 +304,12 @@ public class NetworkTemplate implements Parcelable { } public static final Creator CREATOR = new Creator() { + @Override public NetworkTemplate createFromParcel(Parcel in) { return new NetworkTemplate(in); } + @Override public NetworkTemplate[] newArray(int size) { return new NetworkTemplate[size]; } diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index ccd27632b9..d59585f2fe 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -16,7 +16,7 @@ package com.android.internal.net; -import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; @@ -101,7 +101,7 @@ public class NetworkStatsFactory { while (reader.hasMoreData()) { entry.iface = reader.nextString(); entry.uid = UID_ALL; - entry.set = SET_DEFAULT; + entry.set = SET_ALL; entry.tag = TAG_NONE; final boolean active = reader.nextInt() != 0; @@ -165,7 +165,7 @@ public class NetworkStatsFactory { entry.iface = iface; entry.uid = UID_ALL; - entry.set = SET_DEFAULT; + entry.set = SET_ALL; entry.tag = TAG_NONE; entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes")); entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets")); @@ -193,7 +193,7 @@ public class NetworkStatsFactory { try { entry.iface = values.get(0); entry.uid = UID_ALL; - entry.set = SET_DEFAULT; + entry.set = SET_ALL; entry.tag = TAG_NONE; entry.rxBytes = Long.parseLong(values.get(1)); entry.rxPackets = Long.parseLong(values.get(2)); diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/java/com/android/server/net/NetworkIdentitySet.java index af03fb3182..397f9f41d8 100644 --- a/services/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/java/com/android/server/net/NetworkIdentitySet.java @@ -21,7 +21,6 @@ import android.net.NetworkIdentity; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; -import java.net.ProtocolException; import java.util.HashSet; /** @@ -33,48 +32,46 @@ import java.util.HashSet; public class NetworkIdentitySet extends HashSet { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; + private static final int VERSION_ADD_NETWORK_ID = 3; public NetworkIdentitySet() { } public NetworkIdentitySet(DataInputStream in) throws IOException { final int version = in.readInt(); - switch (version) { - case VERSION_INIT: { - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int ignoredVersion = in.readInt(); - final int type = in.readInt(); - final int subType = in.readInt(); - final String subscriberId = readOptionalString(in); - add(new NetworkIdentity(type, subType, subscriberId, false)); - } - break; + final int size = in.readInt(); + for (int i = 0; i < size; i++) { + if (version <= VERSION_INIT) { + final int ignored = in.readInt(); } - case VERSION_ADD_ROAMING: { - final int size = in.readInt(); - for (int i = 0; i < size; i++) { - final int type = in.readInt(); - final int subType = in.readInt(); - final String subscriberId = readOptionalString(in); - final boolean roaming = in.readBoolean(); - add(new NetworkIdentity(type, subType, subscriberId, roaming)); - } - break; + final int type = in.readInt(); + final int subType = in.readInt(); + final String subscriberId = readOptionalString(in); + final String networkId; + if (version >= VERSION_ADD_NETWORK_ID) { + networkId = readOptionalString(in); + } else { + networkId = null; } - default: { - throw new ProtocolException("unexpected version: " + version); + final boolean roaming; + if (version >= VERSION_ADD_ROAMING) { + roaming = in.readBoolean(); + } else { + roaming = false; } + + add(new NetworkIdentity(type, subType, subscriberId, networkId, false)); } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_ROAMING); + out.writeInt(VERSION_ADD_NETWORK_ID); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); out.writeInt(ident.getSubType()); writeOptionalString(out, ident.getSubscriberId()); + writeOptionalString(out, ident.getNetworkId()); out.writeBoolean(ident.getRoaming()); } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 8796afc06a..b847673d4e 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -34,7 +34,7 @@ import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileAll; -import static android.net.NetworkTemplate.buildTemplateWifi; +import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; @@ -836,7 +836,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { trustedTime); // collect wifi sample - template = buildTemplateWifi(); + template = buildTemplateWifiWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = new NetworkStats.Entry(); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); From 920d9046bcd9ef75fdc7d5406a006050c32a5d29 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 6 Apr 2012 11:12:08 -0700 Subject: [PATCH 0135/1150] INetworkStatsSession with lifecycle for caching. Users outside system_server now explicitly communicate their lifecycle, which keeps a strong-reference chain to any fully loaded NetworkStatsCollection histories. Bug: 6236498 Change-Id: I8e22739b6e89a626b676967a736d7117fd000778 --- .../android/net/INetworkStatsService.aidl | 13 +-- .../android/net/INetworkStatsSession.aidl | 38 +++++++ core/java/android/net/TrafficStats.java | 13 +++ .../server/net/NetworkStatsRecorder.java | 5 + .../server/net/NetworkStatsService.java | 98 +++++++++++++------ 5 files changed, 128 insertions(+), 39 deletions(-) create mode 100644 core/java/android/net/INetworkStatsSession.aidl diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 0e883cf8ac..b4f6367d87 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; @@ -23,15 +24,11 @@ import android.net.NetworkTemplate; /** {@hide} */ interface INetworkStatsService { - /** Return historical network layer stats for traffic that matches template. */ - NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); - /** Return historical network layer stats for specific UID traffic that matches template. */ - NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); + /** Start a statistics query session. */ + INetworkStatsSession openSession(); - /** Return network layer usage summary for traffic that matches template. */ - NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); - /** Return network layer usage summary per UID for traffic that matches template. */ - NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + /** Return network layer usage total for traffic that matches template. */ + long getNetworkTotalBytes(in NetworkTemplate template, long start, long end); /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl new file mode 100644 index 0000000000..1596fa2b01 --- /dev/null +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; + +/** {@hide} */ +interface INetworkStatsSession { + + /** Return network layer usage summary for traffic that matches template. */ + NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); + /** Return historical network layer stats for traffic that matches template. */ + NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); + + /** Return network layer usage summary per UID for traffic that matches template. */ + NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + /** Return historical network layer stats for specific UID traffic that matches template. */ + NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); + + void close(); + +} diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 973fac1909..ee3e1650ae 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -238,6 +238,19 @@ public class TrafficStats { } } + /** {@hide} */ + public static void closeQuietly(INetworkStatsSession session) { + // TODO: move to NetworkStatsService once it exists + if (session != null) { + try { + session.close(); + } catch (RuntimeException rethrown) { + throw rethrown; + } catch (Exception ignored) { + } + } + } + /** * Get the total number of packets transmitted through the mobile interface. * diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 290bd2cc49..540f6066f4 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -221,6 +221,11 @@ public class NetworkStatsRecorder { if (mLastSnapshot != null) { mLastSnapshot = mLastSnapshot.withoutUid(uid); } + + final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; + if (complete != null) { + complete.removeUid(uid); + } } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index b847673d4e..f7ba32996d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -70,6 +70,7 @@ import android.content.IntentFilter; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; import android.net.LinkProperties; import android.net.NetworkIdentity; import android.net.NetworkInfo; @@ -412,40 +413,75 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + public INetworkStatsSession openSession() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + + // return an IBinder which holds strong references to any loaded stats + // for its lifetime; when caller closes only weak references remain. + + return new INetworkStatsSession.Stub() { + private NetworkStatsCollection mUidComplete; + private NetworkStatsCollection mUidTagComplete; + + private NetworkStatsCollection getUidComplete() { + if (mUidComplete == null) { + mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); + } + return mUidComplete; + } + + private NetworkStatsCollection getUidTagComplete() { + if (mUidTagComplete == null) { + mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); + } + return mUidTagComplete; + } + + @Override + public NetworkStats getSummaryForNetwork( + NetworkTemplate template, long start, long end) { + return mDevStatsCached.getSummary(template, start, end); + } + + @Override + public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { + return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + } + + @Override + public NetworkStats getSummaryForAllUid( + NetworkTemplate template, long start, long end, boolean includeTags) { + final NetworkStats stats = getUidComplete().getSummary(template, start, end); + if (includeTags) { + final NetworkStats tagStats = getUidTagComplete() + .getSummary(template, start, end); + stats.combineAllValues(tagStats); + } + return stats; + } + + @Override + public NetworkStatsHistory getHistoryForUid( + NetworkTemplate template, int uid, int set, int tag, int fields) { + if (tag == TAG_NONE) { + return getUidComplete().getHistory(template, uid, set, tag, fields); + } else { + return getUidTagComplete().getHistory(template, uid, set, tag, fields); + } + } + + @Override + public void close() { + mUidComplete = null; + mUidTagComplete = null; + } + }; } @Override - public NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) { - return mDevStatsCached.getSummary(template, start, end); - } - - @Override - public NetworkStatsHistory getHistoryForUid( - NetworkTemplate template, int uid, int set, int tag, int fields) { - // TODO: transition to stats sessions to avoid WeakReferences - if (tag == TAG_NONE) { - return mUidRecorder.getOrLoadCompleteLocked().getHistory( - template, uid, set, tag, fields); - } else { - return mUidTagRecorder.getOrLoadCompleteLocked().getHistory( - template, uid, set, tag, fields); - } - } - - @Override - public NetworkStats getSummaryForAllUid( - NetworkTemplate template, long start, long end, boolean includeTags) { - // TODO: transition to stats sessions to avoid WeakReferences - final NetworkStats stats = mUidRecorder.getOrLoadCompleteLocked().getSummary( - template, start, end); - if (includeTags) { - final NetworkStats tagStats = mUidTagRecorder.getOrLoadCompleteLocked().getSummary( - template, start, end); - stats.combineAllValues(tagStats); - } - return stats; + public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return mDevStatsCached.getSummary(template, start, end).getTotalBytes(); } @Override From 27421b1665019307c47ea2d0ee5f78cf894fe9b0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 9 Apr 2012 10:27:55 -0700 Subject: [PATCH 0136/1150] Splice operations before collapsing ifaces. Bug: 6241038 Change-Id: Ide9058703f7305df8fb070af149ddce0653a0abf --- core/java/android/net/NetworkStats.java | 3 +-- .../java/com/android/server/net/NetworkStatsService.java | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 7a1ef6623e..c58725d39b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -352,10 +352,9 @@ public class NetworkStats implements Parcelable { * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface}, * since operation counts are at data layer. */ - @Deprecated public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(IFACE_ALL, uid[i], set[i], tag[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]); if (j == -1) { operations[i] = 0; } else { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f7ba32996d..519d58ecdd 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -500,6 +500,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Binder.restoreCallingIdentity(token); } + // splice in operation counts + networkLayer.spliceOperationsFrom(mUidOperations); + final NetworkStats dataLayer = new NetworkStats( networkLayer.getElapsedRealtime(), networkLayer.size()); @@ -510,8 +513,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { dataLayer.combineValues(entry); } - // splice in operation counts - dataLayer.spliceOperationsFrom(mUidOperations); return dataLayer; } From 1ba1b673f5b527aa088b68900151246780c53eff Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 9 Apr 2012 10:49:19 -0700 Subject: [PATCH 0137/1150] Migrate to @Override to remove warnings. Bug: 6303344 Change-Id: I0d33b2ed448467379d576ccd71fb5ae20c878852 --- core/java/android/net/NetworkStats.java | 6 ++++-- core/java/android/net/NetworkStatsHistory.java | 6 ++++-- .../server/net/NetworkStatsCollection.java | 8 +++----- .../android/server/net/NetworkStatsRecorder.java | 16 ++++++++-------- .../android/server/net/NetworkStatsService.java | 14 +++++++++++--- 5 files changed, 30 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index c58725d39b..844d05564b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -155,7 +155,7 @@ public class NetworkStats implements Parcelable { operations = parcel.createLongArray(); } - /** {@inheritDoc} */ + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); dest.writeInt(size); @@ -662,16 +662,18 @@ public class NetworkStats implements Parcelable { return writer.toString(); } - /** {@inheritDoc} */ + @Override public int describeContents() { return 0; } public static final Creator CREATOR = new Creator() { + @Override public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); } + @Override public NetworkStats[] newArray(int size) { return new NetworkStats[size]; } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index faf8a3f9fe..0003c6e3d6 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -130,7 +130,7 @@ public class NetworkStatsHistory implements Parcelable { totalBytes = in.readLong(); } - /** {@inheritDoc} */ + @Override public void writeToParcel(Parcel out, int flags) { out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); @@ -191,7 +191,7 @@ public class NetworkStatsHistory implements Parcelable { writeVarLongArray(out, operations, bucketCount); } - /** {@inheritDoc} */ + @Override public int describeContents() { return 0; } @@ -586,10 +586,12 @@ public class NetworkStatsHistory implements Parcelable { } public static final Creator CREATOR = new Creator() { + @Override public NetworkStatsHistory createFromParcel(Parcel in) { return new NetworkStatsHistory(in); } + @Override public NetworkStatsHistory[] newArray(int size) { return new NetworkStatsHistory[size]; } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 70038d93ee..2892a74845 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -57,8 +57,6 @@ import libcore.io.IoUtils; * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. */ public class NetworkStatsCollection implements FileRotator.Reader { - private static final String TAG = "NetworkStatsCollection"; - /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; @@ -173,7 +171,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { } /** - * Record given {@link NetworkStats.Entry} into this collection. + * Record given {@link android.net.NetworkStats.Entry} into this collection. */ public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, long end, NetworkStats.Entry entry) { @@ -227,7 +225,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } - /** {@inheritDoc} */ + @Override public void read(InputStream in) throws IOException { read(new DataInputStream(in)); } @@ -502,7 +500,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { return false; } - /** {@inheritDoc} */ + @Override public int compareTo(Key another) { return Integer.compare(uid, another.uid); } diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 540f6066f4..57ad158bf2 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -240,22 +240,22 @@ public class NetworkStatsRecorder { mCollection = checkNotNull(collection, "missing NetworkStatsCollection"); } - /** {@inheritDoc} */ + @Override public void reset() { // ignored } - /** {@inheritDoc} */ + @Override public void read(InputStream in) throws IOException { mCollection.read(in); } - /** {@inheritDoc} */ + @Override public boolean shouldWrite() { return true; } - /** {@inheritDoc} */ + @Override public void write(OutputStream out) throws IOException { mCollection.write(new DataOutputStream(out)); mCollection.reset(); @@ -275,24 +275,24 @@ public class NetworkStatsRecorder { mUid = uid; } - /** {@inheritDoc} */ + @Override public void reset() { mTemp.reset(); } - /** {@inheritDoc} */ + @Override public void read(InputStream in) throws IOException { mTemp.read(in); mTemp.clearDirty(); mTemp.removeUid(mUid); } - /** {@inheritDoc} */ + @Override public boolean shouldWrite() { return mTemp.isDirty(); } - /** {@inheritDoc} */ + @Override public void write(OutputStream out) throws IOException { mTemp.write(new DataOutputStream(out)); } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 519d58ecdd..4382a03fa2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -999,7 +999,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private Handler.Callback mHandlerCallback = new Handler.Callback() { - /** {@inheritDoc} */ + @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { @@ -1038,7 +1038,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private class DropBoxNonMonotonicObserver implements NonMonotonicObserver { - /** {@inheritDoc} */ + @Override public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, String cookie) { Log.w(TAG, "found non-monotonic values; saving to dropbox"); @@ -1057,7 +1057,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Default external settings that read from {@link Settings.Secure}. + * Default external settings that read from + * {@link android.provider.Settings.Secure}. */ private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { private final ContentResolver mResolver; @@ -1075,19 +1076,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return Settings.Secure.getInt(mResolver, name, defInt) != 0; } + @Override public long getPollInterval() { return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } + @Override public long getTimeCacheMaxAge() { return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); } + @Override public long getGlobalAlertBytes() { return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES); } + @Override public boolean getSampleEnabled() { return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true); } + @Override public Config getDevConfig() { return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES), @@ -1095,6 +1101,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); } + @Override public Config getUidConfig() { return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), @@ -1102,6 +1109,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); } + @Override public Config getUidTagConfig() { return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), From e8de246bb49acd543bae1c6ecd0d14dd1fe836c2 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Wed, 11 Apr 2012 14:52:19 -0700 Subject: [PATCH 0138/1150] Bonjour fixes Change-Id: I1df1dc470bb42c84abc7e1a46bedf9f206910b65 --- .../android/net/nsd/DnsSdServiceInfo.java | 47 ++- core/java/android/net/nsd/NsdManager.java | 50 ++- .../java/com/android/server/NsdService.java | 384 ++++++++++++++++-- 3 files changed, 422 insertions(+), 59 deletions(-) diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java index 47d6ec609f..33c3eb98aa 100644 --- a/core/java/android/net/nsd/DnsSdServiceInfo.java +++ b/core/java/android/net/nsd/DnsSdServiceInfo.java @@ -19,6 +19,8 @@ package android.net.nsd; import android.os.Parcelable; import android.os.Parcel; +import java.net.InetAddress; + /** * Defines a service based on DNS service discovery * {@hide} @@ -27,20 +29,20 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { private String mServiceName; - private String mRegistrationType; + private String mServiceType; private DnsSdTxtRecord mTxtRecord; - private String mHostname; + private InetAddress mHost; private int mPort; - DnsSdServiceInfo() { + public DnsSdServiceInfo() { } - DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { + public DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { mServiceName = sn; - mRegistrationType = rt; + mServiceType = rt; mTxtRecord = tr; } @@ -59,13 +61,13 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { @Override /** @hide */ public String getServiceType() { - return mRegistrationType; + return mServiceType; } @Override /** @hide */ public void setServiceType(String s) { - mRegistrationType = s; + mServiceType = s; } public DnsSdTxtRecord getTxtRecord() { @@ -76,12 +78,12 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { mTxtRecord = new DnsSdTxtRecord(t); } - public String getHostName() { - return mHostname; + public InetAddress getHost() { + return mHost; } - public void setHostName(String s) { - mHostname = s; + public void setHost(InetAddress s) { + mHost = s; } public int getPort() { @@ -96,7 +98,9 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { StringBuffer sb = new StringBuffer(); sb.append("name: ").append(mServiceName). - append("type: ").append(mRegistrationType). + append("type: ").append(mServiceType). + append("host: ").append(mHost). + append("port: ").append(mPort). append("txtRecord: ").append(mTxtRecord); return sb.toString(); } @@ -109,9 +113,14 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { /** Implement the Parcelable interface */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(mServiceName); - dest.writeString(mRegistrationType); + dest.writeString(mServiceType); dest.writeParcelable(mTxtRecord, flags); - dest.writeString(mHostname); + if (mHost != null) { + dest.writeByte((byte)1); + dest.writeByteArray(mHost.getAddress()); + } else { + dest.writeByte((byte)0); + } dest.writeInt(mPort); } @@ -121,9 +130,15 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { public DnsSdServiceInfo createFromParcel(Parcel in) { DnsSdServiceInfo info = new DnsSdServiceInfo(); info.mServiceName = in.readString(); - info.mRegistrationType = in.readString(); + info.mServiceType = in.readString(); info.mTxtRecord = in.readParcelable(null); - info.mHostname = in.readString(); + + if (in.readByte() == 1) { + try { + info.mHost = InetAddress.getByAddress(in.createByteArray()); + } catch (java.net.UnknownHostException e) {} + } + info.mPort = in.readInt(); return info; } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index a109a983fd..505f11b542 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -93,6 +93,15 @@ public class NsdManager { /** @hide */ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17; + /** @hide */ + public static final int STOP_RESOLVE = BASE + 18; + /** @hide */ + public static final int STOP_RESOLVE_FAILED = BASE + 19; + /** @hide */ + public static final int STOP_RESOLVE_SUCCEEDED = BASE + 20; + + + /** * Create a new Nsd instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -117,10 +126,23 @@ public class NsdManager { /** * Indicates that the operation failed because the framework is busy and - * unable to service the request + * unable to service the request. */ public static final int BUSY = 2; + /** + * Indicates that the operation failed because it is already active. + */ + public static final int ALREADY_ACTIVE = 3; + + /** + * Indicates that the operation failed because maximum limit on + * service registrations has reached. + */ + public static final int MAX_REGS_REACHED = 4; + + + /** Interface for callback invocation when framework channel is connected or lost */ public interface ChannelListener { public void onChannelConnected(Channel c); @@ -188,6 +210,7 @@ public class NsdManager { private DnsSdRegisterListener mDnsSdRegisterListener; private DnsSdUpdateRegistrationListener mDnsSdUpdateListener; private DnsSdResolveListener mDnsSdResolveListener; + private ActionListener mDnsSdStopResolveListener; AsyncChannel mAsyncChannel; ServiceHandler mHandler; @@ -278,6 +301,16 @@ public class NsdManager { (DnsSdServiceInfo) message.obj); } break; + case STOP_RESOLVE_FAILED: + if (mDnsSdStopResolveListener!= null) { + mDnsSdStopResolveListener.onFailure(message.arg1); + } + break; + case STOP_RESOLVE_SUCCEEDED: + if (mDnsSdStopResolveListener != null) { + mDnsSdStopResolveListener.onSuccess(); + } + break; default: Log.d(TAG, "Ignored " + message); break; @@ -345,6 +378,14 @@ public class NsdManager { c.mDnsSdResolveListener = b; } + /** + * Set the listener for stopping service resolution. Can be null. + */ + public void setStopResolveListener(Channel c, ActionListener b) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + c.mDnsSdStopResolveListener = b; + } + public void registerService(Channel c, DnsSdServiceInfo serviceInfo) { if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo"); @@ -378,6 +419,13 @@ public class NsdManager { c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo); } + public void stopServiceResolve(Channel c) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + if (c.mDnsSdResolveListener == null) throw new + IllegalStateException("Resolve listener needs to be set first"); + c.mAsyncChannel.sendMessage(STOP_RESOLVE); + } + /** * Get a reference to NetworkService handler. This is used to establish * an AsyncChannel communication with the service diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 768be7df41..a3ac8d0849 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -32,9 +32,11 @@ import android.util.Slog; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.net.InetAddress; import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; +import java.util.HashMap; import java.util.List; +import java.util.concurrent.CountDownLatch; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.TelephonyIntents; @@ -60,10 +62,13 @@ public class NsdService extends INsdManager.Stub { /** * Clients receiving asynchronous messages */ - private List mClients = new ArrayList(); + private HashMap mClients = new HashMap(); private AsyncChannel mReplyChannel = new AsyncChannel(); + private int INVALID_ID = 0; + private int mUniqueId = 1; + /** * Handles client(app) connections */ @@ -75,13 +80,19 @@ public class NsdService extends INsdManager.Stub { @Override public void handleMessage(Message msg) { + ClientInfo clientInfo; + DnsSdServiceInfo servInfo; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { AsyncChannel c = (AsyncChannel) msg.obj; if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - mClients.add(c); + ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + if (mClients.size() == 0) { + startMDnsDaemon(); + } + mClients.put(msg.replyTo, cInfo); } else { Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } @@ -92,7 +103,10 @@ public class NsdService extends INsdManager.Stub { } else { if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); } - mClients.remove((AsyncChannel) msg.obj); + mClients.remove(msg.replyTo); + if (mClients.size() == 0) { + stopMDnsDaemon(); + } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -100,22 +114,98 @@ public class NsdService extends INsdManager.Stub { break; case NsdManager.DISCOVER_SERVICES: if (DBG) Slog.d(TAG, "Discover services"); - DnsSdServiceInfo s = (DnsSdServiceInfo) msg.obj; - discoverServices(1, s.getServiceType()); - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId != INVALID_ID) { + //discovery already in progress + if (DBG) Slog.d(TAG, "discovery in progress"); + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + clientInfo.mDiscoveryId = getUniqueId(); + if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ERROR); + clientInfo.mDiscoveryId = INVALID_ID; + } break; case NsdManager.STOP_DISCOVERY: if (DBG) Slog.d(TAG, "Stop service discovery"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "discovery already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { + clientInfo.mDiscoveryId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ERROR); + } break; case NsdManager.REGISTER_SERVICE: if (DBG) Slog.d(TAG, "Register service"); - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { + if (DBG) Slog.d(TAG, "register service exceeds limit"); + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.MAX_REGS_REACHED); + } + + int id = getUniqueId(); + if (registerService(id, (DnsSdServiceInfo) msg.obj)) { + clientInfo.mRegisteredIds.add(id); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } break; case NsdManager.UPDATE_SERVICE: if (DBG) Slog.d(TAG, "Update service"); + //TODO: implement mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); break; + case NsdManager.RESOLVE_SERVICE: + if (DBG) Slog.d(TAG, "Resolve service"); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId != INVALID_ID) { + //first cancel existing resolve + stopResolveService(clientInfo.mResolveId); + } + + clientInfo.mResolveId = getUniqueId(); + if (!resolveService(clientInfo.mResolveId, servInfo)) { + mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + clientInfo.mResolveId = INVALID_ID; + } + break; + case NsdManager.STOP_RESOLVE: + if (DBG) Slog.d(TAG, "Stop resolve"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "resolve already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopResolveService(clientInfo.mResolveId)) { + clientInfo.mResolveId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ERROR); + } + break; default: Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg); break; @@ -134,12 +224,10 @@ public class NsdService extends INsdManager.Stub { nsdThread.start(); mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper()); - /* mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, MDNS_TAG, 25); Thread th = new Thread(mNativeConnector, MDNS_TAG); th.start(); - */ } public static NsdService create(Context context) throws InterruptedException { @@ -152,22 +240,29 @@ public class NsdService extends INsdManager.Stub { return new Messenger(mAsyncServiceHandler); } - /* These should be in sync with system/netd/mDnsResponseCode.h */ - class NativeResponseCode { - public static final int SERVICE_FOUND = 101; - public static final int SERVICE_LOST = 102; - public static final int SERVICE_DISCOVERY_FAILED = 103; - - public static final int SERVICE_REGISTERED = 104; - public static final int SERVICE_REGISTRATION_FAILED = 105; - - public static final int SERVICE_UPDATED = 106; - public static final int SERVICE_UPDATE_FAILED = 107; - - public static final int SERVICE_RESOLVED = 108; - public static final int SERVICE_RESOLUTION_FAILED = 109; + private int getUniqueId() { + if (++mUniqueId == INVALID_ID) return ++mUniqueId; + return mUniqueId; } + /* These should be in sync with system/netd/mDnsResponseCode.h */ + class NativeResponseCode { + public static final int SERVICE_DISCOVERY_FAILED = 602; + public static final int SERVICE_FOUND = 603; + public static final int SERVICE_LOST = 604; + + public static final int SERVICE_REGISTRATION_FAILED = 605; + public static final int SERVICE_REGISTERED = 606; + + public static final int SERVICE_RESOLUTION_FAILED = 607; + public static final int SERVICE_RESOLVED = 608; + + public static final int SERVICE_UPDATED = 609; + public static final int SERVICE_UPDATE_FAILED = 610; + + public static final int SERVICE_GET_ADDR_FAILED = 611; + public static final int SERVICE_GET_ADDR_SUCCESS = 612; + } class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { public void onDaemonConnected() { @@ -175,21 +270,55 @@ public class NsdService extends INsdManager.Stub { } public boolean onEvent(int code, String raw, String[] cooked) { + ClientInfo clientInfo; + DnsSdServiceInfo servInfo; + int id = Integer.parseInt(cooked[1]); switch (code) { case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType */ + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); + clientInfo = getClientByDiscovery(id); + if (clientInfo == null) break; + + servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, servInfo); break; case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType */ + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); + clientInfo = getClientByDiscovery(id); + if (clientInfo == null) break; + + servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, servInfo); break; case NativeResponseCode.SERVICE_DISCOVERY_FAILED: /* NNN uniqueId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw); + clientInfo = getClientByDiscovery(id); + if (clientInfo == null) break; + + clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ERROR); break; case NativeResponseCode.SERVICE_REGISTERED: /* NNN regId serviceName regType */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); + clientInfo = getClientByRegistration(id); + if (clientInfo == null) break; + + servInfo = new DnsSdServiceInfo(cooked[2], null, null); + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, + id, 0, servInfo); break; case NativeResponseCode.SERVICE_REGISTRATION_FAILED: /* NNN regId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw); + clientInfo = getClientByRegistration(id); + if (clientInfo == null) break; + + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.ERROR); break; case NativeResponseCode.SERVICE_UPDATED: /* NNN regId */ @@ -199,9 +328,52 @@ public class NsdService extends INsdManager.Stub { break; case NativeResponseCode.SERVICE_RESOLVED: /* NNN resolveId fullName hostName port txtlen txtdata */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); + clientInfo = getClientByResolve(id); + if (clientInfo == null) break; + + int index = cooked[2].indexOf("."); + if (index == -1) { + Slog.e(TAG, "Invalid service found " + raw); + break; + } + String name = cooked[2].substring(0, index); + String rest = cooked[2].substring(index); + String type = rest.replace(".local.", ""); + + clientInfo.mResolvedService = new DnsSdServiceInfo(name, type, null); + clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); + + stopResolveService(id); + getAddrInfo(id, cooked[3]); break; case NativeResponseCode.SERVICE_RESOLUTION_FAILED: - /* NNN resovleId errorCode */ + case NativeResponseCode.SERVICE_GET_ADDR_FAILED: + /* NNN resolveId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); + clientInfo = getClientByResolve(id); + if (clientInfo == null) break; + + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + break; + case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: + /* NNN resolveId hostname ttl addr */ + if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw); + clientInfo = getClientByResolve(id); + if (clientInfo == null || clientInfo.mResolvedService == null) break; + + try { + clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, + clientInfo.mResolvedService); + clientInfo.mResolvedService = null; + clientInfo.mResolveId = INVALID_ID; + } catch (java.net.UnknownHostException e) { + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + } + stopGetAddrInfo(id); break; default: break; @@ -210,48 +382,129 @@ public class NsdService extends INsdManager.Stub { } } - private void registerService(int regId, DnsSdServiceInfo service) { + private boolean startMDnsDaemon() { + if (DBG) Slog.d(TAG, "startMDnsDaemon"); + try { + mNativeConnector.execute("mdnssd", "start-service"); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to start daemon" + e); + return false; + } + return true; + } + + private boolean stopMDnsDaemon() { + if (DBG) Slog.d(TAG, "stopMDnsDaemon"); + try { + mNativeConnector.execute("mdnssd", "stop-service"); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to start daemon" + e); + return false; + } + return true; + } + + private boolean registerService(int regId, DnsSdServiceInfo service) { + if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); try { //Add txtlen and txtdata mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(), service.getServiceType(), service.getPort()); } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute registerService"); + Slog.e(TAG, "Failed to execute registerService " + e); + return false; } + return true; } - private void updateService(int regId, DnsSdTxtRecord t) { + private boolean unregisterService(int regId) { + if (DBG) Slog.d(TAG, "unregisterService: " + regId); try { - if (t == null) return; + mNativeConnector.execute("mdnssd", "stop-register", regId); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to execute unregisterService " + e); + return false; + } + return true; + } + + private boolean updateService(int regId, DnsSdTxtRecord t) { + if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t); + try { + if (t == null) return false; mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData()); } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to updateServices"); + Slog.e(TAG, "Failed to updateServices " + e); + return false; } + return true; } - private void discoverServices(int discoveryId, String serviceType) { + private boolean discoverServices(int discoveryId, String serviceType) { + if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType); try { mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType); } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to discoverServices"); + Slog.e(TAG, "Failed to discoverServices " + e); + return false; } + return true; } - private void stopServiceDiscovery(int discoveryId) { + private boolean stopServiceDiscovery(int discoveryId) { + if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId); try { - mNativeConnector.execute("mdnssd", "stopdiscover", discoveryId); + mNativeConnector.execute("mdnssd", "stop-discover", discoveryId); } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to stopServiceDiscovery"); + Slog.e(TAG, "Failed to stopServiceDiscovery " + e); + return false; } + return true; } - private void resolveService(DnsSdServiceInfo service) { + private boolean resolveService(int resolveId, DnsSdServiceInfo service) { + if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service); try { - mNativeConnector.execute("mdnssd", "resolve", service.getServiceName(), - service.getServiceType()); + mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(), + service.getServiceType(), "local."); } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to resolveService"); + Slog.e(TAG, "Failed to resolveService " + e); + return false; } + return true; + } + + private boolean stopResolveService(int resolveId) { + if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId); + try { + mNativeConnector.execute("mdnssd", "stop-resolve", resolveId); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to stop resolve " + e); + return false; + } + return true; + } + + private boolean getAddrInfo(int resolveId, String hostname) { + if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId); + try { + mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to getAddrInfo " + e); + return false; + } + return true; + } + + private boolean stopGetAddrInfo(int resolveId) { + if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId); + try { + mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId); + } catch(NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to stopGetAddrInfo " + e); + return false; + } + return true; } @Override @@ -266,4 +519,51 @@ public class NsdService extends INsdManager.Stub { pw.println("Internal state:"); } + + private ClientInfo getClientByDiscovery(int discoveryId) { + for (ClientInfo c: mClients.values()) { + if (c.mDiscoveryId == discoveryId) { + return c; + } + } + return null; + } + + private ClientInfo getClientByResolve(int resolveId) { + for (ClientInfo c: mClients.values()) { + if (c.mResolveId == resolveId) { + return c; + } + } + return null; + } + + private ClientInfo getClientByRegistration(int regId) { + for (ClientInfo c: mClients.values()) { + if (c.mRegisteredIds.contains(regId)) { + return c; + } + } + return null; + } + + /* Information tracked per client */ + private class ClientInfo { + + private static final int MAX_REG = 5; + private AsyncChannel mChannel; + private Messenger mMessenger; + private int mDiscoveryId; + private int mResolveId; + /* Remembers a resolved service until getaddrinfo completes */ + private DnsSdServiceInfo mResolvedService; + private ArrayList mRegisteredIds = new ArrayList(); + + private ClientInfo(AsyncChannel c, Messenger m) { + mChannel = c; + mMessenger = m; + mDiscoveryId = mResolveId = INVALID_ID; + if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); + } + } } From 8308b9b2af803c2fcd10d8fa8a1b4c50b4087ef5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Apr 2012 19:48:07 -0700 Subject: [PATCH 0139/1150] Move TrafficStats iface counters to xt_qtaguid. Use xt_qtaguid iface_stat_all counters, which are monotonic during a single boot. Track all ifaces associated with mobile networks since boot, and move TrafficStats to using these ifaces. This will include usage of networks omitted from config_data_usage_network_types, specifically on devices that recycle network interfaces across APNs. Split wildcard template matching, and move NetworkStatsService to use mobile wildcard when logging stats. Bug: 5324515 Change-Id: I2211c374c05d1b598cc647f2f873630538955ffe --- .../android/net/INetworkStatsService.aidl | 3 + core/java/android/net/NetworkTemplate.java | 46 ++++- core/java/android/net/TrafficStats.java | 106 ++++++++-- core/jni/android_net_TrafficStats.cpp | 194 +++++++----------- .../server/net/NetworkStatsService.java | 27 ++- 5 files changed, 223 insertions(+), 153 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b4f6367d87..08d4c6cbf4 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -32,6 +32,9 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); + /** Return set of any ifaces associated with mobile networks since boot. */ + String[] getMobileIfaces(); + /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 50432a14d0..39a4d7bb0d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -48,6 +48,8 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_4G = 3; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; + public static final int MATCH_MOBILE_WILDCARD = 6; + public static final int MATCH_WIFI_WILDCARD = 7; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -85,12 +87,20 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null); } + /** + * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * regardless of IMSI. + */ + public static NetworkTemplate buildTemplateMobileWildcard() { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); + } + /** * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ public static NetworkTemplate buildTemplateWifiWildcard() { - return new NetworkTemplate(MATCH_WIFI, null, null); + return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @Deprecated @@ -198,6 +208,10 @@ public class NetworkTemplate implements Parcelable { return matchesWifi(ident); case MATCH_ETHERNET: return matchesEthernet(ident); + case MATCH_MOBILE_WILDCARD: + return matchesMobileWildcard(ident); + case MATCH_WIFI_WILDCARD: + return matchesWifiWildcard(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -257,13 +271,7 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - if (mNetworkId == null) { - return true; - } else { - return Objects.equal(mNetworkId, ident.mNetworkId); - } - case TYPE_WIFI_P2P: - return mNetworkId == null; + return Objects.equal(mNetworkId, ident.mNetworkId); default: return false; } @@ -279,6 +287,24 @@ public class NetworkTemplate implements Parcelable { return false; } + private boolean matchesMobileWildcard(NetworkIdentity ident) { + if (ident.mType == TYPE_WIMAX) { + return true; + } else { + return contains(DATA_USAGE_NETWORK_TYPES, ident.mType); + } + } + + private boolean matchesWifiWildcard(NetworkIdentity ident) { + switch (ident.mType) { + case TYPE_WIFI: + case TYPE_WIFI_P2P: + return true; + default: + return false; + } + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -291,6 +317,10 @@ public class NetworkTemplate implements Parcelable { return "WIFI"; case MATCH_ETHERNET: return "ETHERNET"; + case MATCH_MOBILE_WILDCARD: + return "MOBILE_WILDCARD"; + case MATCH_WIFI_WILDCARD: + return "WIFI_WILDCARD"; default: return "UNKNOWN"; } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ee3e1650ae..e437d2e347 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,6 +88,16 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + private static INetworkStatsService sStatsService; + + private synchronized static INetworkStatsService getStatsService() { + if (sStatsService == null) { + sStatsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + } + return sStatsService; + } + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -228,11 +238,9 @@ public class TrafficStats { * @param operationCount Number of operations to increment count by. */ public static void incrementOperationCount(int tag, int operationCount) { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); try { - statsService.incrementOperationCount(uid, tag, operationCount); + getStatsService().incrementOperationCount(uid, tag, operationCount); } catch (RemoteException e) { throw new RuntimeException(e); } @@ -257,7 +265,13 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileTxPackets(); + public static long getMobileTxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getTxPackets(iface); + } + return total; + } /** * Get the total number of packets received through the mobile interface. @@ -265,7 +279,13 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileRxPackets(); + public static long getMobileRxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getRxPackets(iface); + } + return total; + } /** * Get the total number of bytes transmitted through the mobile interface. @@ -273,7 +293,13 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileTxBytes(); + public static long getMobileTxBytes() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getTxBytes(iface); + } + return total; + } /** * Get the total number of bytes received through the mobile interface. @@ -281,7 +307,13 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getMobileRxBytes(); + public static long getMobileRxBytes() { + long total = 0; + for (String iface : getMobileIfaces()) { + total += getRxBytes(iface); + } + return total; + } /** * Get the total number of packets transmitted through the specified interface. @@ -290,7 +322,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getTxPackets(String iface); + public static long getTxPackets(String iface) { + return nativeGetIfaceStat(iface, TYPE_TX_PACKETS); + } /** * Get the total number of packets received through the specified interface. @@ -299,7 +333,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getRxPackets(String iface); + public static long getRxPackets(String iface) { + return nativeGetIfaceStat(iface, TYPE_RX_PACKETS); + } /** * Get the total number of bytes transmitted through the specified interface. @@ -308,7 +344,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getTxBytes(String iface); + public static long getTxBytes(String iface) { + return nativeGetIfaceStat(iface, TYPE_TX_BYTES); + } /** * Get the total number of bytes received through the specified interface. @@ -317,8 +355,9 @@ public class TrafficStats { * {@link #UNSUPPORTED} will be returned. * @hide */ - public static native long getRxBytes(String iface); - + public static long getRxBytes(String iface) { + return nativeGetIfaceStat(iface, TYPE_RX_BYTES); + } /** * Get the total number of packets sent through all network interfaces. @@ -326,7 +365,9 @@ public class TrafficStats { * @return the number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalTxPackets(); + public static long getTotalTxPackets() { + return nativeGetTotalStat(TYPE_TX_PACKETS); + } /** * Get the total number of packets received through all network interfaces. @@ -334,7 +375,9 @@ public class TrafficStats { * @return number of packets. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalRxPackets(); + public static long getTotalRxPackets() { + return nativeGetTotalStat(TYPE_RX_PACKETS); + } /** * Get the total number of bytes sent through all network interfaces. @@ -342,7 +385,9 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalTxBytes(); + public static long getTotalTxBytes() { + return nativeGetTotalStat(TYPE_TX_BYTES); + } /** * Get the total number of bytes received through all network interfaces. @@ -350,7 +395,9 @@ public class TrafficStats { * @return number of bytes. If the statistics are not supported by this device, * {@link #UNSUPPORTED} will be returned. */ - public static native long getTotalRxBytes(); + public static long getTotalRxBytes() { + return nativeGetTotalStat(TYPE_RX_BYTES); + } /** * Get the number of bytes sent through the network for this UID. @@ -483,7 +530,6 @@ public class TrafficStats { */ public static native long getUidTcpRxSegments(int uid); - /** * Get the number of UDP packets sent for this UID. * Includes DNS requests. @@ -515,13 +561,33 @@ public class TrafficStats { * special permission. */ private static NetworkStats getDataLayerSnapshotForUid(Context context) { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); final int uid = android.os.Process.myUid(); try { - return statsService.getDataLayerSnapshotForUid(uid); + return getStatsService().getDataLayerSnapshotForUid(uid); } catch (RemoteException e) { throw new RuntimeException(e); } } + + /** + * Return set of any ifaces associated with mobile networks since boot. + * Interfaces are never removed from this list, so counters should always be + * monotonic. + */ + private static String[] getMobileIfaces() { + try { + return getStatsService().getMobileIfaces(); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + + // NOTE: keep these in sync with android_net_TrafficStats.cpp + private static final int TYPE_RX_BYTES = 0; + private static final int TYPE_RX_PACKETS = 1; + private static final int TYPE_TX_BYTES = 2; + private static final int TYPE_TX_PACKETS = 3; + + private static native long nativeGetTotalStat(int type); + private static native long nativeGetIfaceStat(String iface, int type); } diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 0ab659b238..325fe26041 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -31,6 +31,9 @@ namespace android { +static const uint64_t VALUE_UNKNOWN = -1; +static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all"; + enum Tx_Rx { TX, RX @@ -42,6 +45,21 @@ enum Tcp_Udp { TCP_AND_UDP }; +// NOTE: keep these in sync with TrafficStats.java +enum IfaceStatType { + RX_BYTES = 0, + RX_PACKETS = 1, + TX_BYTES = 2, + TX_PACKETS = 3 +}; + +struct IfaceStat { + uint64_t rxBytes; + uint64_t rxPackets; + uint64_t txBytes; + uint64_t txPackets; +}; + // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { char buf[80]; @@ -63,130 +81,82 @@ static jlong readNumber(char const* filename) { return atoll(buf); } -static const char* mobile_iface_list[] = { - "rmnet0", - "rmnet1", - "rmnet2", - "rmnet3", - "cdma_rmnet4", - "ppp0", - 0 -}; +static int parseIfaceStat(const char* iface, struct IfaceStat* stat) { + FILE *fp = fopen(IFACE_STAT_ALL, "r"); + if (!fp) { + return errno; + } -static jlong getAll(const char** iface_list, const char* what) { + char buffer[256]; + char cur_iface[32]; + int active; + uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes, + devTxPackets; - char filename[80]; - int idx = 0; - bool supported = false; - jlong total = 0; - while (iface_list[idx] != 0) { - - snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", - iface_list[idx], what); - jlong number = readNumber(filename); - if (number >= 0) { - supported = true; - total += number; + while (fgets(buffer, 256, fp) != NULL) { + if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active, + &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets, + &devTxBytes, &devTxPackets) != 10) { + continue; } - idx++; - } - if (supported) return total; - return -1; -} + if (!iface || !strcmp(iface, cur_iface)) { + stat->rxBytes += rxBytes; + stat->rxPackets += rxPackets; + stat->txBytes += txBytes; + stat->txPackets += txPackets; -// Returns the sum of numbers from the specified path under /sys/class/net/*, -// -1 if no such file exists. -static jlong readTotal(char const* suffix) { - char filename[PATH_MAX] = "/sys/class/net/"; - DIR *dir = opendir(filename); - if (dir == NULL) { - ALOGE("Can't list %s: %s", filename, strerror(errno)); - return -1; - } - - int len = strlen(filename); - jlong total = -1; - while (struct dirent *entry = readdir(dir)) { - // Skip ., .., and localhost interfaces. - if (entry->d_name[0] != '.' && strncmp(entry->d_name, "lo", 2) != 0) { - strlcpy(filename + len, entry->d_name, sizeof(filename) - len); - strlcat(filename, suffix, sizeof(filename)); - jlong num = readNumber(filename); - if (num >= 0) total = total < 0 ? num : total + num; + if (active) { + stat->rxBytes += devRxBytes; + stat->rxPackets += devRxPackets; + stat->txBytes += devTxBytes; + stat->txPackets += devTxPackets; + } } } - closedir(dir); - return total; + fclose(fp); + return 0; } -// Mobile stats get accessed a lot more often than total stats. -// Note the individual files can come and go at runtime, so we check -// each file every time (rather than caching which ones exist). +static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) { + struct IfaceStat stat; + memset(&stat, 0, sizeof(IfaceStat)); -static jlong getMobileTxPackets(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "tx_packets"); -} - -static jlong getMobileRxPackets(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "rx_packets"); -} - -static jlong getMobileTxBytes(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "tx_bytes"); -} - -static jlong getMobileRxBytes(JNIEnv* env, jobject clazz) { - return getAll(mobile_iface_list, "rx_bytes"); -} - -static jlong getData(JNIEnv* env, const char* what, jstring javaInterface) { - ScopedUtfChars interface(env, javaInterface); - if (interface.c_str() == NULL) { - return -1; + if (parseIfaceStat(iface, &stat)) { + return VALUE_UNKNOWN; } - char filename[80]; - snprintf(filename, sizeof(filename), "/sys/class/net/%s/statistics/%s", interface.c_str(), what); - return readNumber(filename); + switch (type) { + case RX_BYTES: + return stat.rxBytes; + case RX_PACKETS: + return stat.rxPackets; + case TX_BYTES: + return stat.txBytes; + case TX_PACKETS: + return stat.txPackets; + default: + return VALUE_UNKNOWN; + } } -static jlong getTxPackets(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "tx_packets", interface); +static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { + return getIfaceStatType(NULL, (IfaceStatType) type); } -static jlong getRxPackets(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "rx_packets", interface); +static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { + struct IfaceStat stat; + const char* ifaceChars = env->GetStringUTFChars(iface, NULL); + if (ifaceChars) { + uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type); + env->ReleaseStringUTFChars(iface, ifaceChars); + return stat; + } else { + return VALUE_UNKNOWN; + } } -static jlong getTxBytes(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "tx_bytes", interface); -} - -static jlong getRxBytes(JNIEnv* env, jobject clazz, jstring interface) { - return getData(env, "rx_bytes", interface); -} - - -// Total stats are read less often, so we're willing to put up -// with listing the directory and concatenating filenames. - -static jlong getTotalTxPackets(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/tx_packets"); -} - -static jlong getTotalRxPackets(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/rx_packets"); -} - -static jlong getTotalTxBytes(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/tx_bytes"); -} - -static jlong getTotalRxBytes(JNIEnv* env, jobject clazz) { - return readTotal("/statistics/rx_bytes"); -} // Per-UID stats require reading from a constructed filename. @@ -323,18 +293,8 @@ static jlong getUidUdpRxPackets(JNIEnv* env, jobject clazz, jint uid) { } static JNINativeMethod gMethods[] = { - {"getMobileTxPackets", "()J", (void*) getMobileTxPackets}, - {"getMobileRxPackets", "()J", (void*) getMobileRxPackets}, - {"getMobileTxBytes", "()J", (void*) getMobileTxBytes}, - {"getMobileRxBytes", "()J", (void*) getMobileRxBytes}, - {"getTxPackets", "(Ljava/lang/String;)J", (void*) getTxPackets}, - {"getRxPackets", "(Ljava/lang/String;)J", (void*) getRxPackets}, - {"getTxBytes", "(Ljava/lang/String;)J", (void*) getTxBytes}, - {"getRxBytes", "(Ljava/lang/String;)J", (void*) getRxBytes}, - {"getTotalTxPackets", "()J", (void*) getTotalTxPackets}, - {"getTotalRxPackets", "()J", (void*) getTotalRxPackets}, - {"getTotalTxBytes", "()J", (void*) getTotalTxBytes}, - {"getTotalRxBytes", "()J", (void*) getTotalRxBytes}, + {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, + {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, /* Per-UID Stats */ {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 4382a03fa2..2a67e02db2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; @@ -33,7 +34,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileAll; +import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; @@ -54,6 +55,8 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.internal.util.ArrayUtils.appendElement; +import static com.android.internal.util.ArrayUtils.contains; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -194,6 +197,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private HashMap mActiveIfaces = Maps.newHashMap(); /** Current default active iface. */ private String mActiveIface; + /** Set of any ifaces associated with mobile networks since boot. */ + private String[] mMobileIfaces = new String[0]; private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -516,6 +521,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return dataLayer; } + @Override + public String[] getMobileIfaces() { + return mMobileIfaces; + } + @Override public void incrementOperationCount(int uid, int tag, int operationCount) { if (Binder.getCallingUid() != uid) { @@ -735,6 +745,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); + + // remember any ifaces associated with mobile networks + if (isNetworkTypeMobile(state.networkInfo.getType())) { + if (!contains(mMobileIfaces, iface)) { + mMobileIfaces = appendElement(String.class, mMobileIfaces, iface); + } + } } } } @@ -861,7 +878,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStats.Entry uidTotal; // collect mobile sample - template = buildTemplateMobileAll(getActiveSubscriberId(mContext)); + template = buildTemplateMobileWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); xtTotal = new NetworkStats.Entry(); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); @@ -1022,12 +1039,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private static String getActiveSubscriberId(Context context) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - return telephony.getSubscriberId(); - } - private boolean isBandwidthControlEnabled() { try { return mNetworkManager.isBandwidthControlEnabled(); From 18da1320fed405cfa1cb1f361b7bfdad881b44cb Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Fri, 13 Apr 2012 12:15:41 -0700 Subject: [PATCH 0140/1150] Open network service discovery API Add support for DNS based network service discovery API. This allows applications to discover and resolve applications on a local network such as Wi-Fi Change-Id: Ie89895edd35d12b7f7a23fb5fed36cb2b2079f7a --- .../android/net/nsd/DnsSdServiceInfo.java | 20 +- core/java/android/net/nsd/NsdManager.java | 340 +++++++++++++----- .../java/com/android/server/NsdService.java | 14 + 3 files changed, 281 insertions(+), 93 deletions(-) diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/DnsSdServiceInfo.java index 33c3eb98aa..66abd3a321 100644 --- a/core/java/android/net/nsd/DnsSdServiceInfo.java +++ b/core/java/android/net/nsd/DnsSdServiceInfo.java @@ -22,8 +22,8 @@ import android.os.Parcel; import java.net.InetAddress; /** - * Defines a service based on DNS service discovery - * {@hide} + * A class representing service information for network service discovery + * {@see NsdManager} */ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { @@ -40,56 +40,63 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { public DnsSdServiceInfo() { } + /** @hide */ public DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { mServiceName = sn; mServiceType = rt; mTxtRecord = tr; } + /** Get the service name */ @Override - /** @hide */ public String getServiceName() { return mServiceName; } + /** Set the service name */ @Override - /** @hide */ public void setServiceName(String s) { mServiceName = s; } + /** Get the service type */ @Override - /** @hide */ public String getServiceType() { return mServiceType; } + /** Set the service type */ @Override - /** @hide */ public void setServiceType(String s) { mServiceType = s; } + /** @hide */ public DnsSdTxtRecord getTxtRecord() { return mTxtRecord; } + /** @hide */ public void setTxtRecord(DnsSdTxtRecord t) { mTxtRecord = new DnsSdTxtRecord(t); } + /** Get the host address. The host address is valid for a resolved service. */ public InetAddress getHost() { return mHost; } + /** Set the host address */ public void setHost(InetAddress s) { mHost = s; } + /** Get port number. The port number is valid for a resolved service. */ public int getPort() { return mPort; } + /** Set port number */ public void setPort(int p) { mPort = p; } @@ -147,5 +154,4 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { return new DnsSdServiceInfo[size]; } }; - } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 505f11b542..dac8d200db 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -24,29 +24,110 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.Messenger; +import android.text.TextUtils; import android.util.Log; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; /** - * The Network Service Discovery Manager class provides the API for service - * discovery. Service discovery enables applications to discover and connect with services - * on a network. Example applications include a game application discovering another instance - * of the game application or a printer application discovering other printers on a network. + * The Network Service Discovery Manager class provides the API to discover services + * on a network. As an example, if device A and device B are connected over a Wi-Fi + * network, a game registered on device A can be discovered by a game on device + * B. Another example use case is an application discovering printers on the network. + * + *

The API currently supports DNS based service discovery and discovery is currently + * limited to a local network over Multicast DNS. In future, it will be extended to + * support wide area discovery and other service discovery mechanisms. + * DNS service discovery is described at http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * *

The API is asynchronous and responses to requests from an application are on listener - * callbacks provided by the application. The application needs to do an initialization with - * {@link #initialize} before doing any operation. + * callbacks provided by the application. The application must invoke {@link #initialize} before + * doing any other operation. * - *

Android currently supports DNS based service discovery and it is limited to a local - * network with the use of multicast DNS. In future, this class will be - * extended to support other service discovery mechanisms. + *

There are three main operations the API supports - registration, discovery and resolution. + *

+ *                          Application start
+ *                                 |
+ *                                 |         <----------------------------------------------
+ *                             initialize()                                                 |
+ *                                 |                                                        |
+ *                                 | Wait until channel connects                            |
+ *                                 | before doing any operation                             |
+ *                                 |                                                        |
+ *                           onChannelConnected()                    __________             |
+ *                                 |                                           |            |
+ *                                 |                                           |            |
+ *                                 |                  onServiceRegistered()    |            |
+ *                     Register any local services  /                          |            |
+ *                      to be advertised with       \                          |            | If application needs to
+ *                       registerService()            onFailure()              |            | do any further operations
+ *                                 |                                           |            | again, it needs to
+ *                                 |                                           |            | initialize() connection
+ *                          discoverServices()                                 |            | to framework again
+ *                                 |                                           |            |
+ *                      Maintain a list to track                               |            |
+ *                        discovered services                                  |            |
+ *                                 |                                           |            |
+ *                                 |--------->                                 |-> onChannelDisconnected()
+ *                                 |          |                                |
+ *                                 |      onServiceFound()                     |
+ *                                 |          |                                |
+ *                                 |     add service to list                   |
+ *                                 |          |                                |
+ *                                 |<----------                                |
+ *                                 |                                           |
+ *                                 |--------->                                 |
+ *                                 |          |                                |
+ *                                 |      onServiceLost()                      |
+ *                                 |          |                                |
+ *                                 |   remove service from list                |
+ *                                 |          |                                |
+ *                                 |<----------                                |
+ *                                 |                                           |
+ *                                 |                                           |
+ *                                 | Connect to a service                      |
+ *                                 | from list ?                               |
+ *                                 |                                           |
+ *                          resolveService()                                   |
+ *                                 |                                           |
+ *                         onServiceResolved()                                 |
+ *                                 |                                           |
+ *                     Establish connection to service                         |
+ *                     with the host and port information                      |
+ *                                 |                                           |
+ *                                 |                                ___________|
+ *                           deinitialize()
+ *                    when done with all operations
+ *                          or before quit
+ *
+ * 
+ * An application that needs to advertise itself over a network for other applications to + * discover it can do so with a call to {@link #registerService}. If Example is a http based + * application that can provide HTML data to peer services, it can register a name "Example" + * with service type "_http._tcp". A successful registration is notified with a callback to + * {@link DnsSdRegisterListener#onServiceRegistered} and a failure to register is notified + * over {@link DnsSdRegisterListener#onFailure} + * + *

A peer application looking for http services can initiate a discovery for "_http._tcp" + * with a call to {@link #discoverServices}. A service found is notified with a callback + * to {@link DnsSdDiscoveryListener#onServiceFound} and a service lost is notified on + * {@link DnsSdDiscoveryListener#onServiceLost}. + * + *

Once the peer application discovers the "Example" http srevice, and needs to receive data + * from the "Example" application, it can initiate a resolve with {@link #resolveService} to + * resolve the host and port details for the purpose of establishing a connection. A successful + * resolve is notified on {@link DnsSdResolveListener#onServiceResolved} and a failure is notified + * on {@link DnsSdResolveListener#onFailure}. + * + * Applications can reserve for a service type at + * http://www.iana.org/form/ports-service. Existing services can be found at + * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml * * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) * Context.getSystemService(Context.NSD_SERVICE)}. - * @hide * + * {@see DnsSdServiceInfo} */ public class NsdManager { private static final String TAG = "NsdManager"; @@ -80,27 +161,32 @@ public class NsdManager { public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11; /** @hide */ - public static final int UPDATE_SERVICE = BASE + 12; + public static final int UNREGISTER_SERVICE = BASE + 12; /** @hide */ - public static final int UPDATE_SERVICE_FAILED = BASE + 13; + public static final int UNREGISTER_SERVICE_FAILED = BASE + 13; /** @hide */ - public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 14; + public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14; /** @hide */ - public static final int RESOLVE_SERVICE = BASE + 15; + public static final int UPDATE_SERVICE = BASE + 15; /** @hide */ - public static final int RESOLVE_SERVICE_FAILED = BASE + 16; + public static final int UPDATE_SERVICE_FAILED = BASE + 16; /** @hide */ - public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 17; + public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 17; /** @hide */ - public static final int STOP_RESOLVE = BASE + 18; + public static final int RESOLVE_SERVICE = BASE + 18; /** @hide */ - public static final int STOP_RESOLVE_FAILED = BASE + 19; + public static final int RESOLVE_SERVICE_FAILED = BASE + 19; /** @hide */ - public static final int STOP_RESOLVE_SUCCEEDED = BASE + 20; - + public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; + /** @hide */ + public static final int STOP_RESOLVE = BASE + 21; + /** @hide */ + public static final int STOP_RESOLVE_FAILED = BASE + 22; + /** @hide */ + public static final int STOP_RESOLVE_SUCCEEDED = BASE + 23; /** * Create a new Nsd instance. Applications use @@ -115,36 +201,44 @@ public class NsdManager { } /** + * Passed with onFailure() calls. * Indicates that the operation failed due to an internal error. */ public static final int ERROR = 0; /** - * Indicates that the operation failed because service discovery is unsupported on the device. + * Passed with onFailure() calls. + * Indicates that the operation failed because service discovery + * is unsupported on the device. */ public static final int UNSUPPORTED = 1; /** - * Indicates that the operation failed because the framework is busy and - * unable to service the request. + * Passed with onFailure() calls. + * Indicates that the operation failed because the framework is + * busy and unable to service the request. */ public static final int BUSY = 2; /** + * Passed with onFailure() calls. * Indicates that the operation failed because it is already active. */ public static final int ALREADY_ACTIVE = 3; /** + * Passed with onFailure() calls. * Indicates that the operation failed because maximum limit on * service registrations has reached. */ public static final int MAX_REGS_REACHED = 4; - - /** Interface for callback invocation when framework channel is connected or lost */ public interface ChannelListener { + /** + * The channel to the framework is connected. + * Application can initiate calls into the framework using the channel instance passed. + */ public void onChannelConnected(Channel c); /** * The channel to the framework has been disconnected. @@ -153,6 +247,7 @@ public class NsdManager { public void onChannelDisconnected(); } + /** Generic interface for callback invocation for a success or failure */ public interface ActionListener { public void onFailure(int errorCode); @@ -160,11 +255,12 @@ public class NsdManager { public void onSuccess(); } + /** Interface for callback invocation for service discovery */ public interface DnsSdDiscoveryListener { public void onFailure(int errorCode); - public void onStarted(String registrationType); + public void onStarted(String serviceType); public void onServiceFound(DnsSdServiceInfo serviceInfo); @@ -172,6 +268,7 @@ public class NsdManager { } + /** Interface for callback invocation for service registration */ public interface DnsSdRegisterListener { public void onFailure(int errorCode); @@ -179,6 +276,7 @@ public class NsdManager { public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo); } + /** @hide */ public interface DnsSdUpdateRegistrationListener { public void onFailure(int errorCode); @@ -186,6 +284,7 @@ public class NsdManager { public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord); } + /** Interface for callback invocation for service resolution */ public interface DnsSdResolveListener { public void onFailure(int errorCode); @@ -208,6 +307,7 @@ public class NsdManager { private DnsSdDiscoveryListener mDnsSdDiscoveryListener; private ActionListener mDnsSdStopDiscoveryListener; private DnsSdRegisterListener mDnsSdRegisterListener; + private ActionListener mDnsSdUnregisterListener; private DnsSdUpdateRegistrationListener mDnsSdUpdateListener; private DnsSdResolveListener mDnsSdResolveListener; private ActionListener mDnsSdStopResolveListener; @@ -279,7 +379,17 @@ public class NsdManager { (DnsSdServiceInfo) message.obj); } break; - case UPDATE_SERVICE_FAILED: + case UNREGISTER_SERVICE_FAILED: + if (mDnsSdUnregisterListener != null) { + mDnsSdUnregisterListener.onFailure(message.arg1); + } + break; + case UNREGISTER_SERVICE_SUCCEEDED: + if (mDnsSdUnregisterListener != null) { + mDnsSdUnregisterListener.onSuccess(); + } + break; + case UPDATE_SERVICE_FAILED: if (mDnsSdUpdateListener != null) { mDnsSdUpdateListener.onFailure(message.arg1); } @@ -319,6 +429,10 @@ public class NsdManager { } } + private static void checkChannel(Channel c) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + } + /** * Registers the application with the service discovery framework. This function * must be the first to be called before any other operations are performed. No service @@ -327,7 +441,7 @@ public class NsdManager { * * @param srcContext is the context of the source * @param srcLooper is the Looper on which the callbacks are receivied - * @param listener for callback at loss of framework communication. + * @param listener for callback at loss of framework communication. Cannot be null. */ public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { Messenger messenger = getMessenger(); @@ -339,88 +453,142 @@ public class NsdManager { } /** - * Set the listener for service discovery. Can be null. + * Disconnects application from service discovery framework. No further operations + * will succeed until a {@link #initialize} is called again. + * + * @param c channel initialized with {@link #initialize} */ - public void setDiscoveryListener(Channel c, DnsSdDiscoveryListener b) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdDiscoveryListener = b; + public void deinitialize(Channel c) { + checkChannel(c); + c.mAsyncChannel.disconnect(); } /** - * Set the listener for stop service discovery. Can be null. + * Register a service to be discovered by other services. + * + *

The function call immediately returns after sending a request to register service + * to the framework. The application is notified of a success to initiate + * discovery through the callback {@link DnsSdRegisterListener#onServiceRegistered} or a failure + * through {@link DnsSdRegisterListener#onFailure}. + * + * @param c is the channel created at {@link #initialize} + * @param serviceType The service type being advertised. + * @param port on which the service is listenering for incoming connections + * @param listener for success or failure callback. Can be null. */ - public void setStopDiscoveryListener(Channel c, ActionListener a) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdStopDiscoveryListener = a; - } - - /** - * Set the listener for service registration. Can be null. - */ - public void setRegisterListener(Channel c, DnsSdRegisterListener b) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdRegisterListener = b; - } - - /** - * Set the listener for service registration. Can be null. - */ - public void setUpdateRegistrationListener(Channel c, DnsSdUpdateRegistrationListener b) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdUpdateListener = b; - } - - /** - * Set the listener for service resolution. Can be null. - */ - public void setResolveListener(Channel c, DnsSdResolveListener b) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdResolveListener = b; - } - - /** - * Set the listener for stopping service resolution. Can be null. - */ - public void setStopResolveListener(Channel c, ActionListener b) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - c.mDnsSdStopResolveListener = b; - } - - public void registerService(Channel c, DnsSdServiceInfo serviceInfo) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo"); + public void registerService(Channel c, String serviceName, String serviceType, int port, + DnsSdRegisterListener listener) { + checkChannel(c); + if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException("Service name or type cannot be empty"); + } + if (port <= 0) { + throw new IllegalArgumentException("Invalid port number"); + } + DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null); + serviceInfo.setPort(port); + c.mDnsSdRegisterListener = listener; c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo); } + /** + * Unregister a service registered through {@link #registerService} + * @param c is the channel created at {@link #initialize} + * @param registeredId is obtained at {@link DnsSdRegisterListener#onServiceRegistered} + * @param listener provides callbacks for success or failure. Can be null. + */ + public void unregisterService(Channel c, int registeredId, ActionListener listener) { + checkChannel(c); + c.mDnsSdUnregisterListener = listener; + c.mAsyncChannel.sendMessage(UNREGISTER_SERVICE, registeredId); + } + + /** @hide */ public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + checkChannel(c); c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord); } - public void discoverServices(Channel c, String serviceType) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - if (c.mDnsSdDiscoveryListener == null) throw new - IllegalStateException("Discovery listener needs to be set first"); + /** + * Initiate service discovery to browse for instances of a service type. Service discovery + * consumes network bandwidth and will continue until the application calls + * {@link #stopServiceDiscovery}. + * + *

The function call immediately returns after sending a request to start service + * discovery to the framework. The application is notified of a success to initiate + * discovery through the callback {@link DnsSdDiscoveryListener#onStarted} or a failure + * through {@link DnsSdDiscoveryListener#onFailure}. + * + *

Upon successful start, application is notified when a service is found with + * {@link DnsSdDiscoveryListener#onServiceFound} or when a service is lost with + * {@link DnsSdDiscoveryListener#onServiceLost}. + * + *

Upon failure to start, service discovery is not active and application does + * not need to invoke {@link #stopServiceDiscovery} + * + * @param c is the channel created at {@link #initialize} + * @param serviceType The service type being discovered. Examples include "_http._tcp" for + * http services or "_ipp._tcp" for printers + * @param listener provides callbacks when service is found or lost. Cannot be null. + */ + public void discoverServices(Channel c, String serviceType, DnsSdDiscoveryListener listener) { + checkChannel(c); + if (listener == null) { + throw new IllegalStateException("Discovery listener needs to be set first"); + } + if (TextUtils.isEmpty(serviceType)) { + throw new IllegalStateException("Service type cannot be empty"); + } DnsSdServiceInfo s = new DnsSdServiceInfo(); s.setServiceType(serviceType); + c.mDnsSdDiscoveryListener = listener; c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s); } - public void stopServiceDiscovery(Channel c) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + /** + * Stop service discovery initiated with {@link #discoverServices}. An active service + * discovery is notified to the application with {@link DnsSdDiscoveryListener#onStarted} + * and it stays active until the application invokes a stop service discovery. + * + *

Upon failure to start service discovery notified through + * {@link DnsSdDiscoveryListener#onFailure} service discovery is not active and + * application does not need to stop it. + * + * @param c is the channel created at {@link #initialize} + * @param listener notifies success or failure. Can be null. + */ + public void stopServiceDiscovery(Channel c, ActionListener listener) { + checkChannel(c); + c.mDnsSdStopDiscoveryListener = listener; c.mAsyncChannel.sendMessage(STOP_DISCOVERY); } - public void resolveService(Channel c, DnsSdServiceInfo serviceInfo) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); - if (serviceInfo == null) throw new IllegalArgumentException("Null serviceInfo"); - if (c.mDnsSdResolveListener == null) throw new - IllegalStateException("Resolve listener needs to be set first"); + /** + * Resolve a discovered service. An application can resolve a service right before + * establishing a connection to fetch the IP and port details on which to setup + * the connection. + * + * @param c is the channel created at {@link #initialize} + * @param serviceName of the the service + * @param serviceType of the service + * @param listener to receive callback upon success or failure. Cannot be null. + */ + public void resolveService(Channel c, String serviceName, String serviceType, + DnsSdResolveListener listener) { + checkChannel(c); + if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException("Service name or type cannot be empty"); + } + if (listener == null) throw new + IllegalStateException("Resolve listener cannot be null"); + c.mDnsSdResolveListener = listener; + DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null); c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo); } + /** @hide */ public void stopServiceResolve(Channel c) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + checkChannel(c); if (c.mDnsSdResolveListener == null) throw new IllegalStateException("Resolve listener needs to be set first"); c.mAsyncChannel.sendMessage(STOP_RESOLVE); diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index a3ac8d0849..8014e272b0 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -167,6 +167,18 @@ public class NsdService extends INsdManager.Stub { NsdManager.ERROR); } break; + case NsdManager.UNREGISTER_SERVICE: + if (DBG) Slog.d(TAG, "unregister service"); + clientInfo = mClients.get(msg.replyTo); + int regId = msg.arg1; + if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && + unregisterService(regId)) { + mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } + break; case NsdManager.UPDATE_SERVICE: if (DBG) Slog.d(TAG, "Update service"); //TODO: implement @@ -237,6 +249,8 @@ public class NsdService extends INsdManager.Stub { } public Messenger getMessenger() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, + "NsdService"); return new Messenger(mAsyncServiceHandler); } From 7500665eb7596f0cada2f7fbcb9efa26e1aaae8f Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Tue, 17 Apr 2012 23:15:29 -0700 Subject: [PATCH 0141/1150] Add user control to turn on/off nsd Change-Id: Ide3cc20adb21ac6dffaf6b9b9136d77a129afa3b --- core/java/android/net/nsd/INsdManager.aidl | 1 + core/java/android/net/nsd/NsdManager.java | 57 +- .../java/com/android/server/NsdService.java | 500 ++++++++++++------ 3 files changed, 396 insertions(+), 162 deletions(-) diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 077a675a14..3361a7b84b 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -26,4 +26,5 @@ import android.os.Messenger; interface INsdManager { Messenger getMessenger(); + void setEnabled(boolean enable); } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index dac8d200db..62c141d558 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,8 @@ package android.net.nsd; +import android.annotation.SdkConstant; +import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; import android.os.IBinder; @@ -133,6 +135,44 @@ public class NsdManager { private static final String TAG = "NsdManager"; INsdManager mService; + /** + * Broadcast intent action to indicate whether network service discovery is + * enabled or disabled. An extra {@link #EXTRA_NSD_STATE} provides the state + * information as int. + * + * @see #EXTRA_NSD_STATE + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String NSD_STATE_CHANGED_ACTION = + "android.net.nsd.STATE_CHANGED"; + + /** + * The lookup key for an int that indicates whether network service discovery is enabled + * or disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}. + * + * @see #NSD_STATE_DISABLED + * @see #NSD_STATE_ENABLED + * @hide + */ + public static final String EXTRA_NSD_STATE = "nsd_state"; + + /** + * Network service discovery is disabled + * + * @see #NSD_STATE_CHANGED_ACTION + * @hide + */ + public static final int NSD_STATE_DISABLED = 1; + + /** + * Network service discovery is enabled + * + * @see #NSD_STATE_CHANGED_ACTION + * @hide + */ + public static final int NSD_STATE_ENABLED = 2; + private static final int BASE = Protocol.BASE_NSD_MANAGER; /** @hide */ @@ -188,6 +228,12 @@ public class NsdManager { /** @hide */ public static final int STOP_RESOLVE_SUCCEEDED = BASE + 23; + /** @hide */ + public static final int ENABLE = BASE + 24; + /** @hide */ + public static final int DISABLE = BASE + 25; + + /** * Create a new Nsd instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -312,8 +358,8 @@ public class NsdManager { private DnsSdResolveListener mDnsSdResolveListener; private ActionListener mDnsSdStopResolveListener; - AsyncChannel mAsyncChannel; - ServiceHandler mHandler; + private AsyncChannel mAsyncChannel; + private ServiceHandler mHandler; class ServiceHandler extends Handler { ServiceHandler(Looper looper) { super(looper); @@ -594,6 +640,13 @@ public class NsdManager { c.mAsyncChannel.sendMessage(STOP_RESOLVE); } + /** Internal use only @hide */ + public void setEnabled(boolean enabled) { + try { + mService.setEnabled(enabled); + } catch (RemoteException e) { } + } + /** * Get a reference to NetworkService handler. This is used to establish * an AsyncChannel communication with the service diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 8014e272b0..839fbe279d 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -17,6 +17,8 @@ package com.android.server; import android.content.Context; +import android.content.ContentResolver; +import android.content.Intent; import android.content.pm.PackageManager; import android.net.nsd.DnsSdServiceInfo; import android.net.nsd.DnsSdTxtRecord; @@ -28,6 +30,7 @@ import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; import android.os.IBinder; +import android.provider.Settings; import android.util.Slog; import java.io.FileDescriptor; @@ -41,6 +44,9 @@ import java.util.concurrent.CountDownLatch; import com.android.internal.app.IBatteryStats; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; +import com.android.internal.util.State; +import com.android.internal.util.StateMachine; import com.android.server.am.BatteryStatsService; import com.android.server.NativeDaemonConnector.Command; import com.android.internal.R; @@ -58,6 +64,8 @@ public class NsdService extends INsdManager.Stub { private static final boolean DBG = true; private Context mContext; + private ContentResolver mContentResolver; + private NsdStateMachine mNsdStateMachine; /** * Clients receiving asynchronous messages @@ -69,189 +77,342 @@ public class NsdService extends INsdManager.Stub { private int INVALID_ID = 0; private int mUniqueId = 1; - /** - * Handles client(app) connections - */ - private class AsyncServiceHandler extends Handler { + private static final int BASE = Protocol.BASE_NSD_MANAGER; + private static final int CMD_TO_STRING_COUNT = NsdManager.STOP_RESOLVE - BASE + 1; + private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; - AsyncServiceHandler(android.os.Looper looper) { - super(looper); - } + static { + sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER"; + sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER"; + sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER"; + sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER"; + sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE"; + sCmdToString[NsdManager.STOP_RESOLVE - BASE] = "STOP-RESOLVE"; + } - @Override - public void handleMessage(Message msg) { - ClientInfo clientInfo; - DnsSdServiceInfo servInfo; - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - AsyncChannel c = (AsyncChannel) msg.obj; - if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); - c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); - if (mClients.size() == 0) { - startMDnsDaemon(); - } - mClients.put(msg.replyTo, cInfo); - } else { - Slog.e(TAG, "Client connection failure, error=" + msg.arg1); - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); - } - mClients.remove(msg.replyTo); - if (mClients.size() == 0) { - stopMDnsDaemon(); - } - break; - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, this, msg.replyTo); - break; - case NsdManager.DISCOVER_SERVICES: - if (DBG) Slog.d(TAG, "Discover services"); - servInfo = (DnsSdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId != INVALID_ID) { - //discovery already in progress - if (DBG) Slog.d(TAG, "discovery in progress"); - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ALREADY_ACTIVE); - break; - } - clientInfo.mDiscoveryId = getUniqueId(); - if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ERROR); - clientInfo.mDiscoveryId = INVALID_ID; - } - break; - case NsdManager.STOP_DISCOVERY: - if (DBG) Slog.d(TAG, "Stop service discovery"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "discovery already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ALREADY_ACTIVE); - break; - } - if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { - clientInfo.mDiscoveryId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ERROR); - } - break; - case NsdManager.REGISTER_SERVICE: - if (DBG) Slog.d(TAG, "Register service"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { - if (DBG) Slog.d(TAG, "register service exceeds limit"); - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.MAX_REGS_REACHED); - } - - int id = getUniqueId(); - if (registerService(id, (DnsSdServiceInfo) msg.obj)) { - clientInfo.mRegisteredIds.add(id); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.ERROR); - } - break; - case NsdManager.UNREGISTER_SERVICE: - if (DBG) Slog.d(TAG, "unregister service"); - clientInfo = mClients.get(msg.replyTo); - int regId = msg.arg1; - if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && - unregisterService(regId)) { - mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.ERROR); - } - break; - case NsdManager.UPDATE_SERVICE: - if (DBG) Slog.d(TAG, "Update service"); - //TODO: implement - mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); - break; - case NsdManager.RESOLVE_SERVICE: - if (DBG) Slog.d(TAG, "Resolve service"); - servInfo = (DnsSdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId != INVALID_ID) { - //first cancel existing resolve - stopResolveService(clientInfo.mResolveId); - } - - clientInfo.mResolveId = getUniqueId(); - if (!resolveService(clientInfo.mResolveId, servInfo)) { - mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.ERROR); - clientInfo.mResolveId = INVALID_ID; - } - break; - case NsdManager.STOP_RESOLVE: - if (DBG) Slog.d(TAG, "Stop resolve"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "resolve already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ALREADY_ACTIVE); - break; - } - if (stopResolveService(clientInfo.mResolveId)) { - clientInfo.mResolveId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); - } else { - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ERROR); - } - break; - default: - Slog.d(TAG, "NsdServicehandler.handleMessage ignoring msg=" + msg); - break; - } + private static String cmdToString(int cmd) { + cmd -= BASE; + if ((cmd >= 0) && (cmd < sCmdToString.length)) { + return sCmdToString[cmd]; + } else { + return null; } } - private AsyncServiceHandler mAsyncServiceHandler; + + private class NsdStateMachine extends StateMachine { + + private DefaultState mDefaultState = new DefaultState(); + private DisabledState mDisabledState = new DisabledState(); + private EnabledState mEnabledState = new EnabledState(); + + @Override + protected String getMessageInfo(Message msg) { + return cmdToString(msg.what); + } + + NsdStateMachine(String name) { + super(name); + addState(mDefaultState); + addState(mDisabledState, mDefaultState); + addState(mEnabledState, mDefaultState); + if (isNsdEnabled()) { + setInitialState(mEnabledState); + } else { + setInitialState(mDisabledState); + } + setProcessedMessagesSize(25); + } + + class DefaultState extends State { + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + AsyncChannel c = (AsyncChannel) msg.obj; + if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); + c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); + ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + mClients.put(msg.replyTo, cInfo); + } else { + Slog.e(TAG, "Client connection failure, error=" + msg.arg1); + } + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { + Slog.e(TAG, "Send failed, client connection lost"); + } else { + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + } + mClients.remove(msg.replyTo); + break; + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: + AsyncChannel ac = new AsyncChannel(); + ac.connect(mContext, getHandler(), msg.replyTo); + break; + case NsdManager.DISCOVER_SERVICES: + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.BUSY); + break; + case NsdManager.STOP_DISCOVERY: + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ERROR); + break; + case NsdManager.REGISTER_SERVICE: + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.ERROR); + break; + case NsdManager.UNREGISTER_SERVICE: + mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.ERROR); + break; + case NsdManager.RESOLVE_SERVICE: + mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + break; + case NsdManager.STOP_RESOLVE: + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ERROR); + break; + default: + Slog.e(TAG, "Unhandled " + msg); + return NOT_HANDLED; + } + return HANDLED; + } + } + + class DisabledState extends State { + @Override + public void enter() { + sendNsdStateChangeBroadcast(false); + } + + @Override + public boolean processMessage(Message msg) { + switch (msg.what) { + case NsdManager.ENABLE: + transitionTo(mEnabledState); + break; + default: + return NOT_HANDLED; + } + return HANDLED; + } + } + + class EnabledState extends State { + @Override + public void enter() { + sendNsdStateChangeBroadcast(true); + if (mClients.size() > 0) { + startMDnsDaemon(); + } + } + + @Override + public void exit() { + if (mClients.size() > 0) { + stopMDnsDaemon(); + } + } + + @Override + public boolean processMessage(Message msg) { + ClientInfo clientInfo; + DnsSdServiceInfo servInfo; + boolean result = HANDLED; + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + //First client + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && + mClients.size() == 0) { + startMDnsDaemon(); + } + result = NOT_HANDLED; + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + //Last client + if (mClients.size() == 1) { + stopMDnsDaemon(); + } + result = NOT_HANDLED; + break; + case NsdManager.DISABLE: + //TODO: cleanup clients + transitionTo(mDisabledState); + break; + case NsdManager.DISCOVER_SERVICES: + if (DBG) Slog.d(TAG, "Discover services"); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId != INVALID_ID) { + //discovery already in progress + if (DBG) Slog.d(TAG, "discovery in progress"); + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + clientInfo.mDiscoveryId = getUniqueId(); + if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.ERROR); + clientInfo.mDiscoveryId = INVALID_ID; + } + break; + case NsdManager.STOP_DISCOVERY: + if (DBG) Slog.d(TAG, "Stop service discovery"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mDiscoveryId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "discovery already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { + clientInfo.mDiscoveryId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.REGISTER_SERVICE: + if (DBG) Slog.d(TAG, "Register service"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { + if (DBG) Slog.d(TAG, "register service exceeds limit"); + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.MAX_REGS_REACHED); + } + + int id = getUniqueId(); + if (registerService(id, (DnsSdServiceInfo) msg.obj)) { + clientInfo.mRegisteredIds.add(id); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.UNREGISTER_SERVICE: + if (DBG) Slog.d(TAG, "unregister service"); + clientInfo = mClients.get(msg.replyTo); + int regId = msg.arg1; + if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && + unregisterService(regId)) { + mReplyChannel.replyToMessage(msg, + NsdManager.UNREGISTER_SERVICE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.ERROR); + } + break; + case NsdManager.UPDATE_SERVICE: + if (DBG) Slog.d(TAG, "Update service"); + //TODO: implement + mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); + break; + case NsdManager.RESOLVE_SERVICE: + if (DBG) Slog.d(TAG, "Resolve service"); + servInfo = (DnsSdServiceInfo) msg.obj; + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId != INVALID_ID) { + //first cancel existing resolve + stopResolveService(clientInfo.mResolveId); + } + + clientInfo.mResolveId = getUniqueId(); + if (!resolveService(clientInfo.mResolveId, servInfo)) { + mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.ERROR); + clientInfo.mResolveId = INVALID_ID; + } + break; + case NsdManager.STOP_RESOLVE: + if (DBG) Slog.d(TAG, "Stop resolve"); + clientInfo = mClients.get(msg.replyTo); + if (clientInfo.mResolveId == INVALID_ID) { + //already stopped + if (DBG) Slog.d(TAG, "resolve already stopped"); + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ALREADY_ACTIVE); + break; + } + if (stopResolveService(clientInfo.mResolveId)) { + clientInfo.mResolveId = INVALID_ID; + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); + } else { + mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, + NsdManager.ERROR); + } + break; + default: + result = NOT_HANDLED; + break; + } + return result; + } + } + } private NativeDaemonConnector mNativeConnector; private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); private NsdService(Context context) { mContext = context; - - HandlerThread nsdThread = new HandlerThread("NsdService"); - nsdThread.start(); - mAsyncServiceHandler = new AsyncServiceHandler(nsdThread.getLooper()); + mContentResolver = context.getContentResolver(); mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, MDNS_TAG, 25); + + mNsdStateMachine = new NsdStateMachine(TAG); + mNsdStateMachine.start(); + Thread th = new Thread(mNativeConnector, MDNS_TAG); th.start(); } public static NsdService create(Context context) throws InterruptedException { NsdService service = new NsdService(context); - /* service.mNativeDaemonConnected.await(); */ + service.mNativeDaemonConnected.await(); return service; } public Messenger getMessenger() { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); - return new Messenger(mAsyncServiceHandler); + return new Messenger(mNsdStateMachine.getHandler()); + } + + public void setEnabled(boolean enable) { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL, + "NsdService"); + Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0); + if (enable) { + mNsdStateMachine.sendMessage(NsdManager.ENABLE); + } else { + mNsdStateMachine.sendMessage(NsdManager.DISABLE); + } + } + + private void sendNsdStateChangeBroadcast(boolean enabled) { + final Intent intent = new Intent(NsdManager.NSD_STATE_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + if (enabled) { + intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED); + } else { + intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED); + } + mContext.sendStickyBroadcast(intent); + } + + private boolean isNsdEnabled() { + boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1; + if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret); + return ret; } private int getUniqueId() { @@ -522,7 +683,7 @@ public class NsdService extends INsdManager.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid=" @@ -531,7 +692,12 @@ public class NsdService extends INsdManager.Stub { return; } - pw.println("Internal state:"); + for (ClientInfo client : mClients.values()) { + pw.println("Client Info"); + pw.println(client); + } + + mNsdStateMachine.dump(fd, pw, args); } private ClientInfo getClientByDiscovery(int discoveryId) { @@ -579,5 +745,19 @@ public class NsdService extends INsdManager.Stub { mDiscoveryId = mResolveId = INVALID_ID; if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("mChannel ").append(mChannel).append("\n"); + sb.append("mMessenger ").append(mMessenger).append("\n"); + sb.append("mDiscoveryId ").append(mDiscoveryId).append("\n"); + sb.append("mResolveId ").append(mResolveId).append("\n"); + sb.append("mResolvedService ").append(mResolvedService).append("\n"); + for(int regId : mRegisteredIds) { + sb.append("regId ").append(regId).append("\n"); + } + return sb.toString(); + } } } From fb97ffe16269f410bf27c79c5dc7af0ac2f60c5b Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Tue, 17 Apr 2012 23:23:42 -0700 Subject: [PATCH 0142/1150] Add network service discovery broadcast Allows apps to know if user has the feature turned off Change-Id: I2d2fecb148eb4e48eb4aea51d1d7643a82df5c52 --- core/java/android/net/nsd/NsdManager.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 62c141d558..ecf5e20991 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -141,10 +141,9 @@ public class NsdManager { * information as int. * * @see #EXTRA_NSD_STATE - * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String NSD_STATE_CHANGED_ACTION = + public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED"; /** @@ -153,7 +152,6 @@ public class NsdManager { * * @see #NSD_STATE_DISABLED * @see #NSD_STATE_ENABLED - * @hide */ public static final String EXTRA_NSD_STATE = "nsd_state"; @@ -161,7 +159,6 @@ public class NsdManager { * Network service discovery is disabled * * @see #NSD_STATE_CHANGED_ACTION - * @hide */ public static final int NSD_STATE_DISABLED = 1; @@ -169,7 +166,6 @@ public class NsdManager { * Network service discovery is enabled * * @see #NSD_STATE_CHANGED_ACTION - * @hide */ public static final int NSD_STATE_ENABLED = 2; From 52fc83a79a434691dad38c628224432bece9e615 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 19 Apr 2012 10:26:34 -0700 Subject: [PATCH 0143/1150] Fix build Change-Id: I1968e0d7d25f613fa6cf72f82d79f17224e3d5ab --- core/java/android/net/nsd/NsdManager.java | 4 ++-- services/java/com/android/server/NsdService.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index ecf5e20991..77e97e1063 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -158,14 +158,14 @@ public class NsdManager { /** * Network service discovery is disabled * - * @see #NSD_STATE_CHANGED_ACTION + * @see #ACTION_NSD_STATE_CHANGED */ public static final int NSD_STATE_DISABLED = 1; /** * Network service discovery is enabled * - * @see #NSD_STATE_CHANGED_ACTION + * @see #ACTION_NSD_STATE_CHANGED */ public static final int NSD_STATE_ENABLED = 2; diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 839fbe279d..f33bf8b24e 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -399,7 +399,7 @@ public class NsdService extends INsdManager.Stub { } private void sendNsdStateChangeBroadcast(boolean enabled) { - final Intent intent = new Intent(NsdManager.NSD_STATE_CHANGED_ACTION); + final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); if (enabled) { intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED); From 2a9efc2c6ecaff887417639226d83c48ad49f790 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 20 Apr 2012 13:08:02 -0700 Subject: [PATCH 0144/1150] Allow quoted strings from NativeDaemonConnector Previously we'd only handled quoted strings going into NDC. This change auto-handles quoted strings in broadcasts and allows protocol handlers to request de-quoted elements when needed instead of using the generic split(" "). bug: 6353048 Change-Id: I8a07be86411063ed1b402294edc399b4cc076da5 --- .../android/server/NativeDaemonConnector.java | 2 +- .../com/android/server/NativeDaemonEvent.java | 85 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 0b5eaffe7f..6a6c585fe7 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -94,7 +94,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public boolean handleMessage(Message msg) { String event = (String) msg.obj; try { - if (!mCallbacks.onEvent(msg.what, event, event.split(" "))) { + if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { log(String.format("Unhandled event '%s'", event)); } } catch (Exception e) { diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index d5e9f66027..f11ae1d391 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -16,6 +16,7 @@ package com.android.server; +import android.util.Slog; import com.google.android.collect.Lists; import java.util.ArrayList; @@ -32,12 +33,14 @@ public class NativeDaemonEvent { private final int mCode; private final String mMessage; private final String mRawEvent; + private String[] mParsed; private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; + mParsed = null; } public int getCmdNumber() { @@ -166,4 +169,86 @@ public class NativeDaemonEvent { } return result.toArray(new String[result.size()]); } + + /** + * Find the Nth field of the event. + * + * This ignores and code or cmdNum, the first return value is given for N=0. + * Also understands "\"quoted\" multiword responses" and tries them as a single field + */ + public String getField(int n) { + if (mParsed == null) { + mParsed = unescapeArgs(mRawEvent); + } + n += 2; // skip code and command# + if (n > mParsed.length) return null; + return mParsed[n]; + } + + public static String[] unescapeArgs(String rawEvent) { + final boolean DEBUG_ROUTINE = false; + final String LOGTAG = "unescapeArgs"; + final ArrayList parsed = new ArrayList(); + final int length = rawEvent.length(); + int current = 0; + int wordEnd = -1; + boolean quoted = false; + + if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'"); + if (rawEvent.charAt(current) == '\"') { + quoted = true; + current++; + } + while (current < length) { + // find the end of the word + if (quoted) { + wordEnd = current; + while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) { + if (rawEvent.charAt(wordEnd - 1) != '\\') { + break; + } else { + wordEnd++; // skip this escaped quote and keep looking + } + } + } else { + wordEnd = rawEvent.indexOf(' ', current); + } + // if we didn't find the end-o-word token, take the rest of the string + if (wordEnd == -1) wordEnd = length; + String word = rawEvent.substring(current, wordEnd); + current += word.length(); + if (!quoted) { + word = word.trim(); + } else { + current++; // skip the trailing quote + } + // unescape stuff within the word + word.replace("\\\\", "\\"); + word.replace("\\\"", "\""); + + if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'"); + parsed.add(word); + + // find the beginning of the next word - either of these options + int nextSpace = rawEvent.indexOf(' ', current); + int nextQuote = rawEvent.indexOf(" \"", current); + if (DEBUG_ROUTINE) { + Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote); + } + if (nextQuote > -1 && nextQuote <= nextSpace) { + quoted = true; + current = nextQuote + 2; + } else { + quoted = false; + if (nextSpace > -1) { + current = nextSpace + 1; + } + } // else we just start the next word after the current and read til the end + if (DEBUG_ROUTINE) { + Slog.e(LOGTAG, "next loop - current=" + current + + ", length=" + length + ", quoted=" + quoted); + } + } + return parsed.toArray(new String[parsed.size()]); + } } From 32c773b16aca2dea55889aab8af8fa0088c2eefb Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 21 Apr 2012 15:36:48 -0700 Subject: [PATCH 0145/1150] Better assertions when bandwidth module disabled. Also disable some verbose logging in WifiStateTracker. Bug: 6368329 Change-Id: I9a5219bc1b3fd870468f7de46cdf4f173a437c59 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 2a67e02db2..f53e9570d7 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -420,6 +420,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + assertBandwidthControlEnabled(); // return an IBinder which holds strong references to any loaded stats // for its lifetime; when caller closes only weak references remain. @@ -486,6 +487,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + assertBandwidthControlEnabled(); return mDevStatsCached.getSummary(template, start, end).getTotalBytes(); } @@ -494,6 +496,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (Binder.getCallingUid() != uid) { mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); } + assertBandwidthControlEnabled(); // TODO: switch to data layer stats once kernel exports // for now, read network layer stats and flatten across all ifaces @@ -565,6 +568,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { @@ -1039,6 +1043,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + private void assertBandwidthControlEnabled() { + if (!isBandwidthControlEnabled()) { + throw new IllegalStateException("Bandwidth module disabled"); + } + } + private boolean isBandwidthControlEnabled() { try { return mNetworkManager.isBandwidthControlEnabled(); From f6d43ea959a5c4543413ef2ab1d9c4a9939431b4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 23 Apr 2012 14:39:19 -0700 Subject: [PATCH 0146/1150] Clear identity when checking if bandwidth enabled. Change-Id: I0f10f86dc14483e29609057c671454b322da4826 --- services/java/com/android/server/net/NetworkStatsService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f53e9570d7..1c3e24f7e5 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1050,11 +1050,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private boolean isBandwidthControlEnabled() { + final long token = Binder.clearCallingIdentity(); try { return mNetworkManager.isBandwidthControlEnabled(); } catch (RemoteException e) { // ignored; service lives in system_server return false; + } finally { + Binder.restoreCallingIdentity(token); } } From cfed18ad5bdd803fa1a26ada71837f75aa30901d Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 1 May 2012 16:26:09 -0700 Subject: [PATCH 0147/1150] Begin collecting xtables iface counters. Add method to parse new iface_stat_fmt proc stats, or return null when kernel support is unavailable. Add test and remove older, unused parsing code. Create new "xt" recorder to persist the new xtables counters when available. Add SSID support to NetworkIdentity to fix policy tests. Bug: 6422414 Change-Id: I77f70e9acb79a559ab626f3af5c4f3599801ed43 --- core/java/android/net/NetworkIdentity.java | 11 +- .../internal/net/NetworkStatsFactory.java | 163 ++++-------------- .../server/net/NetworkStatsRecorder.java | 3 + .../server/net/NetworkStatsService.java | 34 +++- 4 files changed, 70 insertions(+), 141 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 4ac5e76472..3c67bf9e84 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -158,9 +158,14 @@ public class NetworkIdentity { } } else if (type == TYPE_WIFI) { - final WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); - final WifiInfo info = wifi.getConnectionInfo(); - networkId = info != null ? info.getSSID() : null; + if (state.networkId != null) { + networkId = state.networkId; + } else { + final WifiManager wifi = (WifiManager) context.getSystemService( + Context.WIFI_SERVICE); + final WifiInfo info = wifi.getConnectionInfo(); + networkId = info != null ? info.getSSID() : null; + } } return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index d59585f2fe..8b222f02a3 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -24,20 +24,12 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; -import android.util.Slog; import com.android.internal.util.ProcFileReader; -import com.google.android.collect.Lists; -import com.google.android.collect.Sets; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.StringTokenizer; import libcore.io.IoUtils; @@ -50,14 +42,10 @@ public class NetworkStatsFactory { // TODO: consider moving parsing to native code - /** Path to {@code /proc/net/dev}. */ - @Deprecated - private final File mStatsIface; - /** Path to {@code /proc/net/xt_qtaguid/iface_stat}. */ - @Deprecated - private final File mStatsXtIface; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; + /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ + private final File mStatsXtIfaceFmt; /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; @@ -67,28 +55,20 @@ public class NetworkStatsFactory { // @VisibleForTesting public NetworkStatsFactory(File procRoot) { - mStatsIface = new File(procRoot, "net/dev"); - mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); - mStatsXtIface = new File(procRoot, "net/xt_qtaguid/iface_stat"); mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); + mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); + mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); } /** - * Parse and return interface-level summary {@link NetworkStats}. Values - * monotonically increase since device boot, and may include details about - * inactive interfaces. + * Parse and return interface-level summary {@link NetworkStats} measured + * using {@code /proc/net/dev} style hooks, which may include non IP layer + * traffic. Values monotonically increase since device boot, and may include + * details about inactive interfaces. * * @throws IllegalStateException when problem parsing stats. */ - public NetworkStats readNetworkStatsSummary() throws IllegalStateException { - if (mStatsXtIfaceAll.exists()) { - return readNetworkStatsSummarySingleFile(); - } else { - return readNetworkStatsSummaryMultipleFiles(); - } - } - - private NetworkStats readNetworkStatsSummarySingleFile() { + public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); @@ -137,79 +117,40 @@ public class NetworkStatsFactory { } /** - * @deprecated remove once {@code iface_stat_all} is merged to all kernels. + * Parse and return interface-level summary {@link NetworkStats}. Designed + * to return only IP layer traffic. Values monotonically increase since + * device boot, and may include details about inactive interfaces. + * + * @throws IllegalStateException when problem parsing stats. */ - @Deprecated - private NetworkStats readNetworkStatsSummaryMultipleFiles() { + public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); + // return null when kernel doesn't support + if (!mStatsXtIfaceFmt.exists()) return null; + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); final NetworkStats.Entry entry = new NetworkStats.Entry(); - final HashSet knownIfaces = Sets.newHashSet(); - final HashSet activeIfaces = Sets.newHashSet(); - - // collect any historical stats and active state - for (String iface : fileListWithoutNull(mStatsXtIface)) { - final File ifacePath = new File(mStatsXtIface, iface); - - final long active = readSingleLongFromFile(new File(ifacePath, "active")); - if (active == 1) { - knownIfaces.add(iface); - activeIfaces.add(iface); - } else if (active == 0) { - knownIfaces.add(iface); - } else { - continue; - } - - entry.iface = iface; - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.rxBytes = readSingleLongFromFile(new File(ifacePath, "rx_bytes")); - entry.rxPackets = readSingleLongFromFile(new File(ifacePath, "rx_packets")); - entry.txBytes = readSingleLongFromFile(new File(ifacePath, "tx_bytes")); - entry.txPackets = readSingleLongFromFile(new File(ifacePath, "tx_packets")); - - stats.addValues(entry); - } - - final ArrayList values = Lists.newArrayList(); - - BufferedReader reader = null; + ProcFileReader reader = null; try { - reader = new BufferedReader(new FileReader(mStatsIface)); + // open and consume header line + reader = new ProcFileReader(new FileInputStream(mStatsXtIfaceFmt)); + reader.finishLine(); - // skip first two header lines - reader.readLine(); - reader.readLine(); + while (reader.hasMoreData()) { + entry.iface = reader.nextString(); + entry.uid = UID_ALL; + entry.set = SET_ALL; + entry.tag = TAG_NONE; - // parse remaining lines - String line; - while ((line = reader.readLine()) != null) { - splitLine(line, values); + entry.rxBytes = reader.nextLong(); + entry.rxPackets = reader.nextLong(); + entry.txBytes = reader.nextLong(); + entry.txPackets = reader.nextLong(); - try { - entry.iface = values.get(0); - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.rxBytes = Long.parseLong(values.get(1)); - entry.rxPackets = Long.parseLong(values.get(2)); - entry.txBytes = Long.parseLong(values.get(9)); - entry.txPackets = Long.parseLong(values.get(10)); - - if (activeIfaces.contains(entry.iface)) { - // combine stats when iface is active - stats.combineValues(entry); - } else if (!knownIfaces.contains(entry.iface)) { - // add stats when iface is unknown - stats.addValues(entry); - } - } catch (NumberFormatException e) { - Slog.w(TAG, "problem parsing stats row '" + line + "': " + e); - } + stats.addValues(entry); + reader.finishLine(); } } catch (NullPointerException e) { throw new IllegalStateException("problem parsing stats: " + e); @@ -221,7 +162,6 @@ public class NetworkStatsFactory { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); } - return stats; } @@ -286,41 +226,4 @@ public class NetworkStatsFactory { return stats; } - - /** - * Split given line into {@link ArrayList}. - */ - @Deprecated - private static void splitLine(String line, ArrayList outSplit) { - outSplit.clear(); - - final StringTokenizer t = new StringTokenizer(line, " \t\n\r\f:"); - while (t.hasMoreTokens()) { - outSplit.add(t.nextToken()); - } - } - - /** - * Utility method to read a single plain-text {@link Long} from the given - * {@link File}, usually from a {@code /proc/} filesystem. - */ - private static long readSingleLongFromFile(File file) { - try { - final byte[] buffer = IoUtils.readFileAsByteArray(file.toString()); - return Long.parseLong(new String(buffer).trim()); - } catch (NumberFormatException e) { - return -1; - } catch (IOException e) { - return -1; - } - } - - /** - * Wrapper for {@link File#list()} that returns empty array instead of - * {@code null}. - */ - private static String[] fileListWithoutNull(File file) { - final String[] list = file.list(); - return list != null ? list : new String[0]; - } } diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 57ad158bf2..743a746683 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -128,6 +128,9 @@ public class NetworkStatsRecorder { Map ifaceIdent, long currentTimeMillis) { final HashSet unknownIfaces = Sets.newHashSet(); + // skip recording when snapshot missing + if (snapshot == null) return; + // assume first snapshot is bootstrap and don't record if (mLastSnapshot == null) { mLastSnapshot = snapshot; diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 1c3e24f7e5..6d6f59cf0f 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -159,6 +159,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; private static final String PREFIX_DEV = "dev"; + private static final String PREFIX_XT = "xt"; private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; @@ -187,6 +188,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public Config getDevConfig(); + public Config getXtConfig(); public Config getUidConfig(); public Config getUidTagConfig(); } @@ -204,6 +206,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DropBoxNonMonotonicObserver(); private NetworkStatsRecorder mDevRecorder; + private NetworkStatsRecorder mXtRecorder; private NetworkStatsRecorder mUidRecorder; private NetworkStatsRecorder mUidTagRecorder; @@ -268,6 +271,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // create data recorders along with historical rotators mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); + mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); @@ -343,10 +347,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist any pending stats mDevRecorder.forcePersistLocked(currentTime); + mXtRecorder.forcePersistLocked(currentTime); mUidRecorder.forcePersistLocked(currentTime); mUidTagRecorder.forcePersistLocked(currentTime); mDevRecorder = null; + mXtRecorder = null; mUidRecorder = null; mUidTagRecorder = null; @@ -772,9 +778,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // snapshot and record current counters; read UID stats first to // avoid overcounting dev stats. final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats devSnapshot = getNetworkStatsSummary(); + final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); + mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); @@ -824,9 +832,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // snapshot and record current counters; read UID stats first to // avoid overcounting dev stats. final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats devSnapshot = getNetworkStatsSummary(); + final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); + mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); @@ -841,11 +851,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist any pending data depending on requested flags if (persistForce) { mDevRecorder.forcePersistLocked(currentTime); + mXtRecorder.forcePersistLocked(currentTime); mUidRecorder.forcePersistLocked(currentTime); mUidTagRecorder.forcePersistLocked(currentTime); } else { if (persistNetwork) { mDevRecorder.maybePersistLocked(currentTime); + mXtRecorder.maybePersistLocked(currentTime); } if (persistUid) { mUidRecorder.maybePersistLocked(currentTime); @@ -884,7 +896,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // collect mobile sample template = buildTemplateMobileWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = new NetworkStats.Entry(); + xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); EventLogTags.writeNetstatsMobileSample( @@ -896,7 +908,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // collect wifi sample template = buildTemplateWifiWildcard(); devTotal = mDevRecorder.getTotalSinceBootLocked(template); - xtTotal = new NetworkStats.Entry(); + xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); EventLogTags.writeNetstatsWifiSample( @@ -970,6 +982,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDevRecorder.dumpLocked(pw, fullHistory); pw.decreaseIndent(); + pw.println("Xt stats:"); + pw.increaseIndent(); + mXtRecorder.dumpLocked(pw, fullHistory); + pw.decreaseIndent(); + if (includeUid) { pw.println("UID stats:"); pw.increaseIndent(); @@ -986,10 +1003,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private NetworkStats getNetworkStatsSummary() throws RemoteException { - return mNetworkManager.getNetworkStatsSummary(); - } - /** * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. @@ -1125,6 +1138,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); } + @Override + public Config getXtConfig() { + return getDevConfig(); + } + @Override public Config getUidConfig() { return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), From c78bc600399fa14f1024612c31f8858c2007c848 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 2 May 2012 18:11:52 -0700 Subject: [PATCH 0148/1150] Reduce persist threshold for lower warning/limit. Default is 2MB persist threshold, but even that can be substantial for devices on 100MB/month plans. This change gradually reduces the persist threshold up to 8x lower (256kb outstanding) based on lowest active policy. Bug: 5382676 Change-Id: Ief4e8cdb169bfb151a3d1b45722a8eaa01926508 --- .../android/net/INetworkStatsService.aidl | 2 + .../server/net/NetworkStatsCollection.java | 10 +- .../server/net/NetworkStatsRecorder.java | 16 ++- .../server/net/NetworkStatsService.java | 113 ++++++++++++++---- 4 files changed, 107 insertions(+), 34 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 08d4c6cbf4..b7b8731855 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,5 +42,7 @@ interface INetworkStatsService { void setUidForeground(int uid, boolean uidForeground); /** Force update of statistics. */ void forceUpdate(); + /** Advise persistance threshold; may be overridden internally. */ + void advisePersistThreshold(long thresholdBytes); } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 2892a74845..c2e475a5b4 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -186,12 +186,12 @@ public class NetworkStatsCollection implements FileRotator.Reader { if (history.size() == 0) return; noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); - final NetworkStatsHistory existing = mStats.get(key); - if (existing != null) { - existing.recordEntireHistory(history); - } else { - mStats.put(key, history); + NetworkStatsHistory target = mStats.get(key); + if (target == null) { + target = new NetworkStatsHistory(history.getBucketDuration()); + mStats.put(key, target); } + target.recordEntireHistory(history); } /** diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 743a746683..2ce7771135 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.TAG_NONE; +import static android.net.TrafficStats.KB_IN_BYTES; +import static android.net.TrafficStats.MB_IN_BYTES; import static com.android.internal.util.Preconditions.checkNotNull; import android.net.NetworkStats; @@ -25,6 +27,7 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.util.Log; +import android.util.MathUtils; import android.util.Slog; import com.android.internal.util.FileRotator; @@ -58,9 +61,9 @@ public class NetworkStatsRecorder { private final String mCookie; private final long mBucketDuration; - private final long mPersistThresholdBytes; private final boolean mOnlyTags; + private long mPersistThresholdBytes = 2 * MB_IN_BYTES; private NetworkStats mLastSnapshot; private final NetworkStatsCollection mPending; @@ -71,13 +74,12 @@ public class NetworkStatsRecorder { private WeakReference mComplete; public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, - String cookie, long bucketDuration, long persistThresholdBytes, boolean onlyTags) { + String cookie, long bucketDuration, boolean onlyTags) { mRotator = checkNotNull(rotator, "missing FileRotator"); mObserver = checkNotNull(observer, "missing NonMonotonicObserver"); mCookie = cookie; mBucketDuration = bucketDuration; - mPersistThresholdBytes = persistThresholdBytes; mOnlyTags = onlyTags; mPending = new NetworkStatsCollection(bucketDuration); @@ -86,6 +88,12 @@ public class NetworkStatsRecorder { mPendingRewriter = new CombiningRewriter(mPending); } + public void setPersistThreshold(long thresholdBytes) { + if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes); + mPersistThresholdBytes = MathUtils.constrain( + thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES); + } + public void resetLocked() { mLastSnapshot = null; mPending.reset(); @@ -153,7 +161,7 @@ public class NetworkStatsRecorder { continue; } - // skip when no delta occured + // skip when no delta occurred if (entry.isEmpty()) continue; // only record tag data when requested diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 6d6f59cf0f..a9d4b59622 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -36,6 +36,7 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; +import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; @@ -49,6 +50,10 @@ import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE; import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES; import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE; +import static android.provider.Settings.Secure.NETSTATS_UID_TAG_BUCKET_DURATION; +import static android.provider.Settings.Secure.NETSTATS_UID_TAG_DELETE_AGE; +import static android.provider.Settings.Secure.NETSTATS_UID_TAG_PERSIST_BYTES; +import static android.provider.Settings.Secure.NETSTATS_UID_TAG_ROTATE_AGE; import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; @@ -94,10 +99,12 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; import android.provider.Settings; +import android.provider.Settings.Secure; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.EventLog; import android.util.Log; +import android.util.MathUtils; import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; @@ -169,19 +176,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public interface NetworkStatsSettings { public long getPollInterval(); public long getTimeCacheMaxAge(); - public long getGlobalAlertBytes(); public boolean getSampleEnabled(); public static class Config { public final long bucketDuration; - public final long persistBytes; public final long rotateAgeMillis; public final long deleteAgeMillis; - public Config(long bucketDuration, long persistBytes, long rotateAgeMillis, - long deleteAgeMillis) { + public Config(long bucketDuration, long rotateAgeMillis, long deleteAgeMillis) { this.bucketDuration = bucketDuration; - this.persistBytes = persistBytes; this.rotateAgeMillis = rotateAgeMillis; this.deleteAgeMillis = deleteAgeMillis; } @@ -191,6 +194,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public Config getXtConfig(); public Config getUidConfig(); public Config getUidTagConfig(); + + public long getGlobalAlertBytes(long def); + public long getDevPersistBytes(long def); + public long getXtPersistBytes(long def); + public long getUidPersistBytes(long def); + public long getUidTagPersistBytes(long def); } private final Object mStatsLock = new Object(); @@ -223,6 +232,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Handler mHandler; private boolean mSystemReady; + private long mPersistThreshold = 2 * MB_IN_BYTES; + private long mGlobalAlertBytes; public NetworkStatsService( Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { @@ -275,6 +286,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); + updatePersistThresholds(); + synchronized (mStatsLock) { // upgrade any legacy stats, migrating them to rotated files maybeUpgradeLegacyStatsLocked(); @@ -325,10 +338,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsRecorder buildRecorder( String prefix, NetworkStatsSettings.Config config, boolean includeTags) { - return new NetworkStatsRecorder( - new FileRotator(mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - mNonMonotonicObserver, prefix, config.bucketDuration, config.persistBytes, - includeTags); + return new NetworkStatsRecorder(new FileRotator( + mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), + mNonMonotonicObserver, prefix, config.bucketDuration, includeTags); } private void shutdownLocked() { @@ -414,8 +426,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private void registerGlobalAlert() { try { - final long alertBytes = mSettings.getGlobalAlertBytes(); - mNetworkManager.setGlobalAlert(alertBytes); + mNetworkManager.setGlobalAlert(mGlobalAlertBytes); } catch (IllegalStateException e) { Slog.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { @@ -437,14 +448,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsCollection getUidComplete() { if (mUidComplete == null) { - mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); + synchronized (mStatsLock) { + mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); + } } return mUidComplete; } private NetworkStatsCollection getUidTagComplete() { if (mUidTagComplete == null) { - mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); + synchronized (mStatsLock) { + mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); + } } return mUidTagComplete; } @@ -584,6 +599,45 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public void advisePersistThreshold(long thresholdBytes) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + assertBandwidthControlEnabled(); + + // clamp threshold into safe range + mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); + updatePersistThresholds(); + + if (LOGV) { + Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " + + mPersistThreshold); + } + + // persist if beyond new thresholds + final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() + : System.currentTimeMillis(); + mDevRecorder.maybePersistLocked(currentTime); + mXtRecorder.maybePersistLocked(currentTime); + mUidRecorder.maybePersistLocked(currentTime); + mUidTagRecorder.maybePersistLocked(currentTime); + + // re-arm global alert + registerGlobalAlert(); + } + + /** + * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to + * reflect current {@link #mPersistThreshold} value. Always defers to + * {@link Secure} values when defined. + */ + private void updatePersistThresholds() { + mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); + mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); + mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); + mUidTagRecorder.setPersistThreshold(mSettings.getUidTagPersistBytes(mPersistThreshold)); + mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} @@ -1122,41 +1176,50 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); } @Override - public long getGlobalAlertBytes() { - return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, 2 * MB_IN_BYTES); + public long getGlobalAlertBytes(long def) { + return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } @Override public boolean getSampleEnabled() { return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true); } - @Override public Config getDevConfig() { return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), - getSecureLong(NETSTATS_DEV_PERSIST_BYTES, 2 * MB_IN_BYTES), getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); } - @Override public Config getXtConfig() { return getDevConfig(); } - @Override public Config getUidConfig() { return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS), getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); } - @Override public Config getUidTagConfig() { - return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getSecureLong(NETSTATS_UID_PERSIST_BYTES, 2 * MB_IN_BYTES), - getSecureLong(NETSTATS_UID_ROTATE_AGE, 5 * DAY_IN_MILLIS), - getSecureLong(NETSTATS_UID_DELETE_AGE, 15 * DAY_IN_MILLIS)); + return new Config(getSecureLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), + getSecureLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS), + getSecureLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS)); + } + @Override + public long getDevPersistBytes(long def) { + return getSecureLong(NETSTATS_DEV_PERSIST_BYTES, def); + } + @Override + public long getXtPersistBytes(long def) { + return getDevPersistBytes(def); + } + @Override + public long getUidPersistBytes(long def) { + return getSecureLong(NETSTATS_UID_PERSIST_BYTES, def); + } + @Override + public long getUidTagPersistBytes(long def) { + return getSecureLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); } } } From 24a69bbd60851ca4b45cb1b07764e8cd58c51f93 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 7 May 2012 11:08:49 -0700 Subject: [PATCH 0149/1150] Ack, wrap advisePersistThreshold() in lock. Bug: 6449725 Change-Id: I702dc2ff9d4b237c46d89bcae41289bc3e9ef2f8 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index a9d4b59622..1a56b80d7e 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -616,10 +616,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // persist if beyond new thresholds final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); - mDevRecorder.maybePersistLocked(currentTime); - mXtRecorder.maybePersistLocked(currentTime); - mUidRecorder.maybePersistLocked(currentTime); - mUidTagRecorder.maybePersistLocked(currentTime); + synchronized (mStatsLock) { + mDevRecorder.maybePersistLocked(currentTime); + mXtRecorder.maybePersistLocked(currentTime); + mUidRecorder.maybePersistLocked(currentTime); + mUidTagRecorder.maybePersistLocked(currentTime); + } // re-arm global alert registerGlobalAlert(); From e4c42f40267dcbd253c1ccc199960d4f172060f3 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 3 May 2012 16:44:27 -0700 Subject: [PATCH 0150/1150] API review fixes - Remove the notion of channel from an application perspective - Remove the use of DnsSd as part of API and add a protocol type to allow future extensions - Use the listener object as a handler for stop and unregister operations. Also, we now allow multiple active discovery operations. - Remove init/deinit operations in favour of setting up construction Bug:6434844 Change-Id: Id15521d571aac9c4053d81184ad66dfc54f636de --- core/java/android/net/nsd/NsdManager.java | 683 ++++++++---------- ...SdServiceInfo.java => NsdServiceInfo.java} | 22 +- .../java/com/android/server/NsdService.java | 497 +++++++------ 3 files changed, 591 insertions(+), 611 deletions(-) rename core/java/android/net/nsd/{DnsSdServiceInfo.java => NsdServiceInfo.java} (86%) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 77e97e1063..08ba728f65 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -22,12 +22,16 @@ import android.content.Context; import android.os.Binder; import android.os.IBinder; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.Messenger; import android.text.TextUtils; import android.util.Log; +import android.util.SparseArray; + +import java.util.concurrent.CountDownLatch; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -39,88 +43,73 @@ import com.android.internal.util.Protocol; * B. Another example use case is an application discovering printers on the network. * *

The API currently supports DNS based service discovery and discovery is currently - * limited to a local network over Multicast DNS. In future, it will be extended to - * support wide area discovery and other service discovery mechanisms. - * DNS service discovery is described at http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt + * limited to a local network over Multicast DNS. DNS service discovery is described at + * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * *

The API is asynchronous and responses to requests from an application are on listener - * callbacks provided by the application. The application must invoke {@link #initialize} before - * doing any other operation. + * callbacks on a seperate thread. * *

There are three main operations the API supports - registration, discovery and resolution. *

  *                          Application start
  *                                 |
- *                                 |         <----------------------------------------------
- *                             initialize()                                                 |
- *                                 |                                                        |
- *                                 | Wait until channel connects                            |
- *                                 | before doing any operation                             |
- *                                 |                                                        |
- *                           onChannelConnected()                    __________             |
- *                                 |                                           |            |
- *                                 |                                           |            |
- *                                 |                  onServiceRegistered()    |            |
- *                     Register any local services  /                          |            |
- *                      to be advertised with       \                          |            | If application needs to
- *                       registerService()            onFailure()              |            | do any further operations
- *                                 |                                           |            | again, it needs to
- *                                 |                                           |            | initialize() connection
- *                          discoverServices()                                 |            | to framework again
- *                                 |                                           |            |
- *                      Maintain a list to track                               |            |
- *                        discovered services                                  |            |
- *                                 |                                           |            |
- *                                 |--------->                                 |-> onChannelDisconnected()
- *                                 |          |                                |
- *                                 |      onServiceFound()                     |
- *                                 |          |                                |
- *                                 |     add service to list                   |
- *                                 |          |                                |
- *                                 |<----------                                |
- *                                 |                                           |
- *                                 |--------->                                 |
- *                                 |          |                                |
- *                                 |      onServiceLost()                      |
- *                                 |          |                                |
- *                                 |   remove service from list                |
- *                                 |          |                                |
- *                                 |<----------                                |
- *                                 |                                           |
- *                                 |                                           |
- *                                 | Connect to a service                      |
- *                                 | from list ?                               |
- *                                 |                                           |
- *                          resolveService()                                   |
- *                                 |                                           |
- *                         onServiceResolved()                                 |
- *                                 |                                           |
- *                     Establish connection to service                         |
- *                     with the host and port information                      |
- *                                 |                                           |
- *                                 |                                ___________|
- *                           deinitialize()
- *                    when done with all operations
- *                          or before quit
+ *                                 |
+ *                                 |                  onServiceRegistered()
+ *                     Register any local services  /
+ *                      to be advertised with       \
+ *                       registerService()            onRegistrationFailed()
+ *                                 |
+ *                                 |
+ *                          discoverServices()
+ *                                 |
+ *                      Maintain a list to track
+ *                        discovered services
+ *                                 |
+ *                                 |--------->
+ *                                 |          |
+ *                                 |      onServiceFound()
+ *                                 |          |
+ *                                 |     add service to list
+ *                                 |          |
+ *                                 |<----------
+ *                                 |
+ *                                 |--------->
+ *                                 |          |
+ *                                 |      onServiceLost()
+ *                                 |          |
+ *                                 |   remove service from list
+ *                                 |          |
+ *                                 |<----------
+ *                                 |
+ *                                 |
+ *                                 | Connect to a service
+ *                                 | from list ?
+ *                                 |
+ *                          resolveService()
+ *                                 |
+ *                         onServiceResolved()
+ *                                 |
+ *                     Establish connection to service
+ *                     with the host and port information
  *
  * 
* An application that needs to advertise itself over a network for other applications to * discover it can do so with a call to {@link #registerService}. If Example is a http based * application that can provide HTML data to peer services, it can register a name "Example" * with service type "_http._tcp". A successful registration is notified with a callback to - * {@link DnsSdRegisterListener#onServiceRegistered} and a failure to register is notified - * over {@link DnsSdRegisterListener#onFailure} + * {@link RegistrationListener#onServiceRegistered} and a failure to register is notified + * over {@link RegistrationListener#onRegistrationFailed} * *

A peer application looking for http services can initiate a discovery for "_http._tcp" * with a call to {@link #discoverServices}. A service found is notified with a callback - * to {@link DnsSdDiscoveryListener#onServiceFound} and a service lost is notified on - * {@link DnsSdDiscoveryListener#onServiceLost}. + * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on + * {@link DiscoveryListener#onServiceLost}. * *

Once the peer application discovers the "Example" http srevice, and needs to receive data * from the "Example" application, it can initiate a resolve with {@link #resolveService} to * resolve the host and port details for the purpose of establishing a connection. A successful - * resolve is notified on {@link DnsSdResolveListener#onServiceResolved} and a failure is notified - * on {@link DnsSdResolveListener#onFailure}. + * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified + * on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at @@ -129,9 +118,9 @@ import com.android.internal.util.Protocol; * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) * Context.getSystemService(Context.NSD_SERVICE)}. * - * {@see DnsSdServiceInfo} + * {@see NsdServiceInfo} */ -public class NsdManager { +public final class NsdManager { private static final String TAG = "NsdManager"; INsdManager mService; @@ -203,13 +192,6 @@ public class NsdManager { /** @hide */ public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14; - /** @hide */ - public static final int UPDATE_SERVICE = BASE + 15; - /** @hide */ - public static final int UPDATE_SERVICE_FAILED = BASE + 16; - /** @hide */ - public static final int UPDATE_SERVICE_SUCCEEDED = BASE + 17; - /** @hide */ public static final int RESOLVE_SERVICE = BASE + 18; /** @hide */ @@ -217,18 +199,28 @@ public class NsdManager { /** @hide */ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; - /** @hide */ - public static final int STOP_RESOLVE = BASE + 21; - /** @hide */ - public static final int STOP_RESOLVE_FAILED = BASE + 22; - /** @hide */ - public static final int STOP_RESOLVE_SUCCEEDED = BASE + 23; - /** @hide */ public static final int ENABLE = BASE + 24; /** @hide */ public static final int DISABLE = BASE + 25; + /** @hide */ + public static final int NATIVE_DAEMON_EVENT = BASE + 26; + + /** Dns based service discovery protocol */ + public static final int PROTOCOL_DNS_SD = 0x0001; + + private Context mContext; + + private static final int INVALID_LISTENER_KEY = 0; + private int mListenerKey = 1; + private final SparseArray mListenerMap = new SparseArray(); + private final SparseArray mServiceMap = new SparseArray(); + private final Object mMapLock = new Object(); + + private final AsyncChannel mAsyncChannel = new AsyncChannel(); + private ServiceHandler mHandler; + private final CountDownLatch mConnected = new CountDownLatch(1); /** * Create a new Nsd instance. Applications use @@ -238,271 +230,213 @@ public class NsdManager { * @hide - hide this because it takes in a parameter of type INsdManager, which * is a system private class. */ - public NsdManager(INsdManager service) { + public NsdManager(Context context, INsdManager service) { mService = service; + mContext = context; + init(); } /** - * Passed with onFailure() calls. + * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, + * {@link RegistrationListener#onUnregistrationFailed}, + * {@link DiscoveryListener#onStartDiscoveryFailed}, + * {@link DiscoveryListener#onStopDiscoveryFailed} or {@link ResolveListener#onResolveFailed}. + * * Indicates that the operation failed due to an internal error. */ - public static final int ERROR = 0; + public static final int FAILURE_INTERNAL_ERROR = 0; /** - * Passed with onFailure() calls. - * Indicates that the operation failed because service discovery - * is unsupported on the device. - */ - public static final int UNSUPPORTED = 1; - - /** - * Passed with onFailure() calls. - * Indicates that the operation failed because the framework is - * busy and unable to service the request. - */ - public static final int BUSY = 2; - - /** - * Passed with onFailure() calls. * Indicates that the operation failed because it is already active. */ - public static final int ALREADY_ACTIVE = 3; + public static final int FAILURE_ALREADY_ACTIVE = 3; /** - * Passed with onFailure() calls. - * Indicates that the operation failed because maximum limit on - * service registrations has reached. + * Indicates that the operation failed because the maximum outstanding + * requests from the applications have reached. */ - public static final int MAX_REGS_REACHED = 4; - - /** Interface for callback invocation when framework channel is connected or lost */ - public interface ChannelListener { - /** - * The channel to the framework is connected. - * Application can initiate calls into the framework using the channel instance passed. - */ - public void onChannelConnected(Channel c); - /** - * The channel to the framework has been disconnected. - * Application could try re-initializing using {@link #initialize} - */ - public void onChannelDisconnected(); - } - - /** Generic interface for callback invocation for a success or failure */ - public interface ActionListener { - - public void onFailure(int errorCode); - - public void onSuccess(); - } + public static final int FAILURE_MAX_LIMIT = 4; /** Interface for callback invocation for service discovery */ - public interface DnsSdDiscoveryListener { + public interface DiscoveryListener { - public void onFailure(int errorCode); + public void onStartDiscoveryFailed(String serviceType, int errorCode); - public void onStarted(String serviceType); + public void onStopDiscoveryFailed(String serviceType, int errorCode); - public void onServiceFound(DnsSdServiceInfo serviceInfo); + public void onDiscoveryStarted(String serviceType); - public void onServiceLost(DnsSdServiceInfo serviceInfo); + public void onDiscoveryStopped(String serviceType); + + public void onServiceFound(NsdServiceInfo serviceInfo); + + public void onServiceLost(NsdServiceInfo serviceInfo); } /** Interface for callback invocation for service registration */ - public interface DnsSdRegisterListener { + public interface RegistrationListener { - public void onFailure(int errorCode); + public void onRegistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - public void onServiceRegistered(int registeredId, DnsSdServiceInfo serviceInfo); - } + public void onUnregistrationFailed(NsdServiceInfo serviceInfo, int errorCode); - /** @hide */ - public interface DnsSdUpdateRegistrationListener { + public void onServiceRegistered(NsdServiceInfo serviceInfo); - public void onFailure(int errorCode); - - public void onServiceUpdated(int registeredId, DnsSdTxtRecord txtRecord); + public void onServiceUnregistered(NsdServiceInfo serviceInfo); } /** Interface for callback invocation for service resolution */ - public interface DnsSdResolveListener { + public interface ResolveListener { - public void onFailure(int errorCode); + public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode); - public void onServiceResolved(DnsSdServiceInfo serviceInfo); + public void onServiceResolved(NsdServiceInfo serviceInfo); } - /** - * A channel that connects the application to the NetworkService framework. - * Most service operations require a Channel as an argument. An instance of Channel is obtained - * by doing a call on {@link #initialize} - */ - public static class Channel { - Channel(Looper looper, ChannelListener l) { - mAsyncChannel = new AsyncChannel(); - mHandler = new ServiceHandler(looper); - mChannelListener = l; + private class ServiceHandler extends Handler { + ServiceHandler(Looper looper) { + super(looper); } - private ChannelListener mChannelListener; - private DnsSdDiscoveryListener mDnsSdDiscoveryListener; - private ActionListener mDnsSdStopDiscoveryListener; - private DnsSdRegisterListener mDnsSdRegisterListener; - private ActionListener mDnsSdUnregisterListener; - private DnsSdUpdateRegistrationListener mDnsSdUpdateListener; - private DnsSdResolveListener mDnsSdResolveListener; - private ActionListener mDnsSdStopResolveListener; - private AsyncChannel mAsyncChannel; - private ServiceHandler mHandler; - class ServiceHandler extends Handler { - ServiceHandler(Looper looper) { - super(looper); + @Override + public void handleMessage(Message message) { + Object listener = getListener(message.arg2); + boolean listenerRemove = true; + switch (message.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: + mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + mConnected.countDown(); + break; + case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: + // Ignore + break; + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + Log.e(TAG, "Channel lost"); + break; + case DISCOVER_SERVICES_STARTED: + String s = ((NsdServiceInfo) message.obj).getServiceType(); + ((DiscoveryListener) listener).onDiscoveryStarted(s); + // Keep listener until stop discovery + listenerRemove = false; + break; + case DISCOVER_SERVICES_FAILED: + ((DiscoveryListener) listener).onStartDiscoveryFailed( + getNsdService(message.arg2).getServiceType(), message.arg1); + break; + case SERVICE_FOUND: + ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); + // Keep listener until stop discovery + listenerRemove = false; + break; + case SERVICE_LOST: + ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); + // Keep listener until stop discovery + listenerRemove = false; + break; + case STOP_DISCOVERY_FAILED: + ((DiscoveryListener) listener).onStopDiscoveryFailed( + getNsdService(message.arg2).getServiceType(), message.arg1); + break; + case STOP_DISCOVERY_SUCCEEDED: + ((DiscoveryListener) listener).onDiscoveryStopped( + getNsdService(message.arg2).getServiceType()); + break; + case REGISTER_SERVICE_FAILED: + ((RegistrationListener) listener).onRegistrationFailed( + getNsdService(message.arg2), message.arg1); + break; + case REGISTER_SERVICE_SUCCEEDED: + ((RegistrationListener) listener).onServiceRegistered( + (NsdServiceInfo) message.obj); + // Keep listener until unregister + listenerRemove = false; + break; + case UNREGISTER_SERVICE_FAILED: + ((RegistrationListener) listener).onUnregistrationFailed( + getNsdService(message.arg2), message.arg1); + break; + case UNREGISTER_SERVICE_SUCCEEDED: + ((RegistrationListener) listener).onServiceUnregistered( + getNsdService(message.arg2)); + break; + case RESOLVE_SERVICE_FAILED: + ((ResolveListener) listener).onResolveFailed( + getNsdService(message.arg2), message.arg1); + break; + case RESOLVE_SERVICE_SUCCEEDED: + ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); + break; + default: + Log.d(TAG, "Ignored " + message); + break; } - - @Override - public void handleMessage(Message message) { - switch (message.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - break; - case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: - if (mChannelListener != null) { - mChannelListener.onChannelConnected(Channel.this); - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (mChannelListener != null) { - mChannelListener.onChannelDisconnected(); - mChannelListener = null; - } - break; - case DISCOVER_SERVICES_STARTED: - if (mDnsSdDiscoveryListener != null) { - mDnsSdDiscoveryListener.onStarted((String) message.obj); - } - break; - case DISCOVER_SERVICES_FAILED: - if (mDnsSdDiscoveryListener != null) { - mDnsSdDiscoveryListener.onFailure(message.arg1); - } - break; - case SERVICE_FOUND: - if (mDnsSdDiscoveryListener != null) { - mDnsSdDiscoveryListener.onServiceFound( - (DnsSdServiceInfo) message.obj); - } - break; - case SERVICE_LOST: - if (mDnsSdDiscoveryListener != null) { - mDnsSdDiscoveryListener.onServiceLost( - (DnsSdServiceInfo) message.obj); - } - break; - case STOP_DISCOVERY_FAILED: - if (mDnsSdStopDiscoveryListener != null) { - mDnsSdStopDiscoveryListener.onFailure(message.arg1); - } - break; - case STOP_DISCOVERY_SUCCEEDED: - if (mDnsSdStopDiscoveryListener != null) { - mDnsSdStopDiscoveryListener.onSuccess(); - } - break; - case REGISTER_SERVICE_FAILED: - if (mDnsSdRegisterListener != null) { - mDnsSdRegisterListener.onFailure(message.arg1); - } - break; - case REGISTER_SERVICE_SUCCEEDED: - if (mDnsSdRegisterListener != null) { - mDnsSdRegisterListener.onServiceRegistered(message.arg1, - (DnsSdServiceInfo) message.obj); - } - break; - case UNREGISTER_SERVICE_FAILED: - if (mDnsSdUnregisterListener != null) { - mDnsSdUnregisterListener.onFailure(message.arg1); - } - break; - case UNREGISTER_SERVICE_SUCCEEDED: - if (mDnsSdUnregisterListener != null) { - mDnsSdUnregisterListener.onSuccess(); - } - break; - case UPDATE_SERVICE_FAILED: - if (mDnsSdUpdateListener != null) { - mDnsSdUpdateListener.onFailure(message.arg1); - } - break; - case UPDATE_SERVICE_SUCCEEDED: - if (mDnsSdUpdateListener != null) { - mDnsSdUpdateListener.onServiceUpdated(message.arg1, - (DnsSdTxtRecord) message.obj); - } - break; - case RESOLVE_SERVICE_FAILED: - if (mDnsSdResolveListener != null) { - mDnsSdResolveListener.onFailure(message.arg1); - } - break; - case RESOLVE_SERVICE_SUCCEEDED: - if (mDnsSdResolveListener != null) { - mDnsSdResolveListener.onServiceResolved( - (DnsSdServiceInfo) message.obj); - } - break; - case STOP_RESOLVE_FAILED: - if (mDnsSdStopResolveListener!= null) { - mDnsSdStopResolveListener.onFailure(message.arg1); - } - break; - case STOP_RESOLVE_SUCCEEDED: - if (mDnsSdStopResolveListener != null) { - mDnsSdStopResolveListener.onSuccess(); - } - break; - default: - Log.d(TAG, "Ignored " + message); - break; - } + if (listenerRemove) { + removeListener(message.arg2); } } - } - - private static void checkChannel(Channel c) { - if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); } + private int putListener(Object listener, NsdServiceInfo s) { + if (listener == null) return INVALID_LISTENER_KEY; + int key; + synchronized (mMapLock) { + do { + key = mListenerKey++; + } while (key == INVALID_LISTENER_KEY); + mListenerMap.put(key, listener); + mServiceMap.put(key, s); + } + return key; + } + + private Object getListener(int key) { + if (key == INVALID_LISTENER_KEY) return null; + synchronized (mMapLock) { + return mListenerMap.get(key); + } + } + + private NsdServiceInfo getNsdService(int key) { + synchronized (mMapLock) { + return mServiceMap.get(key); + } + } + + private void removeListener(int key) { + if (key == INVALID_LISTENER_KEY) return; + synchronized (mMapLock) { + mListenerMap.remove(key); + mServiceMap.remove(key); + } + } + + private int getListenerKey(Object listener) { + synchronized (mMapLock) { + int valueIndex = mListenerMap.indexOfValue(listener); + if (valueIndex != -1) { + return mListenerMap.keyAt(valueIndex); + } + } + return INVALID_LISTENER_KEY; + } + + /** - * Registers the application with the service discovery framework. This function - * must be the first to be called before any other operations are performed. No service - * discovery operations must be performed until the ChannelListener callback notifies - * that the channel is connected - * - * @param srcContext is the context of the source - * @param srcLooper is the Looper on which the callbacks are receivied - * @param listener for callback at loss of framework communication. Cannot be null. + * Initialize AsyncChannel */ - public void initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { - Messenger messenger = getMessenger(); + private void init() { + final Messenger messenger = getMessenger(); if (messenger == null) throw new RuntimeException("Failed to initialize"); - if (listener == null) throw new IllegalArgumentException("ChannelListener cannot be null"); - - Channel c = new Channel(srcLooper, listener); - c.mAsyncChannel.connect(srcContext, c.mHandler, messenger); - } - - /** - * Disconnects application from service discovery framework. No further operations - * will succeed until a {@link #initialize} is called again. - * - * @param c channel initialized with {@link #initialize} - */ - public void deinitialize(Channel c) { - checkChannel(c); - c.mAsyncChannel.disconnect(); + HandlerThread t = new HandlerThread("NsdManager"); + t.start(); + mHandler = new ServiceHandler(t.getLooper()); + mAsyncChannel.connect(mContext, mHandler, messenger); + try { + mConnected.await(); + } catch (InterruptedException e) { + Log.e(TAG, "interrupted wait at init"); + } } /** @@ -510,45 +444,51 @@ public class NsdManager { * *

The function call immediately returns after sending a request to register service * to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DnsSdRegisterListener#onServiceRegistered} or a failure - * through {@link DnsSdRegisterListener#onFailure}. + * discovery through the callback {@link RegistrationListener#onServiceRegistered} or a failure + * through {@link RegistrationListener#onRegistrationFailed}. * - * @param c is the channel created at {@link #initialize} - * @param serviceType The service type being advertised. - * @param port on which the service is listenering for incoming connections - * @param listener for success or failure callback. Can be null. + * @param serviceInfo The service being registered + * @param protocolType The service discovery protocol + * @param listener The listener notifies of a successful registration and is used to + * unregister this service through a call on {@link #unregisterService}. Cannot be null. */ - public void registerService(Channel c, String serviceName, String serviceType, int port, - DnsSdRegisterListener listener) { - checkChannel(c); - if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) { + public void registerService(NsdServiceInfo serviceInfo, int protocolType, + RegistrationListener listener) { + if (TextUtils.isEmpty(serviceInfo.getServiceName()) || + TextUtils.isEmpty(serviceInfo.getServiceType())) { throw new IllegalArgumentException("Service name or type cannot be empty"); } - if (port <= 0) { + if (serviceInfo.getPort() <= 0) { throw new IllegalArgumentException("Invalid port number"); } - DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null); - serviceInfo.setPort(port); - c.mDnsSdRegisterListener = listener; - c.mAsyncChannel.sendMessage(REGISTER_SERVICE, serviceInfo); + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + if (protocolType != PROTOCOL_DNS_SD) { + throw new IllegalArgumentException("Unsupported protocol"); + } + mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, putListener(listener, serviceInfo), + serviceInfo); } /** - * Unregister a service registered through {@link #registerService} - * @param c is the channel created at {@link #initialize} - * @param registeredId is obtained at {@link DnsSdRegisterListener#onServiceRegistered} - * @param listener provides callbacks for success or failure. Can be null. + * Unregister a service registered through {@link #registerService}. A successful + * unregister is notified to the application with a call to + * {@link RegistrationListener#onServiceUnregistered}. + * + * @param listener This should be the listener object that was passed to + * {@link #registerService}. It identifies the service that should be unregistered + * and notifies of a successful unregistration. */ - public void unregisterService(Channel c, int registeredId, ActionListener listener) { - checkChannel(c); - c.mDnsSdUnregisterListener = listener; - c.mAsyncChannel.sendMessage(UNREGISTER_SERVICE, registeredId); - } - - /** @hide */ - public void updateService(Channel c, int registeredId, DnsSdTxtRecord txtRecord) { - checkChannel(c); - c.mAsyncChannel.sendMessage(UPDATE_SERVICE, registeredId, 0, txtRecord); + public void unregisterService(RegistrationListener listener) { + int id = getListenerKey(listener); + if (id == INVALID_LISTENER_KEY) { + throw new IllegalArgumentException("listener not registered"); + } + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); } /** @@ -558,51 +498,61 @@ public class NsdManager { * *

The function call immediately returns after sending a request to start service * discovery to the framework. The application is notified of a success to initiate - * discovery through the callback {@link DnsSdDiscoveryListener#onStarted} or a failure - * through {@link DnsSdDiscoveryListener#onFailure}. + * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure + * through {@link DiscoveryListener#onStartDiscoveryFailed}. * *

Upon successful start, application is notified when a service is found with - * {@link DnsSdDiscoveryListener#onServiceFound} or when a service is lost with - * {@link DnsSdDiscoveryListener#onServiceLost}. + * {@link DiscoveryListener#onServiceFound} or when a service is lost with + * {@link DiscoveryListener#onServiceLost}. * *

Upon failure to start, service discovery is not active and application does * not need to invoke {@link #stopServiceDiscovery} * - * @param c is the channel created at {@link #initialize} * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers - * @param listener provides callbacks when service is found or lost. Cannot be null. + * @param protocolType The service discovery protocol + * @param listener The listener notifies of a successful discovery and is used + * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. + * Cannot be null. */ - public void discoverServices(Channel c, String serviceType, DnsSdDiscoveryListener listener) { - checkChannel(c); + public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { if (listener == null) { - throw new IllegalStateException("Discovery listener needs to be set first"); + throw new IllegalArgumentException("listener cannot be null"); } if (TextUtils.isEmpty(serviceType)) { - throw new IllegalStateException("Service type cannot be empty"); + throw new IllegalArgumentException("Service type cannot be empty"); } - DnsSdServiceInfo s = new DnsSdServiceInfo(); + + if (protocolType != PROTOCOL_DNS_SD) { + throw new IllegalArgumentException("Unsupported protocol"); + } + + NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); - c.mDnsSdDiscoveryListener = listener; - c.mAsyncChannel.sendMessage(DISCOVER_SERVICES, s); + mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, putListener(listener, s), s); } /** * Stop service discovery initiated with {@link #discoverServices}. An active service - * discovery is notified to the application with {@link DnsSdDiscoveryListener#onStarted} - * and it stays active until the application invokes a stop service discovery. + * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} + * and it stays active until the application invokes a stop service discovery. A successful + * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. * - *

Upon failure to start service discovery notified through - * {@link DnsSdDiscoveryListener#onFailure} service discovery is not active and - * application does not need to stop it. + *

Upon failure to stop service discovery, application is notified through + * {@link DiscoveryListener#onStopDiscoveryFailed}. * - * @param c is the channel created at {@link #initialize} - * @param listener notifies success or failure. Can be null. + * @param listener This should be the listener object that was passed to {@link #discoverServices}. + * It identifies the discovery that should be stopped and notifies of a successful stop. */ - public void stopServiceDiscovery(Channel c, ActionListener listener) { - checkChannel(c); - c.mDnsSdStopDiscoveryListener = listener; - c.mAsyncChannel.sendMessage(STOP_DISCOVERY); + public void stopServiceDiscovery(DiscoveryListener listener) { + int id = getListenerKey(listener); + if (id == INVALID_LISTENER_KEY) { + throw new IllegalArgumentException("service discovery not active on listener"); + } + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); } /** @@ -610,30 +560,19 @@ public class NsdManager { * establishing a connection to fetch the IP and port details on which to setup * the connection. * - * @param c is the channel created at {@link #initialize} - * @param serviceName of the the service - * @param serviceType of the service + * @param serviceInfo service to be resolved * @param listener to receive callback upon success or failure. Cannot be null. */ - public void resolveService(Channel c, String serviceName, String serviceType, - DnsSdResolveListener listener) { - checkChannel(c); - if (TextUtils.isEmpty(serviceName) || TextUtils.isEmpty(serviceType)) { + public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { + if (TextUtils.isEmpty(serviceInfo.getServiceName()) || + TextUtils.isEmpty(serviceInfo.getServiceType())) { throw new IllegalArgumentException("Service name or type cannot be empty"); } - if (listener == null) throw new - IllegalStateException("Resolve listener cannot be null"); - c.mDnsSdResolveListener = listener; - DnsSdServiceInfo serviceInfo = new DnsSdServiceInfo(serviceName, serviceType, null); - c.mAsyncChannel.sendMessage(RESOLVE_SERVICE, serviceInfo); - } - - /** @hide */ - public void stopServiceResolve(Channel c) { - checkChannel(c); - if (c.mDnsSdResolveListener == null) throw new - IllegalStateException("Resolve listener needs to be set first"); - c.mAsyncChannel.sendMessage(STOP_RESOLVE); + if (listener == null) { + throw new IllegalArgumentException("listener cannot be null"); + } + mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, putListener(listener, serviceInfo), + serviceInfo); } /** Internal use only @hide */ diff --git a/core/java/android/net/nsd/DnsSdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java similarity index 86% rename from core/java/android/net/nsd/DnsSdServiceInfo.java rename to core/java/android/net/nsd/NsdServiceInfo.java index 66abd3a321..205a21d95b 100644 --- a/core/java/android/net/nsd/DnsSdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -25,7 +25,7 @@ import java.net.InetAddress; * A class representing service information for network service discovery * {@see NsdManager} */ -public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { +public final class NsdServiceInfo implements Parcelable { private String mServiceName; @@ -37,36 +37,32 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { private int mPort; - public DnsSdServiceInfo() { + public NsdServiceInfo() { } /** @hide */ - public DnsSdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { + public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { mServiceName = sn; mServiceType = rt; mTxtRecord = tr; } /** Get the service name */ - @Override public String getServiceName() { return mServiceName; } /** Set the service name */ - @Override public void setServiceName(String s) { mServiceName = s; } /** Get the service type */ - @Override public String getServiceType() { return mServiceType; } /** Set the service type */ - @Override public void setServiceType(String s) { mServiceType = s; } @@ -132,10 +128,10 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { } /** Implement the Parcelable interface */ - public static final Creator CREATOR = - new Creator() { - public DnsSdServiceInfo createFromParcel(Parcel in) { - DnsSdServiceInfo info = new DnsSdServiceInfo(); + public static final Creator CREATOR = + new Creator() { + public NsdServiceInfo createFromParcel(Parcel in) { + NsdServiceInfo info = new NsdServiceInfo(); info.mServiceName = in.readString(); info.mServiceType = in.readString(); info.mTxtRecord = in.readParcelable(null); @@ -150,8 +146,8 @@ public class DnsSdServiceInfo implements NetworkServiceInfo, Parcelable { return info; } - public DnsSdServiceInfo[] newArray(int size) { - return new DnsSdServiceInfo[size]; + public NsdServiceInfo[] newArray(int size) { + return new NsdServiceInfo[size]; } }; } diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index f33bf8b24e..cc8e6a4b2d 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -20,7 +20,7 @@ import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; -import android.net.nsd.DnsSdServiceInfo; +import android.net.nsd.NsdServiceInfo; import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -32,6 +32,7 @@ import android.os.Messenger; import android.os.IBinder; import android.provider.Settings; import android.util.Slog; +import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -72,13 +73,16 @@ public class NsdService extends INsdManager.Stub { */ private HashMap mClients = new HashMap(); + /* A map from unique id to client info */ + private SparseArray mIdToClientInfoMap= new SparseArray(); + private AsyncChannel mReplyChannel = new AsyncChannel(); private int INVALID_ID = 0; private int mUniqueId = 1; private static final int BASE = Protocol.BASE_NSD_MANAGER; - private static final int CMD_TO_STRING_COUNT = NsdManager.STOP_RESOLVE - BASE + 1; + private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1; private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT]; static { @@ -87,7 +91,6 @@ public class NsdService extends INsdManager.Stub { sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER"; sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER"; sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE"; - sCmdToString[NsdManager.STOP_RESOLVE - BASE] = "STOP-RESOLVE"; } private static String cmdToString(int cmd) { @@ -101,9 +104,9 @@ public class NsdService extends INsdManager.Stub { private class NsdStateMachine extends StateMachine { - private DefaultState mDefaultState = new DefaultState(); - private DisabledState mDisabledState = new DisabledState(); - private EnabledState mEnabledState = new EnabledState(); + private final DefaultState mDefaultState = new DefaultState(); + private final DisabledState mDisabledState = new DisabledState(); + private final EnabledState mEnabledState = new EnabledState(); @Override protected String getMessageInfo(Message msg) { @@ -151,29 +154,26 @@ public class NsdService extends INsdManager.Stub { ac.connect(mContext, getHandler(), msg.replyTo); break; case NsdManager.DISCOVER_SERVICES: - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.BUSY); + replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; case NsdManager.STOP_DISCOVERY: - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; case NsdManager.REGISTER_SERVICE: - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; case NsdManager.UNREGISTER_SERVICE: - mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; case NsdManager.RESOLVE_SERVICE: - mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.ERROR); - break; - case NsdManager.STOP_RESOLVE: - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; + case NsdManager.NATIVE_DAEMON_EVENT: default: Slog.e(TAG, "Unhandled " + msg); return NOT_HANDLED; @@ -217,11 +217,30 @@ public class NsdService extends INsdManager.Stub { } } + private boolean requestLimitReached(ClientInfo clientInfo) { + if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) { + if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo); + return true; + } + return false; + } + + private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + clientInfo.mClientIds.put(clientId, globalId); + mIdToClientInfoMap.put(globalId, clientInfo); + } + + private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + clientInfo.mClientIds.remove(clientId); + mIdToClientInfoMap.remove(globalId); + } + @Override public boolean processMessage(Message msg) { ClientInfo clientInfo; - DnsSdServiceInfo servInfo; + NsdServiceInfo servInfo; boolean result = HANDLED; + int id; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: //First client @@ -244,111 +263,112 @@ public class NsdService extends INsdManager.Stub { break; case NsdManager.DISCOVER_SERVICES: if (DBG) Slog.d(TAG, "Discover services"); - servInfo = (DnsSdServiceInfo) msg.obj; + servInfo = (NsdServiceInfo) msg.obj; clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId != INVALID_ID) { - //discovery already in progress - if (DBG) Slog.d(TAG, "discovery in progress"); - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ALREADY_ACTIVE); + + if (requestLimitReached(clientInfo)) { + replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.FAILURE_MAX_LIMIT); break; } - clientInfo.mDiscoveryId = getUniqueId(); - if (discoverServices(clientInfo.mDiscoveryId, servInfo.getServiceType())) { - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED); + + id = getUniqueId(); + if (discoverServices(id, servInfo.getServiceType())) { + if (DBG) { + Slog.d(TAG, "Discover " + msg.arg2 + " " + id + + servInfo.getServiceType()); + } + storeRequestMap(msg.arg2, id, clientInfo); + replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); } else { - mReplyChannel.replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ERROR); - clientInfo.mDiscoveryId = INVALID_ID; + stopServiceDiscovery(id); + replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.STOP_DISCOVERY: if (DBG) Slog.d(TAG, "Stop service discovery"); clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mDiscoveryId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "discovery already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ALREADY_ACTIVE); + + try { + id = clientInfo.mClientIds.get(msg.arg2).intValue(); + } catch (NullPointerException e) { + replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); break; } - if (stopServiceDiscovery(clientInfo.mDiscoveryId)) { - clientInfo.mDiscoveryId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); + removeRequestMap(msg.arg2, id, clientInfo); + if (stopServiceDiscovery(id)) { + replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); } else { - mReplyChannel.replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.REGISTER_SERVICE: if (DBG) Slog.d(TAG, "Register service"); clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mRegisteredIds.size() >= ClientInfo.MAX_REG) { - if (DBG) Slog.d(TAG, "register service exceeds limit"); - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.MAX_REGS_REACHED); + if (requestLimitReached(clientInfo)) { + replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.FAILURE_MAX_LIMIT); + break; } - int id = getUniqueId(); - if (registerService(id, (DnsSdServiceInfo) msg.obj)) { - clientInfo.mRegisteredIds.add(id); + id = getUniqueId(); + if (registerService(id, (NsdServiceInfo) msg.obj)) { + if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); + storeRequestMap(msg.arg2, id, clientInfo); + // Return success after mDns reports success } else { - mReplyChannel.replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.ERROR); + unregisterService(id); + replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.UNREGISTER_SERVICE: if (DBG) Slog.d(TAG, "unregister service"); clientInfo = mClients.get(msg.replyTo); - int regId = msg.arg1; - if (clientInfo.mRegisteredIds.remove(new Integer(regId)) && - unregisterService(regId)) { - mReplyChannel.replyToMessage(msg, - NsdManager.UNREGISTER_SERVICE_SUCCEEDED); + try { + id = clientInfo.mClientIds.get(msg.arg2).intValue(); + } catch (NullPointerException e) { + replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); + break; + } + removeRequestMap(msg.arg2, id, clientInfo); + if (unregisterService(id)) { + replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED); } else { - mReplyChannel.replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); } - break; - case NsdManager.UPDATE_SERVICE: - if (DBG) Slog.d(TAG, "Update service"); - //TODO: implement - mReplyChannel.replyToMessage(msg, NsdManager.UPDATE_SERVICE_FAILED); break; case NsdManager.RESOLVE_SERVICE: if (DBG) Slog.d(TAG, "Resolve service"); - servInfo = (DnsSdServiceInfo) msg.obj; + servInfo = (NsdServiceInfo) msg.obj; clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId != INVALID_ID) { - //first cancel existing resolve - stopResolveService(clientInfo.mResolveId); - } - clientInfo.mResolveId = getUniqueId(); - if (!resolveService(clientInfo.mResolveId, servInfo)) { - mReplyChannel.replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.ERROR); - clientInfo.mResolveId = INVALID_ID; - } - break; - case NsdManager.STOP_RESOLVE: - if (DBG) Slog.d(TAG, "Stop resolve"); - clientInfo = mClients.get(msg.replyTo); - if (clientInfo.mResolveId == INVALID_ID) { - //already stopped - if (DBG) Slog.d(TAG, "resolve already stopped"); - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ALREADY_ACTIVE); + + if (clientInfo.mResolvedService != null) { + replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_ALREADY_ACTIVE); break; } - if (stopResolveService(clientInfo.mResolveId)) { - clientInfo.mResolveId = INVALID_ID; - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_SUCCEEDED); + + id = getUniqueId(); + if (resolveService(id, servInfo)) { + clientInfo.mResolvedService = new NsdServiceInfo(); + storeRequestMap(msg.arg2, id, clientInfo); } else { - mReplyChannel.replyToMessage(msg, NsdManager.STOP_RESOLVE_FAILED, - NsdManager.ERROR); + replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR); } break; + case NsdManager.NATIVE_DAEMON_EVENT: + NativeEvent event = (NativeEvent) msg.obj; + handleNativeEvent(event.code, event.raw, + NativeDaemonEvent.unescapeArgs(event.raw)); + break; default: result = NOT_HANDLED; break; @@ -439,121 +459,144 @@ public class NsdService extends INsdManager.Stub { public static final int SERVICE_GET_ADDR_SUCCESS = 612; } + private class NativeEvent { + int code; + String raw; + + NativeEvent(int code, String raw) { + this.code = code; + this.raw = raw; + } + } + class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { public void onDaemonConnected() { mNativeDaemonConnected.countDown(); } public boolean onEvent(int code, String raw, String[] cooked) { - ClientInfo clientInfo; - DnsSdServiceInfo servInfo; - int id = Integer.parseInt(cooked[1]); - switch (code) { - case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain */ - if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); - clientInfo = getClientByDiscovery(id); - if (clientInfo == null) break; + // TODO: NDC translates a message to a callback, we could enhance NDC to + // directly interact with a state machine through messages + NativeEvent event = new NativeEvent(code, raw); + mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event); + return true; + } + } - servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, servInfo); + private void handleNativeEvent(int code, String raw, String[] cooked) { + NsdServiceInfo servInfo; + int id = Integer.parseInt(cooked[1]); + ClientInfo clientInfo = mIdToClientInfoMap.get(id); + if (clientInfo == null) { + Slog.e(TAG, "Unique id with no client mapping: " + id); + return; + } + + /* This goes in response as msg.arg2 */ + int clientId = -1; + int keyId = clientInfo.mClientIds.indexOfValue(id); + if (keyId != -1) { + clientId = clientInfo.mClientIds.keyAt(keyId); + } + switch (code) { + case NativeResponseCode.SERVICE_FOUND: + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, + clientId, servInfo); + break; + case NativeResponseCode.SERVICE_LOST: + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, + clientId, servInfo); + break; + case NativeResponseCode.SERVICE_DISCOVERY_FAILED: + /* NNN uniqueId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_REGISTERED: + /* NNN regId serviceName regType */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], null, null); + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, + id, clientId, servInfo); + break; + case NativeResponseCode.SERVICE_REGISTRATION_FAILED: + /* NNN regId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_UPDATED: + /* NNN regId */ + break; + case NativeResponseCode.SERVICE_UPDATE_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_RESOLVED: + /* NNN resolveId fullName hostName port txtlen txtdata */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); + int index = cooked[2].indexOf("."); + if (index == -1) { + Slog.e(TAG, "Invalid service found " + raw); break; - case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain */ - if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); - clientInfo = getClientByDiscovery(id); - if (clientInfo == null) break; + } + String name = cooked[2].substring(0, index); + String rest = cooked[2].substring(index); + String type = rest.replace(".local.", ""); - servInfo = new DnsSdServiceInfo(cooked[2], cooked[3], null); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, servInfo); - break; - case NativeResponseCode.SERVICE_DISCOVERY_FAILED: - /* NNN uniqueId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw); - clientInfo = getClientByDiscovery(id); - if (clientInfo == null) break; - - clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.ERROR); - break; - case NativeResponseCode.SERVICE_REGISTERED: - /* NNN regId serviceName regType */ - if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); - clientInfo = getClientByRegistration(id); - if (clientInfo == null) break; - - servInfo = new DnsSdServiceInfo(cooked[2], null, null); - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, - id, 0, servInfo); - break; - case NativeResponseCode.SERVICE_REGISTRATION_FAILED: - /* NNN regId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw); - clientInfo = getClientByRegistration(id); - if (clientInfo == null) break; - - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.ERROR); - break; - case NativeResponseCode.SERVICE_UPDATED: - /* NNN regId */ - break; - case NativeResponseCode.SERVICE_UPDATE_FAILED: - /* NNN regId errorCode */ - break; - case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata */ - if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); - clientInfo = getClientByResolve(id); - if (clientInfo == null) break; - - int index = cooked[2].indexOf("."); - if (index == -1) { - Slog.e(TAG, "Invalid service found " + raw); - break; - } - String name = cooked[2].substring(0, index); - String rest = cooked[2].substring(index); - String type = rest.replace(".local.", ""); - - clientInfo.mResolvedService = new DnsSdServiceInfo(name, type, null); - clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); - - stopResolveService(id); - getAddrInfo(id, cooked[3]); - break; - case NativeResponseCode.SERVICE_RESOLUTION_FAILED: - case NativeResponseCode.SERVICE_GET_ADDR_FAILED: - /* NNN resolveId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); - clientInfo = getClientByResolve(id); - if (clientInfo == null) break; + clientInfo.mResolvedService.setServiceName(name); + clientInfo.mResolvedService.setServiceType(type); + clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); + stopResolveService(id); + if (!getAddrInfo(id, cooked[3])) { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.ERROR); - break; - case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr */ - if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw); - clientInfo = getClientByResolve(id); - if (clientInfo == null || clientInfo.mResolvedService == null) break; - - try { - clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, - clientInfo.mResolvedService); - clientInfo.mResolvedService = null; - clientInfo.mResolveId = INVALID_ID; - } catch (java.net.UnknownHostException e) { - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.ERROR); - } - stopGetAddrInfo(id); - break; - default: - break; - } - return false; + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + mIdToClientInfoMap.remove(id); + clientInfo.mResolvedService = null; + } + break; + case NativeResponseCode.SERVICE_RESOLUTION_FAILED: + /* NNN resolveId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); + stopResolveService(id); + mIdToClientInfoMap.remove(id); + clientInfo.mResolvedService = null; + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_GET_ADDR_FAILED: + /* NNN resolveId errorCode */ + stopGetAddrInfo(id); + mIdToClientInfoMap.remove(id); + clientInfo.mResolvedService = null; + if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: + /* NNN resolveId hostname ttl addr */ + if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw); + try { + clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, + 0, clientId, clientInfo.mResolvedService); + } catch (java.net.UnknownHostException e) { + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + } + stopGetAddrInfo(id); + mIdToClientInfoMap.remove(id); + clientInfo.mResolvedService = null; + break; + default: + break; } } @@ -579,7 +622,7 @@ public class NsdService extends INsdManager.Stub { return true; } - private boolean registerService(int regId, DnsSdServiceInfo service) { + private boolean registerService(int regId, NsdServiceInfo service) { if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); try { //Add txtlen and txtdata @@ -637,7 +680,7 @@ public class NsdService extends INsdManager.Stub { return true; } - private boolean resolveService(int resolveId, DnsSdServiceInfo service) { + private boolean resolveService(int resolveId, NsdServiceInfo service) { if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service); try { mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(), @@ -700,49 +743,52 @@ public class NsdService extends INsdManager.Stub { mNsdStateMachine.dump(fd, pw, args); } - private ClientInfo getClientByDiscovery(int discoveryId) { - for (ClientInfo c: mClients.values()) { - if (c.mDiscoveryId == discoveryId) { - return c; - } - } - return null; + /* arg2 on the source message has an id that needs to be retained in replies + * see NsdManager for details */ + private Message obtainMessage(Message srcMsg) { + Message msg = Message.obtain(); + msg.arg2 = srcMsg.arg2; + return msg; } - private ClientInfo getClientByResolve(int resolveId) { - for (ClientInfo c: mClients.values()) { - if (c.mResolveId == resolveId) { - return c; - } - } - return null; + private void replyToMessage(Message msg, int what) { + if (msg.replyTo == null) return; + Message dstMsg = obtainMessage(msg); + dstMsg.what = what; + mReplyChannel.replyToMessage(msg, dstMsg); } - private ClientInfo getClientByRegistration(int regId) { - for (ClientInfo c: mClients.values()) { - if (c.mRegisteredIds.contains(regId)) { - return c; - } - } - return null; + private void replyToMessage(Message msg, int what, int arg1) { + if (msg.replyTo == null) return; + Message dstMsg = obtainMessage(msg); + dstMsg.what = what; + dstMsg.arg1 = arg1; + mReplyChannel.replyToMessage(msg, dstMsg); + } + + private void replyToMessage(Message msg, int what, Object obj) { + if (msg.replyTo == null) return; + Message dstMsg = obtainMessage(msg); + dstMsg.what = what; + dstMsg.obj = obj; + mReplyChannel.replyToMessage(msg, dstMsg); } /* Information tracked per client */ private class ClientInfo { - private static final int MAX_REG = 5; + private static final int MAX_LIMIT = 10; private AsyncChannel mChannel; private Messenger mMessenger; - private int mDiscoveryId; - private int mResolveId; /* Remembers a resolved service until getaddrinfo completes */ - private DnsSdServiceInfo mResolvedService; - private ArrayList mRegisteredIds = new ArrayList(); + private NsdServiceInfo mResolvedService; + + /* A map from client id to unique id sent to mDns */ + private SparseArray mClientIds = new SparseArray(); private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; mMessenger = m; - mDiscoveryId = mResolveId = INVALID_ID; if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); } @@ -751,11 +797,10 @@ public class NsdService extends INsdManager.Stub { StringBuffer sb = new StringBuffer(); sb.append("mChannel ").append(mChannel).append("\n"); sb.append("mMessenger ").append(mMessenger).append("\n"); - sb.append("mDiscoveryId ").append(mDiscoveryId).append("\n"); - sb.append("mResolveId ").append(mResolveId).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); - for(int regId : mRegisteredIds) { - sb.append("regId ").append(regId).append("\n"); + for(int i = 0; i< mClientIds.size(); i++) { + sb.append("clientId ").append(mClientIds.keyAt(i)); + sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n"); } return sb.toString(); } From 585bc91d22e29cbfef296b7a31dd6bbafd8971e4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 9 May 2012 13:33:52 -0700 Subject: [PATCH 0151/1150] Recover from Throwable in FileRotator, dump. In rewriteSingle(), catch Throwable to rollback to backup file, instead of just IOException. Also add dumpAll() to pack up contents for later debugging, and use it when encountering bad stats. Bug: 6467868 Change-Id: Ic8e287cf5a235706811a304a88d71d11d3a79cd4 --- .../server/net/NetworkStatsRecorder.java | 37 ++++++++++++++++++- .../server/net/NetworkStatsService.java | 4 +- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 2ce7771135..c3ecf54951 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -26,6 +26,7 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.DropBoxManager; import android.util.Log; import android.util.MathUtils; import android.util.Slog; @@ -34,6 +35,7 @@ import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Sets; +import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; @@ -43,6 +45,8 @@ import java.lang.ref.WeakReference; import java.util.HashSet; import java.util.Map; +import libcore.io.IoUtils; + /** * Logic to record deltas between periodic {@link NetworkStats} snapshots into * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. @@ -56,8 +60,14 @@ public class NetworkStatsRecorder { private static final boolean LOGD = false; private static final boolean LOGV = false; + private static final String TAG_NETSTATS_DUMP = "netstats_dump"; + + /** Dump before deleting in {@link #recoverFromWtf()}. */ + private static final boolean DUMP_BEFORE_DELETE = true; + private final FileRotator mRotator; private final NonMonotonicObserver mObserver; + private final DropBoxManager mDropBox; private final String mCookie; private final long mBucketDuration; @@ -74,9 +84,10 @@ public class NetworkStatsRecorder { private WeakReference mComplete; public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, - String cookie, long bucketDuration, boolean onlyTags) { + DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) { mRotator = checkNotNull(rotator, "missing FileRotator"); mObserver = checkNotNull(observer, "missing NonMonotonicObserver"); + mDropBox = checkNotNull(dropBox, "missing DropBoxManager"); mCookie = cookie; mBucketDuration = bucketDuration; @@ -122,6 +133,7 @@ public class NetworkStatsRecorder { mComplete = new WeakReference(complete); } catch (IOException e) { Log.wtf(TAG, "problem completely reading network stats", e); + recoverFromWtf(); } } return complete; @@ -212,6 +224,7 @@ public class NetworkStatsRecorder { mPending.reset(); } catch (IOException e) { Log.wtf(TAG, "problem persisting pending stats", e); + recoverFromWtf(); } } } @@ -226,6 +239,7 @@ public class NetworkStatsRecorder { mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); } catch (IOException e) { Log.wtf(TAG, "problem removing UID " + uid, e); + recoverFromWtf(); } // clear UID from current stats snapshot @@ -355,4 +369,25 @@ public class NetworkStatsRecorder { mSinceBoot.dump(pw); } } + + /** + * Recover from {@link FileRotator} failure by dumping state to + * {@link DropBoxManager} and deleting contents. + */ + private void recoverFromWtf() { + if (DUMP_BEFORE_DELETE) { + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + try { + mRotator.dumpAll(os); + } catch (IOException e) { + // ignore partial contents + os.reset(); + } finally { + IoUtils.closeQuietly(os); + } + mDropBox.addData(TAG_NETSTATS_DUMP, os.toByteArray(), 0); + } + + mRotator.deleteAll(); + } } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 1a56b80d7e..e710b3389e 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -338,9 +338,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsRecorder buildRecorder( String prefix, NetworkStatsSettings.Config config, boolean includeTags) { + final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( + Context.DROPBOX_SERVICE); return new NetworkStatsRecorder(new FileRotator( mBaseDir, prefix, config.rotateAgeMillis, config.deleteAgeMillis), - mNonMonotonicObserver, prefix, config.bucketDuration, includeTags); + mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags); } private void shutdownLocked() { From b9439a4c2aa58d42336ede9b98f1bb16f5afc00c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 9 May 2012 19:59:07 -0700 Subject: [PATCH 0152/1150] Avoid updating thresholds during shutdown. Bug: 6472388 Change-Id: I70e1ed5dc75056840f2f0b130ce0dfecb06f385e --- .../java/com/android/server/net/NetworkStatsService.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index e710b3389e..0e93b0affc 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -608,17 +608,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // clamp threshold into safe range mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); - updatePersistThresholds(); - if (LOGV) { Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " + mPersistThreshold); } - // persist if beyond new thresholds + // update and persist if beyond new thresholds final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); synchronized (mStatsLock) { + if (!mSystemReady) return; + + updatePersistThresholds(); + mDevRecorder.maybePersistLocked(currentTime); mXtRecorder.maybePersistLocked(currentTime); mUidRecorder.maybePersistLocked(currentTime); From b90e5677d15ef964968a93bf1c49c7b73e153d84 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 15 May 2012 17:26:57 -0700 Subject: [PATCH 0153/1150] Add some logging to NDC. bug:6492166 Change-Id: Ib7c7a0927d3e920f6c041f7252f3f24c8e597bc7 --- services/java/com/android/server/NativeDaemonConnector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 6a6c585fe7..a15d3bbb4c 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -148,6 +148,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { + log("POST<- {" + rawEvent + "}"); mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { @@ -327,6 +328,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); } + log("RMV <- {" + event + "}"); events.add(event); } while (event.isClassContinue()); @@ -337,6 +339,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new NativeDaemonFailureException(logCmd, event); } + log("RTN <- {" + logCmd + "}"); return events.toArray(new NativeDaemonEvent[events.size()]); } From 3ddc9b374503dae13cb855a23671371e210adce0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 16 May 2012 14:51:19 -0700 Subject: [PATCH 0154/1150] Transition from DEV network stats to XT. When XT stats are available, transition to prefer them over DEV, since they aren't subject to hardware driver bugs. Only switches at the first atomic XT bucket, and adds a Settings.Secure flag to force back to DEV if needed. Includes tests to cover transition. Fix tests where device overlay would change which network types reflected data usage. Test both history and summary APIs. Fixed collection timestamps to reflect full buckets. Bug: 6504744 Change-Id: Idd7f3b2fdb064c36547c85c51c214fd938c59b7e --- core/java/android/net/NetworkStats.java | 8 +++ .../java/android/net/NetworkStatsHistory.java | 18 +++++- core/java/android/net/NetworkTemplate.java | 11 +++- .../server/net/NetworkStatsCollection.java | 33 ++++++++-- .../server/net/NetworkStatsService.java | 61 ++++++++++++++++++- 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 844d05564b..fb7a4f8ad2 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -111,6 +111,14 @@ public class NetworkStats implements Parcelable { && operations == 0; } + public void add(Entry another) { + this.rxBytes += another.rxBytes; + this.rxPackets += another.rxPackets; + this.txBytes += another.txBytes; + this.txPackets += another.txPackets; + this.operations += another.operations; + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 0003c6e3d6..a37c26f90d 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -342,11 +342,23 @@ public class NetworkStatsHistory implements Parcelable { * for combining together stats for external reporting. */ public void recordEntireHistory(NetworkStatsHistory input) { + recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); + } + + /** + * Record given {@link NetworkStatsHistory} into this history, copying only + * buckets that atomically occur in the inclusive time range. Doesn't + * interpolate across partial buckets. + */ + public void recordHistory(NetworkStatsHistory input, long start, long end) { final NetworkStats.Entry entry = new NetworkStats.Entry( IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); for (int i = 0; i < input.bucketCount; i++) { - final long start = input.bucketStart[i]; - final long end = start + input.bucketDuration; + final long bucketStart = input.bucketStart[i]; + final long bucketEnd = bucketStart + input.bucketDuration; + + // skip when bucket is outside requested range + if (bucketStart < start || bucketEnd > end) continue; entry.rxBytes = getLong(input.rxBytes, i, 0L); entry.rxPackets = getLong(input.rxPackets, i, 0L); @@ -354,7 +366,7 @@ public class NetworkStatsHistory implements Parcelable { entry.txPackets = getLong(input.txPackets, i, 0L); entry.operations = getLong(input.operations, i, 0L); - recordData(start, end, entry); + recordData(bucketStart, bucketEnd, entry); } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 39a4d7bb0d..d8e53d523f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -61,6 +61,13 @@ public class NetworkTemplate implements Parcelable { com.android.internal.R.array.config_data_usage_network_types); } + private static boolean sForceAllNetworkTypes = false; + + // @VisibleForTesting + public static void forceAllNetworkTypes() { + sForceAllNetworkTypes = true; + } + /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -225,7 +232,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return (contains(DATA_USAGE_NETWORK_TYPES, ident.mType) + return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) && Objects.equal(mSubscriberId, ident.mSubscriberId)); } } @@ -291,7 +298,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return contains(DATA_USAGE_NETWORK_TYPES, ident.mType); + return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType); } } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index c2e475a5b4..9ddf011069 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -71,7 +71,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { private HashMap mStats = Maps.newHashMap(); - private long mBucketDuration; + private final long mBucketDuration; private long mStartMillis; private long mEndMillis; @@ -95,6 +95,18 @@ public class NetworkStatsCollection implements FileRotator.Reader { return mStartMillis; } + /** + * Return first atomic bucket in this collection, which is more conservative + * than {@link #mStartMillis}. + */ + public long getFirstAtomicBucketMillis() { + if (mStartMillis == Long.MAX_VALUE) { + return Long.MAX_VALUE; + } else { + return mStartMillis + mBucketDuration; + } + } + public long getEndMillis() { return mEndMillis; } @@ -121,6 +133,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields) { + return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE); + } + + /** + * Combine all {@link NetworkStatsHistory} in this collection which match + * the requested parameters. + */ + public NetworkStatsHistory getHistory( + NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { final NetworkStatsHistory combined = new NetworkStatsHistory( mBucketDuration, estimateBuckets(), fields); for (Map.Entry entry : mStats.entrySet()) { @@ -128,7 +149,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { final boolean setMatches = set == SET_ALL || key.set == set; if (key.uid == uid && setMatches && key.tag == tag && templateMatches(template, key.ident)) { - combined.recordEntireHistory(entry.getValue()); + combined.recordHistory(entry.getValue(), start, end); } } return combined; @@ -145,6 +166,9 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; + // shortcut when we know stats will be empty + if (start == end) return stats; + for (Map.Entry mapEntry : mStats.entrySet()) { final Key key = mapEntry.getKey(); if (templateMatches(template, key.ident)) { @@ -175,8 +199,9 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, long end, NetworkStats.Entry entry) { - noteRecordedHistory(start, end, entry.rxBytes + entry.txBytes); - findOrCreateHistory(ident, uid, set, tag).recordData(start, end, entry); + final NetworkStatsHistory history = findOrCreateHistory(ident, uid, set, tag); + history.recordData(start, end, entry); + noteRecordedHistory(history.getStart(), history.getEnd(), entry.rxBytes + entry.txBytes); } /** diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0e93b0affc..ba122ecdf2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -44,6 +44,7 @@ import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES; import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE; import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES; import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; +import static android.provider.Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV; import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED; import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE; import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; @@ -177,6 +178,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getPollInterval(); public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); + public boolean getReportXtOverDev(); public static class Config { public final long bucketDuration; @@ -221,6 +223,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Cached {@link #mDevRecorder} stats. */ private NetworkStatsCollection mDevStatsCached; + /** Cached {@link #mXtRecorder} stats. */ + private NetworkStatsCollection mXtStatsCached; /** Current counter sets for each UID. */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); @@ -295,6 +299,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // read historical network stats from disk, since policy service // might need them right away. mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked(); + mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); // bootstrap initial stats to prevent double-counting later bootstrapStatsLocked(); @@ -371,6 +376,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidTagRecorder = null; mDevStatsCached = null; + mXtStatsCached = null; mSystemReady = false; } @@ -469,12 +475,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { - return mDevStatsCached.getSummary(template, start, end); + return internalGetSummaryForNetwork(template, start, end); } @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + return internalGetHistoryForNetwork(template, fields); } @Override @@ -507,11 +513,56 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; } + /** + * Return network summary, splicing between {@link #mDevStatsCached} + * and {@link #mXtStatsCached} when appropriate. + */ + private NetworkStats internalGetSummaryForNetwork( + NetworkTemplate template, long start, long end) { + if (!mSettings.getReportXtOverDev()) { + // shortcut when XT reporting disabled + return mDevStatsCached.getSummary(template, start, end); + } + + // splice stats between DEV and XT, switching over from DEV to XT at + // first atomic bucket. + final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); + final NetworkStats dev = mDevStatsCached.getSummary( + template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket)); + final NetworkStats xt = mXtStatsCached.getSummary( + template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket)); + + xt.combineAllValues(dev); + return xt; + } + + /** + * Return network history, splicing between {@link #mDevStatsCached} + * and {@link #mXtStatsCached} when appropriate. + */ + private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) { + if (!mSettings.getReportXtOverDev()) { + // shortcut when XT reporting disabled + return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + } + + // splice stats between DEV and XT, switching over from DEV to XT at + // first atomic bucket. + final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); + final NetworkStatsHistory dev = mDevStatsCached.getHistory( + template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket); + final NetworkStatsHistory xt = mXtStatsCached.getHistory( + template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE); + + xt.recordEntireHistory(dev); + return xt; + } + @Override public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); - return mDevStatsCached.getSummary(template, start, end).getTotalBytes(); + return internalGetSummaryForNetwork(template, start, end).getTotalBytes(); } @Override @@ -1190,6 +1241,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true); } @Override + public boolean getReportXtOverDev() { + return getSecureBoolean(NETSTATS_REPORT_XT_OVER_DEV, true); + } + @Override public Config getDevConfig() { return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 6c37b32a26e119df3ad7c2b178f53721bb26eb7d Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 22 May 2012 16:07:46 -0700 Subject: [PATCH 0155/1150] Modify logging to debug this issue Logging exec time on startUsingNetworkFeature as we've had some reports suggesting it's causing ANRs. Remove some logging from NDC so it's local log is more useful. bug:6492166 Change-Id: I258ff6c59bff2c65935242d50496d84720c5d493 --- .../java/com/android/server/NativeDaemonConnector.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index a15d3bbb4c..f71125a839 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -58,6 +58,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private AtomicInteger mSequenceNumber; private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ + private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */ /** Lock held whenever communicating with native daemon. */ private final Object mDaemonLock = new Object(); @@ -148,7 +149,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( event.getCode(), event.getRawEvent())); } else { - log("POST<- {" + rawEvent + "}"); mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { @@ -300,6 +300,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo final int sequenceNumber = mSequenceNumber.incrementAndGet(); final StringBuilder cmdBuilder = new StringBuilder(Integer.toString(sequenceNumber)).append(' '); + final long startTime = SystemClock.elapsedRealtime(); makeCommand(cmdBuilder, cmd, args); @@ -332,6 +333,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo events.add(event); } while (event.isClassContinue()); + final long endTime = SystemClock.elapsedRealtime(); + if (endTime - startTime > WARN_EXECUTE_DELAY_MS) { + loge("NDC Command {" + logCmd + "} took too long (" + (endTime - startTime) + "ms)"); + } + if (event.isClassClientError()) { throw new NativeDaemonArgumentException(logCmd, event); } @@ -339,7 +345,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new NativeDaemonFailureException(logCmd, event); } - log("RTN <- {" + logCmd + "}"); return events.toArray(new NativeDaemonEvent[events.size()]); } From 358f5d40b1d8842badf2662d8f6fc427aaea6569 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 29 May 2012 12:40:46 -0700 Subject: [PATCH 0156/1150] Enhance StateMachine Quitting and logging support. Make StateMachine#quit non-conditional and remove the need to process the SM_QUIT_CMD it is now private. Rename halting to onHalting. Add onQuitting Change the message specific logging to be more generic and change the xxxProcessedMessagesYyy methods to xxxLogRecXyy names. Also add addLogRec(String) and addLogRec(String, State) as the generic logging methods. bug: 5678189 Change-Id: I22f66d11828bfd70498db625fe1be728b90478b7 --- services/java/com/android/server/NsdService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index cc8e6a4b2d..193e80cdf1 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -109,8 +109,8 @@ public class NsdService extends INsdManager.Stub { private final EnabledState mEnabledState = new EnabledState(); @Override - protected String getMessageInfo(Message msg) { - return cmdToString(msg.what); + protected String getWhatToString(int what) { + return cmdToString(what); } NsdStateMachine(String name) { @@ -123,7 +123,7 @@ public class NsdService extends INsdManager.Stub { } else { setInitialState(mDisabledState); } - setProcessedMessagesSize(25); + setLogRecSize(25); } class DefaultState extends State { From 67c80edfab8812be65a410143ea19e4529411122 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Fri, 1 Jun 2012 16:44:13 -0700 Subject: [PATCH 0157/1150] Add contentobserver for nsd_on setting Bug: 6606274 Change-Id: I863b9e2a2446d697f3c9c49f24dcdc2b599f091e --- .../java/com/android/server/NsdService.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index cc8e6a4b2d..6ad8bd0374 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.net.nsd.NsdServiceInfo; import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; @@ -113,6 +114,26 @@ public class NsdService extends INsdManager.Stub { return cmdToString(msg.what); } + /** + * Observes the NSD on/off setting, and takes action when changed. + */ + private void registerForNsdSetting() { + ContentObserver contentObserver = new ContentObserver(this.getHandler()) { + @Override + public void onChange(boolean selfChange) { + if (isNsdEnabled()) { + mNsdStateMachine.sendMessage(NsdManager.ENABLE); + } else { + mNsdStateMachine.sendMessage(NsdManager.DISABLE); + } + } + }; + + mContext.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.NSD_ON), + false, contentObserver); + } + NsdStateMachine(String name) { super(name); addState(mDefaultState); @@ -124,6 +145,7 @@ public class NsdService extends INsdManager.Stub { setInitialState(mDisabledState); } setProcessedMessagesSize(25); + registerForNsdSetting(); } class DefaultState extends State { From 610bc9678d5a1aad7e8a9e9f0acfb448777a6279 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 5 Jun 2012 11:48:40 -0700 Subject: [PATCH 0158/1150] Fix a sync problem in NativeDaemonConnector. We had a gap in sync coverage between doing a check and waiting and a matching gap between setting a condition and notifying. It was possible to get context switched just so and have the notify hit before the waiter had started waiting. bug:6492166 Change-Id: Idc876cf85b35902a79fae932547957ed5ef00e4f --- .../android/server/NativeDaemonConnector.java | 129 ++++++++++-------- 1 file changed, 69 insertions(+), 60 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index f71125a839..92af9a9e6a 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -35,6 +35,9 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.TimeUnit; import java.util.LinkedList; /** @@ -482,102 +485,108 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private static class ResponseQueue { - private static class Response { + private static class PendingCmd { public int cmdNum; - public LinkedList responses = new LinkedList(); + public BlockingQueue responses = + new ArrayBlockingQueue(10); public String request; - public Response(int c, String r) {cmdNum = c; request = r;} + + // The availableResponseCount member is used to track when we can remove this + // instance from the ResponseQueue. + // This is used under the protection of a sync of the mPendingCmds object. + // A positive value means we've had more writers retreive this object while + // a negative value means we've had more readers. When we've had an equal number + // (it goes to zero) we can remove this object from the mPendingCmds list. + // Note that we may have more responses for this command (and more readers + // coming), but that would result in a new PendingCmd instance being created + // and added with the same cmdNum. + // Also note that when this goes to zero it just means a parity of readers and + // writers have retrieved this object - not that they are done using it. The + // responses queue may well have more responses yet to be read or may get more + // responses added to it. But all those readers/writers have retreived and + // hold references to this instance already so it can be removed from + // mPendingCmds queue. + public int availableResponseCount; + public PendingCmd(int c, String r) {cmdNum = c; request = r;} } - private final LinkedList mResponses; + private final LinkedList mPendingCmds; private int mMaxCount; ResponseQueue(int maxCount) { - mResponses = new LinkedList(); + mPendingCmds = new LinkedList(); mMaxCount = maxCount; } public void add(int cmdNum, NativeDaemonEvent response) { - Response found = null; - synchronized (mResponses) { - for (Response r : mResponses) { - if (r.cmdNum == cmdNum) { - found = r; + PendingCmd found = null; + synchronized (mPendingCmds) { + for (PendingCmd pendingCmd : mPendingCmds) { + if (pendingCmd.cmdNum == cmdNum) { + found = pendingCmd; break; } } if (found == null) { // didn't find it - make sure our queue isn't too big before adding - // another.. - while (mResponses.size() >= mMaxCount) { + while (mPendingCmds.size() >= mMaxCount) { Slog.e("NativeDaemonConnector.ResponseQueue", - "more buffered than allowed: " + mResponses.size() + + "more buffered than allowed: " + mPendingCmds.size() + " >= " + mMaxCount); // let any waiter timeout waiting for this - Response r = mResponses.remove(); + PendingCmd pendingCmd = mPendingCmds.remove(); Slog.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + r.request + " (" + r.cmdNum + ")"); + "Removing request: " + pendingCmd.request + " (" + + pendingCmd.cmdNum + ")"); } - found = new Response(cmdNum, null); - mResponses.add(found); + found = new PendingCmd(cmdNum, null); + mPendingCmds.add(found); } - found.responses.add(response); - } - synchronized (found) { - found.notify(); + found.availableResponseCount++; + // if a matching remove call has already retrieved this we can remove this + // instance from our list + if (found.availableResponseCount == 0) mPendingCmds.remove(found); } + try { + found.responses.put(response); + } catch (InterruptedException e) { } } // note that the timeout does not count time in deep sleep. If you don't want // the device to sleep, hold a wakelock public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { - long endTime = SystemClock.uptimeMillis() + timeoutMs; - long nowTime; - Response found = null; - while (true) { - synchronized (mResponses) { - for (Response response : mResponses) { - if (response.cmdNum == cmdNum) { - found = response; - // how many response fragments are left - switch (response.responses.size()) { - case 0: // haven't got any - must wait - break; - case 1: // last one - remove this from the master list - mResponses.remove(response); // fall through - default: // take one and move on - response.request = origCmd; - return response.responses.remove(); - } - } - } - nowTime = SystemClock.uptimeMillis(); - if (endTime <= nowTime) { - Slog.e("NativeDaemonConnector.ResponseQueue", - "Timeout waiting for response"); - return null; - } - /* pre-allocate so we have something unique to wait on */ - if (found == null) { - found = new Response(cmdNum, origCmd); - mResponses.add(found); + PendingCmd found = null; + synchronized (mPendingCmds) { + for (PendingCmd pendingCmd : mPendingCmds) { + if (pendingCmd.cmdNum == cmdNum) { + found = pendingCmd; + break; } } - try { - synchronized (found) { - found.wait(endTime - nowTime); - } - } catch (InterruptedException e) { - // loop around to check if we're done or if it's time to stop waiting + if (found == null) { + found = new PendingCmd(cmdNum, origCmd); + mPendingCmds.add(found); } + found.availableResponseCount--; + // if a matching add call has already retrieved this we can remove this + // instance from our list + if (found.availableResponseCount == 0) mPendingCmds.remove(found); } + NativeDaemonEvent result = null; + try { + result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) {} + if (result == null) { + Slog.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); + } + return result; } public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Pending requests:"); - synchronized (mResponses) { - for (Response response : mResponses) { - pw.println(" Cmd " + response.cmdNum + " - " + response.request); + synchronized (mPendingCmds) { + for (PendingCmd pendingCmd : mPendingCmds) { + pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.request); } } } From 66f04e9ddb21e3a13029a1e6d9b3bb09ff044aa6 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 29 May 2012 12:40:46 -0700 Subject: [PATCH 0159/1150] Enhance StateMachine Quitting and logging support. DO NOT MERGE Make StateMachine#quit non-conditional and remove the need to process the SM_QUIT_CMD it is now private. Rename halting to onHalting. Add onQuitting Change the message specific logging to be more generic and change the xxxProcessedMessagesYyy methods to xxxLogRecXyy names. Also add addLogRec(String) and addLogRec(String, State) as the generic logging methods. bug: 5678189 Change-Id: I22f66d11828bfd70498db625fe1be728b90478b7 Conflicts: services/java/com/android/server/NsdService.java --- services/java/com/android/server/NsdService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 6ad8bd0374..87843d956a 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -110,8 +110,8 @@ public class NsdService extends INsdManager.Stub { private final EnabledState mEnabledState = new EnabledState(); @Override - protected String getMessageInfo(Message msg) { - return cmdToString(msg.what); + protected String getWhatToString(int what) { + return cmdToString(what); } /** @@ -144,7 +144,7 @@ public class NsdService extends INsdManager.Stub { } else { setInitialState(mDisabledState); } - setProcessedMessagesSize(25); + setLogRecSize(25); registerForNsdSetting(); } From 0dbcedeeceb39901ac773e17ac6a1aaada59a726 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 27 Jul 2012 17:35:32 -0700 Subject: [PATCH 0160/1150] API to adjust network stats. Enables system apps to correctly account network usage performed on behalf of another application. Bug: 6695246 Change-Id: I39e243afd57936b6b30157a6ca511a17b6c55c39 --- .../android/net/INetworkStatsService.aidl | 3 ++ core/java/android/net/TrafficStats.java | 28 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 8 ++++++ 3 files changed, 39 insertions(+) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b7b8731855..4d46334fb3 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -45,4 +45,7 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); + /** Adjust recorded network stats. */ + void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operationCount); + } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e437d2e347..b66c2fe5cf 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,6 +88,13 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + /** + * Default tag value for cloud messaging traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_CLOUD_MESSAGING = 0xFFFFFF04; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { @@ -246,6 +253,27 @@ public class TrafficStats { } } + /** + * Adjust network statistics for the given UID and tag by the requested + * amount. This can be used to correctly account network usage performed on + * behalf of another application. Values can be negative. + *

+ * Requires that caller holds + * {@link android.Manifest.permission#MODIFY_NETWORK_ACCOUNTING} permission. + * + * @see #setThreadStatsUid(int) + * @hide + */ + public static void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets, long operationCount) { + try { + getStatsService().adjustNetworkStats( + uid, tag, rxBytes, rxPackets, txBytes, txPackets, operationCount); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** {@hide} */ public static void closeQuietly(INetworkStatsSession session) { // TODO: move to NetworkStatsService once it exists diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index ba122ecdf2..373576bd8d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -695,6 +695,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); } + @Override + public void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operationCount) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + + // TODO: store adjusted network stats in separate data structure + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} From 6f5215d3bf74a9309b1e6cd9912b566cef96f775 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 31 Jul 2012 10:58:38 -0700 Subject: [PATCH 0161/1150] Revert "am a21a6075: Reconcile with jb-mr1-release" This reverts commit 27a2c8495816553cbbf120af8096b9e9f01ed11c, reversing changes made to 905272a439b396161a1e2368fa49e1747cb24143. --- .../android/net/INetworkStatsService.aidl | 3 ++ core/java/android/net/TrafficStats.java | 28 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 8 ++++++ 3 files changed, 39 insertions(+) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b7b8731855..4d46334fb3 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -45,4 +45,7 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); + /** Adjust recorded network stats. */ + void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operationCount); + } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e437d2e347..b66c2fe5cf 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,6 +88,13 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + /** + * Default tag value for cloud messaging traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_CLOUD_MESSAGING = 0xFFFFFF04; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { @@ -246,6 +253,27 @@ public class TrafficStats { } } + /** + * Adjust network statistics for the given UID and tag by the requested + * amount. This can be used to correctly account network usage performed on + * behalf of another application. Values can be negative. + *

+ * Requires that caller holds + * {@link android.Manifest.permission#MODIFY_NETWORK_ACCOUNTING} permission. + * + * @see #setThreadStatsUid(int) + * @hide + */ + public static void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets, long operationCount) { + try { + getStatsService().adjustNetworkStats( + uid, tag, rxBytes, rxPackets, txBytes, txPackets, operationCount); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** {@hide} */ public static void closeQuietly(INetworkStatsSession session) { // TODO: move to NetworkStatsService once it exists diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index ba122ecdf2..373576bd8d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -695,6 +695,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); } + @Override + public void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operationCount) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + + // TODO: store adjusted network stats in separate data structure + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} From 6615400fe836e8591bf70a0901209ae5214c3190 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 27 Jul 2012 17:35:32 -0700 Subject: [PATCH 0162/1150] API to adjust network stats. DO NOT MERGE. Enables system apps to correctly account network usage performed on behalf of another application. Bug: 6695246 Change-Id: I39e243afd57936b6b30157a6ca511a17b6c55c39 --- .../android/net/INetworkStatsService.aidl | 3 ++ core/java/android/net/TrafficStats.java | 28 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 8 ++++++ 3 files changed, 39 insertions(+) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b7b8731855..4d46334fb3 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -45,4 +45,7 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); + /** Adjust recorded network stats. */ + void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operationCount); + } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e437d2e347..b66c2fe5cf 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,6 +88,13 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + /** + * Default tag value for cloud messaging traffic. + * + * @hide + */ + public static final int TAG_SYSTEM_CLOUD_MESSAGING = 0xFFFFFF04; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { @@ -246,6 +253,27 @@ public class TrafficStats { } } + /** + * Adjust network statistics for the given UID and tag by the requested + * amount. This can be used to correctly account network usage performed on + * behalf of another application. Values can be negative. + *

+ * Requires that caller holds + * {@link android.Manifest.permission#MODIFY_NETWORK_ACCOUNTING} permission. + * + * @see #setThreadStatsUid(int) + * @hide + */ + public static void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, + long txBytes, long txPackets, long operationCount) { + try { + getStatsService().adjustNetworkStats( + uid, tag, rxBytes, rxPackets, txBytes, txPackets, operationCount); + } catch (RemoteException e) { + throw new RuntimeException(e); + } + } + /** {@hide} */ public static void closeQuietly(INetworkStatsSession session) { // TODO: move to NetworkStatsService once it exists diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index ba122ecdf2..373576bd8d 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -695,6 +695,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); } + @Override + public void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operationCount) { + mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + + // TODO: store adjusted network stats in separate data structure + } + /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} From e1cf73eb6949117df598f5ba5b26439058f8adb5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 31 Jul 2012 17:11:07 -0700 Subject: [PATCH 0163/1150] Revert "API to adjust network stats." --- .../android/net/INetworkStatsService.aidl | 3 -- core/java/android/net/TrafficStats.java | 28 ------------------- .../server/net/NetworkStatsService.java | 8 ------ 3 files changed, 39 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 4d46334fb3..b7b8731855 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -45,7 +45,4 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); - /** Adjust recorded network stats. */ - void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operationCount); - } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index b66c2fe5cf..e437d2e347 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -88,13 +88,6 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; - /** - * Default tag value for cloud messaging traffic. - * - * @hide - */ - public static final int TAG_SYSTEM_CLOUD_MESSAGING = 0xFFFFFF04; - private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { @@ -253,27 +246,6 @@ public class TrafficStats { } } - /** - * Adjust network statistics for the given UID and tag by the requested - * amount. This can be used to correctly account network usage performed on - * behalf of another application. Values can be negative. - *

- * Requires that caller holds - * {@link android.Manifest.permission#MODIFY_NETWORK_ACCOUNTING} permission. - * - * @see #setThreadStatsUid(int) - * @hide - */ - public static void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operationCount) { - try { - getStatsService().adjustNetworkStats( - uid, tag, rxBytes, rxPackets, txBytes, txPackets, operationCount); - } catch (RemoteException e) { - throw new RuntimeException(e); - } - } - /** {@hide} */ public static void closeQuietly(INetworkStatsSession session) { // TODO: move to NetworkStatsService once it exists diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 373576bd8d..ba122ecdf2 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -695,14 +695,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); } - @Override - public void adjustNetworkStats(int uid, int tag, long rxBytes, long rxPackets, long txBytes, - long txPackets, long operationCount) { - mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); - - // TODO: store adjusted network stats in separate data structure - } - /** * Receiver that watches for {@link IConnectivityManager} to claim network * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} From 3dfb8b498a6952c6dcadacc4edac5565de718e4c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 31 Jul 2012 17:54:35 -0700 Subject: [PATCH 0164/1150] Make AtomicFile a public API. It's about time! Change-Id: Ib34e294747405b7ab709cb0bbb2d9a0cc80ce86a --- .../java/com/android/server/net/NetworkStatsCollection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 9ddf011069..60666b47a4 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -29,8 +29,8 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.text.format.DateUtils; +import android.util.AtomicFile; -import com.android.internal.os.AtomicFile; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Objects; From 0066733be0c6d04623f75869f8fe68a275257ee2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 5 Aug 2012 14:29:23 -0700 Subject: [PATCH 0165/1150] Make generic BaseNetworkObserver. This makes it easier to add new INetworkManagementEventObserver events in future. Change-Id: I432263d745558de4b878f313c1951230ed9db2b1 --- services/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index ba122ecdf2..ffe2a3d4a1 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -763,7 +763,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Observer that watches for {@link INetworkManagementService} alerts. */ - private INetworkManagementEventObserver mAlertObserver = new NetworkAlertObserver() { + private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us From 6ce481864a9b65a886b860a919e122c599d76c51 Mon Sep 17 00:00:00 2001 From: Vairavan Srinivasan Date: Sun, 5 Aug 2012 13:14:12 -0700 Subject: [PATCH 0166/1150] NsdService: Clear client info after resolution request is serviced. Currently, the client requests tracked in mClientIds for resolution requests isn't cleared at all and causes failues of additional registration and discovery requests once the number of requests reaches MAX_LIMIT. In addition, bubble up unhandled native events to default state of nsd state machine. Change-Id: Ief14e0fff644aa2698fcddd71f538820f802be58 --- .../java/com/android/server/NsdService.java | 252 +++++++++--------- 1 file changed, 129 insertions(+), 123 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 87843d956a..3c1f462f93 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -388,8 +388,10 @@ public class NsdService extends INsdManager.Stub { break; case NsdManager.NATIVE_DAEMON_EVENT: NativeEvent event = (NativeEvent) msg.obj; - handleNativeEvent(event.code, event.raw, - NativeDaemonEvent.unescapeArgs(event.raw)); + if (!handleNativeEvent(event.code, event.raw, + NativeDaemonEvent.unescapeArgs(event.raw))) { + result = NOT_HANDLED; + } break; default: result = NOT_HANDLED; @@ -397,6 +399,127 @@ public class NsdService extends INsdManager.Stub { } return result; } + + private boolean handleNativeEvent(int code, String raw, String[] cooked) { + boolean handled = true; + NsdServiceInfo servInfo; + int id = Integer.parseInt(cooked[1]); + ClientInfo clientInfo = mIdToClientInfoMap.get(id); + if (clientInfo == null) { + Slog.e(TAG, "Unique id with no client mapping: " + id); + handled = false; + return handled; + } + + /* This goes in response as msg.arg2 */ + int clientId = -1; + int keyId = clientInfo.mClientIds.indexOfValue(id); + if (keyId != -1) { + clientId = clientInfo.mClientIds.keyAt(keyId); + } + switch (code) { + case NativeResponseCode.SERVICE_FOUND: + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, + clientId, servInfo); + break; + case NativeResponseCode.SERVICE_LOST: + /* NNN uniqueId serviceName regType domain */ + if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, + clientId, servInfo); + break; + case NativeResponseCode.SERVICE_DISCOVERY_FAILED: + /* NNN uniqueId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_REGISTERED: + /* NNN regId serviceName regType */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); + servInfo = new NsdServiceInfo(cooked[2], null, null); + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, + id, clientId, servInfo); + break; + case NativeResponseCode.SERVICE_REGISTRATION_FAILED: + /* NNN regId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_UPDATED: + /* NNN regId */ + break; + case NativeResponseCode.SERVICE_UPDATE_FAILED: + /* NNN regId errorCode */ + break; + case NativeResponseCode.SERVICE_RESOLVED: + /* NNN resolveId fullName hostName port txtlen txtdata */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); + int index = cooked[2].indexOf("."); + if (index == -1) { + Slog.e(TAG, "Invalid service found " + raw); + break; + } + String name = cooked[2].substring(0, index); + String rest = cooked[2].substring(index); + String type = rest.replace(".local.", ""); + + clientInfo.mResolvedService.setServiceName(name); + clientInfo.mResolvedService.setServiceType(type); + clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); + + stopResolveService(id); + if (!getAddrInfo(id, cooked[3])) { + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + removeRequestMap(clientId, id, clientInfo); + clientInfo.mResolvedService = null; + } + break; + case NativeResponseCode.SERVICE_RESOLUTION_FAILED: + /* NNN resolveId errorCode */ + if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); + stopResolveService(id); + removeRequestMap(clientId, id, clientInfo); + clientInfo.mResolvedService = null; + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_GET_ADDR_FAILED: + /* NNN resolveId errorCode */ + stopGetAddrInfo(id); + removeRequestMap(clientId, id, clientInfo); + clientInfo.mResolvedService = null; + if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + break; + case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: + /* NNN resolveId hostname ttl addr */ + if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw); + try { + clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, + 0, clientId, clientInfo.mResolvedService); + } catch (java.net.UnknownHostException e) { + clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, + NsdManager.FAILURE_INTERNAL_ERROR, clientId); + } + stopGetAddrInfo(id); + removeRequestMap(clientId, id, clientInfo); + clientInfo.mResolvedService = null; + break; + default: + handled = false; + break; + } + return handled; + } } } @@ -482,8 +605,8 @@ public class NsdService extends INsdManager.Stub { } private class NativeEvent { - int code; - String raw; + final int code; + final String raw; NativeEvent(int code, String raw) { this.code = code; @@ -505,123 +628,6 @@ public class NsdService extends INsdManager.Stub { } } - private void handleNativeEvent(int code, String raw, String[] cooked) { - NsdServiceInfo servInfo; - int id = Integer.parseInt(cooked[1]); - ClientInfo clientInfo = mIdToClientInfoMap.get(id); - if (clientInfo == null) { - Slog.e(TAG, "Unique id with no client mapping: " + id); - return; - } - - /* This goes in response as msg.arg2 */ - int clientId = -1; - int keyId = clientInfo.mClientIds.indexOfValue(id); - if (keyId != -1) { - clientId = clientInfo.mClientIds.keyAt(keyId); - } - switch (code) { - case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain */ - if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, - clientId, servInfo); - break; - case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain */ - if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, - clientId, servInfo); - break; - case NativeResponseCode.SERVICE_DISCOVERY_FAILED: - /* NNN uniqueId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw); - clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - break; - case NativeResponseCode.SERVICE_REGISTERED: - /* NNN regId serviceName regType */ - if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], null, null); - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, - id, clientId, servInfo); - break; - case NativeResponseCode.SERVICE_REGISTRATION_FAILED: - /* NNN regId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw); - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - break; - case NativeResponseCode.SERVICE_UPDATED: - /* NNN regId */ - break; - case NativeResponseCode.SERVICE_UPDATE_FAILED: - /* NNN regId errorCode */ - break; - case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata */ - if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); - int index = cooked[2].indexOf("."); - if (index == -1) { - Slog.e(TAG, "Invalid service found " + raw); - break; - } - String name = cooked[2].substring(0, index); - String rest = cooked[2].substring(index); - String type = rest.replace(".local.", ""); - - clientInfo.mResolvedService.setServiceName(name); - clientInfo.mResolvedService.setServiceType(type); - clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); - - stopResolveService(id); - if (!getAddrInfo(id, cooked[3])) { - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - mIdToClientInfoMap.remove(id); - clientInfo.mResolvedService = null; - } - break; - case NativeResponseCode.SERVICE_RESOLUTION_FAILED: - /* NNN resolveId errorCode */ - if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); - stopResolveService(id); - mIdToClientInfoMap.remove(id); - clientInfo.mResolvedService = null; - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - break; - case NativeResponseCode.SERVICE_GET_ADDR_FAILED: - /* NNN resolveId errorCode */ - stopGetAddrInfo(id); - mIdToClientInfoMap.remove(id); - clientInfo.mResolvedService = null; - if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw); - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - break; - case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr */ - if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw); - try { - clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, - 0, clientId, clientInfo.mResolvedService); - } catch (java.net.UnknownHostException e) { - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); - } - stopGetAddrInfo(id); - mIdToClientInfoMap.remove(id); - clientInfo.mResolvedService = null; - break; - default: - break; - } - } - private boolean startMDnsDaemon() { if (DBG) Slog.d(TAG, "startMDnsDaemon"); try { @@ -800,8 +806,8 @@ public class NsdService extends INsdManager.Stub { private class ClientInfo { private static final int MAX_LIMIT = 10; - private AsyncChannel mChannel; - private Messenger mMessenger; + private final AsyncChannel mChannel; + private final Messenger mMessenger; /* Remembers a resolved service until getaddrinfo completes */ private NsdServiceInfo mResolvedService; From 692107e8276cd387100b9f2cf91206ef71fee731 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 29 Aug 2012 18:32:08 -0700 Subject: [PATCH 0167/1150] Improve multi-user broadcasts. You can now use ALL and CURRENT when sending broadcasts, to specify where the broadcast goes. Sticky broadcasts are now correctly separated per user, and registered receivers are filtered based on the requested target user. New Context APIs for more kinds of sending broadcasts as users. Updating a bunch of system code that sends broadcasts to explicitly specify which user the broadcast goes to. Made a single version of the code for interpreting the requested target user ID that all entries to activity manager (start activity, send broadcast, start service) use. Change-Id: Ie29f02dd5242ef8c8fa56c54593a315cd2574e1c --- services/java/com/android/server/NsdService.java | 3 ++- services/java/com/android/server/net/NetworkStatsService.java | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 87843d956a..2a7a2eb687 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -31,6 +31,7 @@ import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; import android.os.IBinder; +import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; import android.util.SparseArray; @@ -448,7 +449,7 @@ public class NsdService extends INsdManager.Stub { } else { intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED); } - mContext.sendStickyBroadcast(intent); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } private boolean isNsdEnabled() { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index ffe2a3d4a1..f2d2fb7fb5 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -99,6 +99,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Secure; import android.telephony.PhoneStateListener; @@ -989,7 +990,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcast(updatedIntent, READ_NETWORK_USAGE_HISTORY); + mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, + READ_NETWORK_USAGE_HISTORY); } /** From 633746dc751f2a0a9d4a7466eaeb51f9b5449fb0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 14 Sep 2012 13:09:57 -0700 Subject: [PATCH 0168/1150] Move to Global.NETSTATS and Global.NTP constants. Bug: 7157464 Change-Id: Ief10fd37940f62420f5684940994c9f93802e0be --- .../server/net/NetworkStatsService.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f2d2fb7fb5..bd52f035c1 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -38,23 +38,23 @@ import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; -import static android.provider.Settings.Secure.NETSTATS_DEV_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_DEV_DELETE_AGE; -import static android.provider.Settings.Secure.NETSTATS_DEV_PERSIST_BYTES; -import static android.provider.Settings.Secure.NETSTATS_DEV_ROTATE_AGE; -import static android.provider.Settings.Secure.NETSTATS_GLOBAL_ALERT_BYTES; -import static android.provider.Settings.Secure.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Secure.NETSTATS_REPORT_XT_OVER_DEV; -import static android.provider.Settings.Secure.NETSTATS_SAMPLE_ENABLED; -import static android.provider.Settings.Secure.NETSTATS_TIME_CACHE_MAX_AGE; -import static android.provider.Settings.Secure.NETSTATS_UID_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_UID_DELETE_AGE; -import static android.provider.Settings.Secure.NETSTATS_UID_PERSIST_BYTES; -import static android.provider.Settings.Secure.NETSTATS_UID_ROTATE_AGE; -import static android.provider.Settings.Secure.NETSTATS_UID_TAG_BUCKET_DURATION; -import static android.provider.Settings.Secure.NETSTATS_UID_TAG_DELETE_AGE; -import static android.provider.Settings.Secure.NETSTATS_UID_TAG_PERSIST_BYTES; -import static android.provider.Settings.Secure.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; +import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; +import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; +import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE; +import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES; +import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL; +import static android.provider.Settings.Global.NETSTATS_REPORT_XT_OVER_DEV; +import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED; +import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE; +import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION; +import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE; +import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES; +import static android.provider.Settings.Global.NETSTATS_UID_ROTATE_AGE; +import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; +import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; +import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; +import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; From 77127d1c9311eba8fefdeff66e261f2329ccbf7c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 14 Sep 2012 13:47:51 -0700 Subject: [PATCH 0169/1150] Actually move to Global settings. Also add better ConnectivityService logging. Bug: 7157464 Change-Id: Ia235a7e62ed809240913c4782920c1410c7d597d --- .../server/net/NetworkStatsService.java | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index bd52f035c1..3a593e4558 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -1218,39 +1218,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: adjust these timings for production builds } - private long getSecureLong(String name, long def) { - return Settings.Secure.getLong(mResolver, name, def); + private long getGlobalLong(String name, long def) { + return Settings.Global.getLong(mResolver, name, def); } - private boolean getSecureBoolean(String name, boolean def) { + private boolean getGlobalBoolean(String name, boolean def) { final int defInt = def ? 1 : 0; - return Settings.Secure.getInt(mResolver, name, defInt) != 0; + return Settings.Global.getInt(mResolver, name, defInt) != 0; } @Override public long getPollInterval() { - return getSecureLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); + return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } @Override public long getTimeCacheMaxAge() { - return getSecureLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); + return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); } @Override public long getGlobalAlertBytes(long def) { - return getSecureLong(NETSTATS_GLOBAL_ALERT_BYTES, def); + return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } @Override public boolean getSampleEnabled() { - return getSecureBoolean(NETSTATS_SAMPLE_ENABLED, true); + return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true); } @Override public boolean getReportXtOverDev() { - return getSecureBoolean(NETSTATS_REPORT_XT_OVER_DEV, true); + return getGlobalBoolean(NETSTATS_REPORT_XT_OVER_DEV, true); } @Override public Config getDevConfig() { - return new Config(getSecureLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), - getSecureLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), - getSecureLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); + return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), + getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), + getGlobalLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); } @Override public Config getXtConfig() { @@ -1258,19 +1258,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override public Config getUidConfig() { - return new Config(getSecureLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getSecureLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS), - getSecureLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); + return new Config(getGlobalLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), + getGlobalLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS), + getGlobalLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); } @Override public Config getUidTagConfig() { - return new Config(getSecureLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getSecureLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS), - getSecureLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS)); + return new Config(getGlobalLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), + getGlobalLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS), + getGlobalLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS)); } @Override public long getDevPersistBytes(long def) { - return getSecureLong(NETSTATS_DEV_PERSIST_BYTES, def); + return getGlobalLong(NETSTATS_DEV_PERSIST_BYTES, def); } @Override public long getXtPersistBytes(long def) { @@ -1278,11 +1278,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override public long getUidPersistBytes(long def) { - return getSecureLong(NETSTATS_UID_PERSIST_BYTES, def); + return getGlobalLong(NETSTATS_UID_PERSIST_BYTES, def); } @Override public long getUidTagPersistBytes(long def) { - return getSecureLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); + return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); } } } From 8c8309a6fe6903e2db95c144d068ab28cc600032 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 19 Sep 2012 14:10:39 -0700 Subject: [PATCH 0170/1150] Migrate network stats from removed users. When a user is removed, migrate all network stats belonging to that user into special UID_REMOVED bucket. Also removes those stats from kernel to avoid double-counting if another user is created. Bug: 7194784 Change-Id: I03f1d660fe3754566326b7749cae8068fc224ea9 --- core/java/android/net/NetworkStats.java | 5 +- .../server/net/NetworkStatsCollection.java | 5 +- .../server/net/NetworkStatsRecorder.java | 27 ++++--- .../server/net/NetworkStatsService.java | 71 ++++++++++++++++--- 4 files changed, 85 insertions(+), 23 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index fb7a4f8ad2..446bbf0509 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.SparseBooleanArray; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.Objects; import java.io.CharArrayWriter; @@ -608,13 +609,13 @@ public class NetworkStats implements Parcelable { * Return all rows except those attributed to the requested UID; doesn't * mutate the original structure. */ - public NetworkStats withoutUid(int uid) { + public NetworkStats withoutUids(int[] uids) { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); Entry entry = new Entry(); for (int i = 0; i < size; i++) { entry = getValues(i, entry); - if (entry.uid != uid) { + if (!ArrayUtils.contains(uids, entry.uid)) { stats.addValues(entry); } } diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 60666b47a4..3169035786 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -31,6 +31,7 @@ import android.net.TrafficStats; import android.text.format.DateUtils; import android.util.AtomicFile; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Objects; @@ -431,13 +432,13 @@ public class NetworkStatsCollection implements FileRotator.Reader { * moving any {@link NetworkStats#TAG_NONE} series to * {@link TrafficStats#UID_REMOVED}. */ - public void removeUid(int uid) { + public void removeUids(int[] uids) { final ArrayList knownKeys = Lists.newArrayList(); knownKeys.addAll(mStats.keySet()); // migrate all UID stats into special "removed" bucket for (Key key : knownKeys) { - if (key.uid == uid) { + if (ArrayUtils.contains(uids, key.uid)) { // only migrate combined TAG_NONE history if (key.tag == TAG_NONE) { final NetworkStatsHistory uidHistory = mStats.get(key); diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index c3ecf54951..2b32b41506 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -42,6 +42,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.ref.WeakReference; +import java.util.Arrays; import java.util.HashSet; import java.util.Map; @@ -233,23 +234,27 @@ public class NetworkStatsRecorder { * Remove the given UID from all {@link FileRotator} history, migrating it * to {@link TrafficStats#UID_REMOVED}. */ - public void removeUidLocked(int uid) { + public void removeUidsLocked(int[] uids) { try { - // process all existing data to migrate uid - mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uid)); + // Rewrite all persisted data to migrate UID stats + mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); } catch (IOException e) { - Log.wtf(TAG, "problem removing UID " + uid, e); + Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); recoverFromWtf(); } - // clear UID from current stats snapshot + // Remove any pending stats + mPending.removeUids(uids); + mSinceBoot.removeUids(uids); + + // Clear UID from current stats snapshot if (mLastSnapshot != null) { - mLastSnapshot = mLastSnapshot.withoutUid(uid); + mLastSnapshot = mLastSnapshot.withoutUids(uids); } final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; if (complete != null) { - complete.removeUid(uid); + complete.removeUids(uids); } } @@ -293,11 +298,11 @@ public class NetworkStatsRecorder { */ public static class RemoveUidRewriter implements FileRotator.Rewriter { private final NetworkStatsCollection mTemp; - private final int mUid; + private final int[] mUids; - public RemoveUidRewriter(long bucketDuration, int uid) { + public RemoveUidRewriter(long bucketDuration, int[] uids) { mTemp = new NetworkStatsCollection(bucketDuration); - mUid = uid; + mUids = uids; } @Override @@ -309,7 +314,7 @@ public class NetworkStatsRecorder { public void read(InputStream in) throws IOException { mTemp.read(in); mTemp.clearDirty(); - mTemp.removeUid(mUid); + mTemp.removeUids(mUids); } @Override diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 3a593e4558..f2748a3058 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -23,6 +23,7 @@ import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; +import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; @@ -76,6 +77,8 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; @@ -112,6 +115,7 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; @@ -122,8 +126,10 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; +import java.util.List; /** * Collect and persist detailed network statistics, and provide this data to @@ -322,6 +328,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final IntentFilter removedFilter = new IntentFilter(ACTION_UID_REMOVED); mContext.registerReceiver(mRemovedReceiver, removedFilter, null, mHandler); + // listen for user changes to clean stats + final IntentFilter userFilter = new IntentFilter(ACTION_USER_REMOVED); + mContext.registerReceiver(mUserReceiver, userFilter, null, mHandler); + // persist stats during clean shutdown final IntentFilter shutdownFilter = new IntentFilter(ACTION_SHUTDOWN); mContext.registerReceiver(mShutdownReceiver, shutdownFilter); @@ -739,11 +749,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void onReceive(Context context, Intent intent) { // on background handler thread, and UID_REMOVED is protected // broadcast. - final int uid = intent.getIntExtra(EXTRA_UID, 0); + + final int uid = intent.getIntExtra(EXTRA_UID, -1); + if (uid == -1) return; + synchronized (mStatsLock) { mWakeLock.acquire(); try { - removeUidLocked(uid); + removeUidsLocked(uid); + } finally { + mWakeLock.release(); + } + } + } + }; + + private BroadcastReceiver mUserReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // On background handler thread, and USER_REMOVED is protected + // broadcast. + + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + if (userId == -1) return; + + synchronized (mStatsLock) { + mWakeLock.acquire(); + try { + removeUserLocked(userId); } finally { mWakeLock.release(); } @@ -1034,15 +1067,37 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Clean up {@link #mUidRecorder} after UID is removed. */ - private void removeUidLocked(int uid) { - // perform one last poll before removing + private void removeUidsLocked(int... uids) { + if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); + + // Perform one last poll before removing performPollLocked(FLAG_PERSIST_ALL); - mUidRecorder.removeUidLocked(uid); - mUidTagRecorder.removeUidLocked(uid); + mUidRecorder.removeUidsLocked(uids); + mUidTagRecorder.removeUidsLocked(uids); - // clear kernel stats associated with UID - resetKernelUidStats(uid); + // Clear kernel stats associated with UID + for (int uid : uids) { + resetKernelUidStats(uid); + } + } + + /** + * Clean up {@link #mUidRecorder} after user is removed. + */ + private void removeUserLocked(int userId) { + if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId); + + // Build list of UIDs that we should clean up + int[] uids = new int[0]; + final List apps = mContext.getPackageManager().getInstalledApplications( + PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS); + for (ApplicationInfo app : apps) { + final int uid = UserHandle.getUid(userId, app.uid); + uids = ArrayUtils.appendInt(uids, uid); + } + + removeUidsLocked(uids); } @Override From c783695df225aaf87383991669c74e0f77df27c4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 26 Sep 2012 22:03:49 -0700 Subject: [PATCH 0171/1150] Migrate more Secure settings to Global. Migrate networking, storage, battery, DropBox, and PackageManager related Secure settings to Global table. Bug: 7232014, 7231331, 7231198 Change-Id: I772c2a9586a2f708c9db95622477f235064b8f4d --- services/java/com/android/server/NsdService.java | 6 +++--- .../java/com/android/server/net/NetworkStatsService.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 2a7a2eb687..1b9742cae6 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -131,7 +131,7 @@ public class NsdService extends INsdManager.Stub { }; mContext.getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.NSD_ON), + Settings.Global.getUriFor(Settings.Global.NSD_ON), false, contentObserver); } @@ -433,7 +433,7 @@ public class NsdService extends INsdManager.Stub { public void setEnabled(boolean enable) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL, "NsdService"); - Settings.Secure.putInt(mContentResolver, Settings.Secure.NSD_ON, enable ? 1 : 0); + Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0); if (enable) { mNsdStateMachine.sendMessage(NsdManager.ENABLE); } else { @@ -453,7 +453,7 @@ public class NsdService extends INsdManager.Stub { } private boolean isNsdEnabled() { - boolean ret = Settings.Secure.getInt(mContentResolver, Settings.Secure.NSD_ON, 1) == 1; + boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1; if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret); return ret; } diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index f2748a3058..0efdead7f9 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -104,7 +104,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; -import android.provider.Settings.Secure; +import android.provider.Settings.Global; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.util.EventLog; @@ -696,7 +696,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to * reflect current {@link #mPersistThreshold} value. Always defers to - * {@link Secure} values when defined. + * {@link Global} values when defined. */ private void updatePersistThresholds() { mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); @@ -1263,7 +1263,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Default external settings that read from - * {@link android.provider.Settings.Secure}. + * {@link android.provider.Settings.Global}. */ private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { private final ContentResolver mResolver; From 0f1fea45d3871e358b621920593578f88bc7ed57 Mon Sep 17 00:00:00 2001 From: You Kim Date: Sun, 28 Oct 2012 22:13:48 +0900 Subject: [PATCH 0172/1150] return value of String.replace() is ignored. Change-Id: Id7330e1ffc9f429b22f153d8e644fa7c64354173 Signed-off-by: You Kim --- services/java/com/android/server/NativeDaemonEvent.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/java/com/android/server/NativeDaemonEvent.java index f11ae1d391..209515279b 100644 --- a/services/java/com/android/server/NativeDaemonEvent.java +++ b/services/java/com/android/server/NativeDaemonEvent.java @@ -223,8 +223,8 @@ public class NativeDaemonEvent { current++; // skip the trailing quote } // unescape stuff within the word - word.replace("\\\\", "\\"); - word.replace("\\\"", "\""); + word = word.replace("\\\\", "\\"); + word = word.replace("\\\"", "\""); if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'"); parsed.add(word); From 3a8abe7eec556e5626422ec583a0bb4d9f185329 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Nov 2012 14:48:20 -0700 Subject: [PATCH 0173/1150] Sanity check network stats coming from disk. Throw early when structure is unstable, which allows the normal recoverFromWtf() path to recover automatically. Bug: 7440485 Change-Id: Ic150d17daac4de7c9ff3489025403a9b485b4620 --- core/java/android/net/NetworkStatsHistory.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a37c26f90d..382b25e377 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -177,6 +177,12 @@ public class NetworkStatsHistory implements Parcelable { throw new ProtocolException("unexpected version: " + version); } } + + if (bucketStart.length != bucketCount || rxBytes.length != bucketCount + || rxPackets.length != bucketCount || txBytes.length != bucketCount + || txPackets.length != bucketCount || operations.length != bucketCount) { + throw new ProtocolException("Mismatched history lengths"); + } } public void writeToStream(DataOutputStream out) throws IOException { From 526438dbe665b85f8da49beb70b9366f09b9b477 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 12 Nov 2012 11:45:05 -0800 Subject: [PATCH 0174/1150] Useful annotations for code documentation. Bug: 6537978 Change-Id: I806c3c09e3255f8789455f13bf37c1dde2a93f1f --- core/java/android/net/NetworkStats.java | 9 +++++---- core/java/android/net/NetworkTemplate.java | 3 ++- .../com/android/internal/net/NetworkStatsFactory.java | 3 ++- .../java/com/android/server/NativeDaemonConnector.java | 3 ++- .../java/com/android/server/net/NetworkStatsService.java | 3 ++- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 446bbf0509..c7576057e1 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.os.Parcelable; import android.os.SystemClock; import android.util.SparseBooleanArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.Objects; @@ -190,14 +191,14 @@ public class NetworkStats implements Parcelable { return clone; } - // @VisibleForTesting + @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { return addValues( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } - // @VisibleForTesting + @VisibleForTesting public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( @@ -269,7 +270,7 @@ public class NetworkStats implements Parcelable { return size; } - // @VisibleForTesting + @VisibleForTesting public int internalSize() { return iface.length; } @@ -335,7 +336,7 @@ public class NetworkStats implements Parcelable { * Find first stats index that matches the requested parameters, starting * search around the hinted index as an optimization. */ - // @VisibleForTesting + @VisibleForTesting public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d8e53d523f..d3839ad435 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -33,6 +33,7 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Objects; /** @@ -63,7 +64,7 @@ public class NetworkTemplate implements Parcelable { private static boolean sForceAllNetworkTypes = false; - // @VisibleForTesting + @VisibleForTesting public static void forceAllNetworkTypes() { sForceAllNetworkTypes = true; } diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8b222f02a3..c517a68e2b 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -25,6 +25,7 @@ import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ProcFileReader; import java.io.File; @@ -53,7 +54,7 @@ public class NetworkStatsFactory { this(new File("/proc/")); } - // @VisibleForTesting + @VisibleForTesting public NetworkStatsFactory(File procRoot) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 92af9a9e6a..5e94a9fc76 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -25,6 +25,7 @@ import android.os.SystemClock; import android.util.LocalLog; import android.util.Slog; +import com.android.internal.annotations.VisibleForTesting; import com.google.android.collect.Lists; import java.nio.charset.Charsets; @@ -400,7 +401,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * Append the given argument to {@link StringBuilder}, escaping as needed, * and surrounding with quotes when it contains spaces. */ - // @VisibleForTesting + @VisibleForTesting static void appendEscaped(StringBuilder builder, String arg) { final boolean hasSpaces = arg.indexOf(' ') >= 0; if (hasSpaces) { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0efdead7f9..7101520e80 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -115,6 +115,7 @@ import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -165,7 +166,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private IConnectivityManager mConnManager; - // @VisibleForTesting + @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; public static final String ACTION_NETWORK_STATS_UPDATED = From 0e851c78e3badf8b64b47ce53710b096e84334fb Mon Sep 17 00:00:00 2001 From: Anders 3 Fridlund Date: Thu, 7 Jun 2012 11:24:10 +0200 Subject: [PATCH 0175/1150] Move NTP updates outside locks When the ServerThread handles ACTION_SHUTDOWN intent it sometimes get stuck on mStatsLock in NetworkStatsService.java. 0 com.android.server.net.NetworkStatsService$5.onReceive() 1 android.app.LoadedApk$ReceiverDispatcher$Args.run() 2 android.os.Handler.handleCallback() 3 android.os.Handler.dispatchMessage() 4 android.os.Looper.loop() 5 com.android.server.ServerThread.run() This happens when the NetworkStats thread is already holding the mStatsLock while updating NTP. 0 libcore.io.Posix.getaddrinfo() 1 libcore.io.ForwardingOs.getaddrinfo() 2 java.net.InetAddress.lookupHostByName() 3 java.net.InetAddress.getAllByNameImpl() 4 java.net.InetAddress.getByName() 5 android.net.SntpClient.requestTime() 6 android.util.NtpTrustedTime.forceRefresh() 7 com.android.server.net.NetworkStatsService.performPoll() 8 com.android.server.net.NetworkStatsService.access$100() 9 com.android.server.net.NetworkStatsService$2.onReceive() 10 android.app.LoadedApk$ReceiverDispatcher$Args.run() 11 android.os.Handler.handleCallback() 12 android.os.Handler.dispatchMessage() 13 android.os.Looper.loop() 14 android.os.HandlerThread.run() Since the NTP update consists of several socket operations it may get stuck long enough to trigger a System Server Watchdog even though the socket timeout is set to 20 second. Further, the NTP update doesn't actually need to be performed inside the locks and an attempt to change this was made earlier, but the code wasn't actually moved outside the locks. Change-Id: Ib37a2b8c2d51a01adb7ff01764f82309433703f0 --- .../com/android/server/net/NetworkStatsService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 0efdead7f9..a3b44e26d8 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -939,14 +939,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void performPoll(int flags) { + // try refreshing time source when stale + if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { + mTime.forceRefresh(); + } + synchronized (mStatsLock) { mWakeLock.acquire(); - // try refreshing time source when stale - if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { - mTime.forceRefresh(); - } - try { performPollLocked(flags); } finally { From 17ffba97001adae9366c2c6e2817ac68e90f7929 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 30 Nov 2012 17:49:39 -0800 Subject: [PATCH 0176/1150] Avoid null mobile interfaces. Bug: 7634215 Change-Id: I6745f6a78c07ba11d98b4562a6b53386112ef652 --- services/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 7101520e80..546f2be077 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -903,7 +903,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); // remember any ifaces associated with mobile networks - if (isNetworkTypeMobile(state.networkInfo.getType())) { + if (isNetworkTypeMobile(state.networkInfo.getType()) && iface != null) { if (!contains(mMobileIfaces, iface)) { mMobileIfaces = appendElement(String.class, mMobileIfaces, iface); } From 86230aca66f3fa0c62d1b24fe0ea330678d433a3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 18 Dec 2012 17:06:06 -0800 Subject: [PATCH 0177/1150] Fix metered SSID matching regression. WifiInfo changed to return SSIDs with quotes included, so relax our identity matching to accept matches regardless of quotedness. Bug: 7695807 Change-Id: Ib5d06666035e06b2d4b2f7cb498767d63b1b1828 --- core/java/android/net/NetworkTemplate.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d3839ad435..c189ba4cd6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -22,6 +22,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.scrubSubscriberId; +import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; @@ -279,7 +280,8 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equal(mNetworkId, ident.mNetworkId); + return Objects.equal( + removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); default: return false; } From 9e766ac16565d69e5dc451ad86e3a575eedf722a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 5 Feb 2013 21:32:33 -0800 Subject: [PATCH 0178/1150] Offer parsed TCP interface statistics. Also switch to newer iface_stat_fmt numbers, which are measured at XT level instead of dev. Bug: 7903145, 6569689 Change-Id: Ibeb742966b8c89916ea31a49388a5dbe25a5f67f --- core/java/android/net/TrafficStats.java | 26 +++++ core/jni/android_net_TrafficStats.cpp | 139 +++++++++++++----------- 2 files changed, 104 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e437d2e347..a014cec3fe 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -315,6 +315,30 @@ public class TrafficStats { return total; } + /** {@hide} */ + public static long getMobileTcpRxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + final long stat = nativeGetIfaceStat(iface, TYPE_TCP_RX_PACKETS); + if (stat != UNSUPPORTED) { + total += stat; + } + } + return total; + } + + /** {@hide} */ + public static long getMobileTcpTxPackets() { + long total = 0; + for (String iface : getMobileIfaces()) { + final long stat = nativeGetIfaceStat(iface, TYPE_TCP_TX_PACKETS); + if (stat != UNSUPPORTED) { + total += stat; + } + } + return total; + } + /** * Get the total number of packets transmitted through the specified interface. * @@ -587,6 +611,8 @@ public class TrafficStats { private static final int TYPE_RX_PACKETS = 1; private static final int TYPE_TX_BYTES = 2; private static final int TYPE_TX_PACKETS = 3; + private static final int TYPE_TCP_RX_PACKETS = 4; + private static final int TYPE_TCP_TX_PACKETS = 5; private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 325fe26041..aa8a58b483 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -31,8 +31,7 @@ namespace android { -static const uint64_t VALUE_UNKNOWN = -1; -static const char* IFACE_STAT_ALL = "/proc/net/xt_qtaguid/iface_stat_all"; +static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt"; enum Tx_Rx { TX, @@ -46,20 +45,45 @@ enum Tcp_Udp { }; // NOTE: keep these in sync with TrafficStats.java -enum IfaceStatType { +static const uint64_t UNKNOWN = -1; + +enum StatsType { RX_BYTES = 0, RX_PACKETS = 1, TX_BYTES = 2, - TX_PACKETS = 3 + TX_PACKETS = 3, + TCP_RX_PACKETS = 4, + TCP_TX_PACKETS = 5 }; -struct IfaceStat { +struct Stats { uint64_t rxBytes; uint64_t rxPackets; uint64_t txBytes; uint64_t txPackets; + uint64_t tcpRxPackets; + uint64_t tcpTxPackets; }; +static uint64_t getStatsType(struct Stats* stats, StatsType type) { + switch (type) { + case RX_BYTES: + return stats->rxBytes; + case RX_PACKETS: + return stats->rxPackets; + case TX_BYTES: + return stats->txBytes; + case TX_PACKETS: + return stats->txPackets; + case TCP_RX_PACKETS: + return stats->tcpRxPackets; + case TCP_TX_PACKETS: + return stats->tcpTxPackets; + default: + return UNKNOWN; + } +} + // Returns an ASCII decimal number read from the specified file, -1 on error. static jlong readNumber(char const* filename) { char buf[80]; @@ -81,79 +105,72 @@ static jlong readNumber(char const* filename) { return atoll(buf); } -static int parseIfaceStat(const char* iface, struct IfaceStat* stat) { - FILE *fp = fopen(IFACE_STAT_ALL, "r"); - if (!fp) { - return errno; +static int parseIfaceStats(const char* iface, struct Stats* stats) { + FILE *fp = fopen(QTAGUID_IFACE_STATS, "r"); + if (fp == NULL) { + return -1; } char buffer[256]; char cur_iface[32]; - int active; - uint64_t rxBytes, rxPackets, txBytes, txPackets, devRxBytes, devRxPackets, devTxBytes, - devTxPackets; + bool foundTcp = false; + uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets; - while (fgets(buffer, 256, fp) != NULL) { - if (sscanf(buffer, "%31s %d %llu %llu %llu %llu %llu %llu %llu %llu", cur_iface, &active, - &rxBytes, &rxPackets, &txBytes, &txPackets, &devRxBytes, &devRxPackets, - &devTxBytes, &devTxPackets) != 10) { - continue; - } - - if (!iface || !strcmp(iface, cur_iface)) { - stat->rxBytes += rxBytes; - stat->rxPackets += rxPackets; - stat->txBytes += txBytes; - stat->txPackets += txPackets; - - if (active) { - stat->rxBytes += devRxBytes; - stat->rxPackets += devRxPackets; - stat->txBytes += devTxBytes; - stat->txPackets += devTxPackets; + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + int matched = sscanf(buffer, "%31s %llu %llu %llu %llu " + "%*llu %llu %*llu %*llu %*llu %*llu " + "%*llu %llu %*llu %*llu %*llu %*llu", cur_iface, &rxBytes, + &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets); + if (matched >= 5) { + if (matched == 7) { + foundTcp = true; + } + if (!iface || !strcmp(iface, cur_iface)) { + stats->rxBytes += rxBytes; + stats->rxPackets += rxPackets; + stats->txBytes += txBytes; + stats->txPackets += txPackets; + if (matched == 7) { + stats->tcpRxPackets += tcpRxPackets; + stats->tcpTxPackets += tcpTxPackets; + } } } } - fclose(fp); + if (!foundTcp) { + stats->tcpRxPackets = UNKNOWN; + stats->tcpTxPackets = UNKNOWN; + } + + if (fclose(fp) != 0) { + return -1; + } return 0; } -static uint64_t getIfaceStatType(const char* iface, IfaceStatType type) { - struct IfaceStat stat; - memset(&stat, 0, sizeof(IfaceStat)); - - if (parseIfaceStat(iface, &stat)) { - return VALUE_UNKNOWN; - } - - switch (type) { - case RX_BYTES: - return stat.rxBytes; - case RX_PACKETS: - return stat.rxPackets; - case TX_BYTES: - return stat.txBytes; - case TX_PACKETS: - return stat.txPackets; - default: - return VALUE_UNKNOWN; - } -} - static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { - return getIfaceStatType(NULL, (IfaceStatType) type); + struct Stats stats; + memset(&stats, 0, sizeof(Stats)); + if (parseIfaceStats(NULL, &stats) == 0) { + return getStatsType(&stats, (StatsType) type); + } else { + return UNKNOWN; + } } static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { - struct IfaceStat stat; - const char* ifaceChars = env->GetStringUTFChars(iface, NULL); - if (ifaceChars) { - uint64_t stat = getIfaceStatType(ifaceChars, (IfaceStatType) type); - env->ReleaseStringUTFChars(iface, ifaceChars); - return stat; + ScopedUtfChars iface8(env, iface); + if (iface8.c_str() == NULL) { + return UNKNOWN; + } + + struct Stats stats; + memset(&stats, 0, sizeof(Stats)); + if (parseIfaceStats(NULL, &stats) == 0) { + return getStatsType(&stats, (StatsType) type); } else { - return VALUE_UNKNOWN; + return UNKNOWN; } } From 5fee2c9ee2071fde63019ba78f7fa4eb0a3a5bda Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 15 Jan 2013 17:25:09 -0800 Subject: [PATCH 0179/1150] Improve TrafficStats UID APIs. Deprecate transport layer statistics, leaving only the summarized network layer statistics. Improve documentation to be clear about layers where measurements occur, and their behavior since boot. Under the hood, move to using xt_qtaguid UID statistics. Bug: 6818637, 7013662 Change-Id: I9f26992e5fcdebd88c671e5765bd91229e7b0016 --- core/java/android/net/TrafficStats.java | 230 ++++++++++++------------ core/jni/android_net_TrafficStats.cpp | 219 ++++------------------ 2 files changed, 152 insertions(+), 297 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a014cec3fe..a2829109a4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -424,161 +424,156 @@ public class TrafficStats { } /** - * Get the number of bytes sent through the network for this UID. - * The statistics are across all interfaces. + * Return number of bytes transmitted by the given UID since device boot. + * Counts packets across all network interfaces, and always increases + * monotonically since device boot. Statistics are measured at the network + * layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * {@link #UNSUPPORTED} on devices where statistics aren't available. * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @see android.os.Process#myUid() + * @see android.content.pm.ApplicationInfo#uid */ - public static native long getUidTxBytes(int uid); + public static long getUidTxBytes(int uid) { + return nativeGetUidStat(uid, TYPE_TX_BYTES); + } /** - * Get the number of bytes received through the network for this UID. - * The statistics are across all interfaces. + * Return number of bytes received by the given UID since device boot. + * Counts packets across all network interfaces, and always increases + * monotonically since device boot. Statistics are measured at the network + * layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * {@link #UNSUPPORTED} on devices where statistics aren't available. * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes + * @see android.os.Process#myUid() + * @see android.content.pm.ApplicationInfo#uid */ - public static native long getUidRxBytes(int uid); + public static long getUidRxBytes(int uid) { + return nativeGetUidStat(uid, TYPE_RX_BYTES); + } /** - * Get the number of packets (TCP segments + UDP) sent through - * the network for this UID. - * The statistics are across all interfaces. + * Return number of packets transmitted by the given UID since device boot. + * Counts packets across all network interfaces, and always increases + * monotonically since device boot. Statistics are measured at the network + * layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * {@link #UNSUPPORTED} on devices where statistics aren't available. * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of packets. - * If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @see android.os.Process#myUid() + * @see android.content.pm.ApplicationInfo#uid */ - public static native long getUidTxPackets(int uid); + public static long getUidTxPackets(int uid) { + return nativeGetUidStat(uid, TYPE_TX_PACKETS); + } /** - * Get the number of packets (TCP segments + UDP) received through - * the network for this UID. - * The statistics are across all interfaces. + * Return number of packets received by the given UID since device boot. + * Counts packets across all network interfaces, and always increases + * monotonically since device boot. Statistics are measured at the network + * layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * {@link #UNSUPPORTED} on devices where statistics aren't available. * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of packets + * @see android.os.Process#myUid() + * @see android.content.pm.ApplicationInfo#uid */ - public static native long getUidRxPackets(int uid); + public static long getUidRxPackets(int uid) { + return nativeGetUidStat(uid, TYPE_RX_PACKETS); + } /** - * Get the number of TCP payload bytes sent for this UID. - * This total does not include protocol and control overheads at - * the transport and the lower layers of the networking stack. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidTxBytes(int) */ - public static native long getUidTcpTxBytes(int uid); + @Deprecated + public static long getUidTcpTxBytes(int uid) { + return UNSUPPORTED; + } /** - * Get the number of TCP payload bytes received for this UID. - * This total does not include protocol and control overheads at - * the transport and the lower layers of the networking stack. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidRxBytes(int) */ - public static native long getUidTcpRxBytes(int uid); + @Deprecated + public static long getUidTcpRxBytes(int uid) { + return UNSUPPORTED; + } /** - * Get the number of UDP payload bytes sent for this UID. - * This total does not include protocol and control overheads at - * the transport and the lower layers of the networking stack. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidTxBytes(int) */ - public static native long getUidUdpTxBytes(int uid); + @Deprecated + public static long getUidUdpTxBytes(int uid) { + return UNSUPPORTED; + } /** - * Get the number of UDP payload bytes received for this UID. - * This total does not include protocol and control overheads at - * the transport and the lower layers of the networking stack. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidRxBytes(int) */ - public static native long getUidUdpRxBytes(int uid); + @Deprecated + public static long getUidUdpRxBytes(int uid) { + return UNSUPPORTED; + } /** - * Get the number of TCP segments sent for this UID. - * Does not include TCP control packets (SYN/ACKs/FIN/..). - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of TCP segments. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidTxPackets(int) */ - public static native long getUidTcpTxSegments(int uid); + @Deprecated + public static long getUidTcpTxSegments(int uid) { + return UNSUPPORTED; + } /** - * Get the number of TCP segments received for this UID. - * Does not include TCP control packets (SYN/ACKs/FIN/..). - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of TCP segments. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidRxPackets(int) */ - public static native long getUidTcpRxSegments(int uid); + @Deprecated + public static long getUidTcpRxSegments(int uid) { + return UNSUPPORTED; + } /** - * Get the number of UDP packets sent for this UID. - * Includes DNS requests. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidTxPackets(int) */ - public static native long getUidUdpTxPackets(int uid); + @Deprecated + public static long getUidUdpTxPackets(int uid) { + return UNSUPPORTED; + } /** - * Get the number of UDP packets received for this UID. - * Includes DNS responses. - * The statistics are across all interfaces. - * - * {@see android.os.Process#myUid()}. - * - * @param uid The UID of the process to examine. - * @return number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * transport layer statistics are no longer available, and will + * always return {@link #UNSUPPORTED}. + * @see #getUidRxPackets(int) */ - public static native long getUidUdpRxPackets(int uid); + @Deprecated + public static long getUidUdpRxPackets(int uid) { + return UNSUPPORTED; + } /** * Return detailed {@link NetworkStats} for the current UID. Requires no @@ -616,4 +611,5 @@ public class TrafficStats { private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); + private static native long nativeGetUidStat(int uid, int type); } diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index aa8a58b483..bf963de691 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -32,17 +32,7 @@ namespace android { static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt"; - -enum Tx_Rx { - TX, - RX -}; - -enum Tcp_Udp { - TCP, - UDP, - TCP_AND_UDP -}; +static const char* QTAGUID_UID_STATS = "/proc/net/xt_qtaguid/stats"; // NOTE: keep these in sync with TrafficStats.java static const uint64_t UNKNOWN = -1; @@ -84,27 +74,6 @@ static uint64_t getStatsType(struct Stats* stats, StatsType type) { } } -// Returns an ASCII decimal number read from the specified file, -1 on error. -static jlong readNumber(char const* filename) { - char buf[80]; - int fd = open(filename, O_RDONLY); - if (fd < 0) { - if (errno != ENOENT) ALOGE("Can't open %s: %s", filename, strerror(errno)); - return -1; - } - - int len = read(fd, buf, sizeof(buf) - 1); - if (len < 0) { - ALOGE("Can't read %s: %s", filename, strerror(errno)); - close(fd); - return -1; - } - - close(fd); - buf[len] = '\0'; - return atoll(buf); -} - static int parseIfaceStats(const char* iface, struct Stats* stats) { FILE *fp = fopen(QTAGUID_IFACE_STATS, "r"); if (fp == NULL) { @@ -149,6 +118,36 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { return 0; } +static int parseUidStats(const uint32_t uid, struct Stats* stats) { + FILE *fp = fopen(QTAGUID_UID_STATS, "r"); + if (fp == NULL) { + return -1; + } + + char buffer[256]; + char iface[32]; + uint32_t idx, cur_uid, set; + uint64_t tag, rxBytes, rxPackets, txBytes, txPackets; + + while (fgets(buffer, 256, fp) != NULL) { + if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &idx, + iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, &txBytes, + &txPackets) == 9) { + if (uid == cur_uid && tag == 0L) { + stats->rxBytes += rxBytes; + stats->rxPackets += rxPackets; + stats->txBytes += txBytes; + stats->txPackets += txPackets; + } + } + } + + if (fclose(fp) != 0) { + return -1; + } + return 0; +} + static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { struct Stats stats; memset(&stats, 0, sizeof(Stats)); @@ -174,160 +173,20 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { } } - -// Per-UID stats require reading from a constructed filename. - -static jlong getUidBytes(JNIEnv* env, jobject clazz, jint uid, - enum Tx_Rx tx_or_rx, enum Tcp_Udp tcp_or_udp) { - char tcp_filename[80], udp_filename[80]; - jlong tcp_bytes = -1, udp_bytes = -1, total_bytes = -1; - - switch (tx_or_rx) { - case TX: - sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_snd", uid); - sprintf(udp_filename, "/proc/uid_stat/%d/udp_snd", uid); - break; - case RX: - sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_rcv", uid); - sprintf(udp_filename, "/proc/uid_stat/%d/udp_rcv", uid); - break; - default: - return -1; +static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { + struct Stats stats; + memset(&stats, 0, sizeof(Stats)); + if (parseUidStats(uid, &stats) == 0) { + return getStatsType(&stats, (StatsType) type); + } else { + return UNKNOWN; } - - switch (tcp_or_udp) { - case TCP: - tcp_bytes = readNumber(tcp_filename); - total_bytes = (tcp_bytes >= 0) ? tcp_bytes : -1; - break; - case UDP: - udp_bytes = readNumber(udp_filename); - total_bytes = (udp_bytes >= 0) ? udp_bytes : -1; - break; - case TCP_AND_UDP: - tcp_bytes = readNumber(tcp_filename); - total_bytes += (tcp_bytes >= 0 ? tcp_bytes : 0); - - udp_bytes = readNumber(udp_filename); - total_bytes += (udp_bytes >= 0 ? udp_bytes : 0); - break; - default: - return -1; - } - - return total_bytes; -} - -static jlong getUidPkts(JNIEnv* env, jobject clazz, jint uid, - enum Tx_Rx tx_or_rx, enum Tcp_Udp tcp_or_udp) { - char tcp_filename[80], udp_filename[80]; - jlong tcp_pkts = -1, udp_pkts = -1, total_pkts = -1; - - switch (tx_or_rx) { - case TX: - sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_snd_pkt", uid); - sprintf(udp_filename, "/proc/uid_stat/%d/udp_snd_pkt", uid); - break; - case RX: - sprintf(tcp_filename, "/proc/uid_stat/%d/tcp_rcv_pkt", uid); - sprintf(udp_filename, "/proc/uid_stat/%d/udp_rcv_pkt", uid); - break; - default: - return -1; - } - - switch (tcp_or_udp) { - case TCP: - tcp_pkts = readNumber(tcp_filename); - total_pkts = (tcp_pkts >= 0) ? tcp_pkts : -1; - break; - case UDP: - udp_pkts = readNumber(udp_filename); - total_pkts = (udp_pkts >= 0) ? udp_pkts : -1; - break; - case TCP_AND_UDP: - tcp_pkts = readNumber(tcp_filename); - total_pkts += (tcp_pkts >= 0 ? tcp_pkts : 0); - - udp_pkts = readNumber(udp_filename); - total_pkts += (udp_pkts >= 0 ? udp_pkts : 0); - break; - default: - return -1; - } - - return total_pkts; -} - -static jlong getUidRxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, RX, TCP_AND_UDP); -} - -static jlong getUidTxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, TX, TCP_AND_UDP); -} - -/* TCP Segments + UDP Packets */ -static jlong getUidTxPackets(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, TX, TCP_AND_UDP); -} - -/* TCP Segments + UDP Packets */ -static jlong getUidRxPackets(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, RX, TCP_AND_UDP); -} - -static jlong getUidTcpTxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, TX, TCP); -} - -static jlong getUidTcpRxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, RX, TCP); -} - -static jlong getUidUdpTxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, TX, UDP); -} - -static jlong getUidUdpRxBytes(JNIEnv* env, jobject clazz, jint uid) { - return getUidBytes(env, clazz, uid, RX, UDP); -} - -static jlong getUidTcpTxSegments(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, TX, TCP); -} - -static jlong getUidTcpRxSegments(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, RX, TCP); -} - -static jlong getUidUdpTxPackets(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, TX, UDP); -} - -static jlong getUidUdpRxPackets(JNIEnv* env, jobject clazz, jint uid) { - return getUidPkts(env, clazz, uid, RX, UDP); } static JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, - - /* Per-UID Stats */ - {"getUidTxBytes", "(I)J", (void*) getUidTxBytes}, - {"getUidRxBytes", "(I)J", (void*) getUidRxBytes}, - {"getUidTxPackets", "(I)J", (void*) getUidTxPackets}, - {"getUidRxPackets", "(I)J", (void*) getUidRxPackets}, - - {"getUidTcpTxBytes", "(I)J", (void*) getUidTcpTxBytes}, - {"getUidTcpRxBytes", "(I)J", (void*) getUidTcpRxBytes}, - {"getUidUdpTxBytes", "(I)J", (void*) getUidUdpTxBytes}, - {"getUidUdpRxBytes", "(I)J", (void*) getUidUdpRxBytes}, - - {"getUidTcpTxSegments", "(I)J", (void*) getUidTcpTxSegments}, - {"getUidTcpRxSegments", "(I)J", (void*) getUidTcpRxSegments}, - {"getUidUdpTxPackets", "(I)J", (void*) getUidUdpTxPackets}, - {"getUidUdpRxPackets", "(I)J", (void*) getUidUdpRxPackets}, + {"nativeGetUidStat", "(II)J", (void*) getUidStat}, }; int register_android_net_TrafficStats(JNIEnv* env) { From 805bdac0a0311baefa3479df9bb2742409bff9f6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 7 Feb 2013 15:02:55 -0800 Subject: [PATCH 0180/1150] Use safe buffer sizes when parsing network stats. Change-Id: I1733c1ddc48f9410136aee7af7889fdc7be8cc10 --- core/jni/android_net_TrafficStats.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index bf963de691..9e60904e0e 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -80,7 +80,7 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { return -1; } - char buffer[256]; + char buffer[384]; char cur_iface[32]; bool foundTcp = false; uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets; @@ -124,12 +124,12 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) { return -1; } - char buffer[256]; + char buffer[384]; char iface[32]; uint32_t idx, cur_uid, set; uint64_t tag, rxBytes, rxPackets, txBytes, txPackets; - while (fgets(buffer, 256, fp) != NULL) { + while (fgets(buffer, sizeof(buffer), fp) != NULL) { if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, &txBytes, &txPackets) == 9) { From 51c819c4ea604a69cdfff52570f90072e3b55fa8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 14 Jan 2013 16:48:51 -0800 Subject: [PATCH 0181/1150] Parse network stats using native code. Switch to parsing detailed network stats with native code, which is 71% faster than ProcFileReader. Change-Id: I2525aaee74d227ce187ba3a74dd08a2b06514deb --- core/java/android/net/NetworkStats.java | 12 ++ .../internal/net/NetworkStatsFactory.java | 84 +++++--- ...droid_internal_net_NetworkStatsFactory.cpp | 187 ++++++++++++++++++ 3 files changed, 260 insertions(+), 23 deletions(-) create mode 100644 core/jni/com_android_internal_net_NetworkStatsFactory.cpp diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index c7576057e1..9cb904d4c4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -135,6 +135,18 @@ public class NetworkStats implements Parcelable { builder.append(" operations=").append(operations); return builder.toString(); } + + @Override + public boolean equals(Object o) { + if (o instanceof Entry) { + final Entry e = (Entry) o; + return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes + && rxPackets == e.rxPackets && txBytes == e.txBytes + && txPackets == e.txPackets && operations == e.operations + && iface.equals(e.iface); + } + return false; + } } public NetworkStats(long elapsedRealtime, int initialSize) { diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index c517a68e2b..8282d237b3 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -31,6 +31,7 @@ import com.android.internal.util.ProcFileReader; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.net.ProtocolException; import libcore.io.IoUtils; @@ -41,7 +42,8 @@ import libcore.io.IoUtils; public class NetworkStatsFactory { private static final String TAG = "NetworkStatsFactory"; - // TODO: consider moving parsing to native code + private static final boolean USE_NATIVE_PARSING = true; + private static final boolean SANITY_CHECK_NATIVE = false; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; @@ -69,7 +71,7 @@ public class NetworkStatsFactory { * * @throws IllegalStateException when problem parsing stats. */ - public NetworkStats readNetworkStatsSummaryDev() throws IllegalStateException { + public NetworkStats readNetworkStatsSummaryDev() throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); @@ -105,11 +107,9 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException e) { - throw new IllegalStateException("problem parsing stats: " + e); + throw new ProtocolException("problem parsing stats", e); } catch (NumberFormatException e) { - throw new IllegalStateException("problem parsing stats: " + e); - } catch (IOException e) { - throw new IllegalStateException("problem parsing stats: " + e); + throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -124,7 +124,7 @@ public class NetworkStatsFactory { * * @throws IllegalStateException when problem parsing stats. */ - public NetworkStats readNetworkStatsSummaryXt() throws IllegalStateException { + public NetworkStats readNetworkStatsSummaryXt() throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); // return null when kernel doesn't support @@ -154,11 +154,9 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException e) { - throw new IllegalStateException("problem parsing stats: " + e); + throw new ProtocolException("problem parsing stats", e); } catch (NumberFormatException e) { - throw new IllegalStateException("problem parsing stats: " + e); - } catch (IOException e) { - throw new IllegalStateException("problem parsing stats: " + e); + throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -166,17 +164,33 @@ public class NetworkStatsFactory { return stats; } - public NetworkStats readNetworkStatsDetail() { + public NetworkStats readNetworkStatsDetail() throws IOException { return readNetworkStatsDetail(UID_ALL); } + public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException { + if (USE_NATIVE_PARSING) { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) { + throw new IOException("Failed to parse network stats"); + } + if (SANITY_CHECK_NATIVE) { + final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid); + assertEquals(javaStats, stats); + } + return stats; + } else { + return javaReadNetworkStatsDetail(mStatsXtUid, limitUid); + } + } + /** - * Parse and return {@link NetworkStats} with UID-level details. Values - * monotonically increase since device boot. - * - * @throws IllegalStateException when problem parsing stats. + * Parse and return {@link NetworkStats} with UID-level details. Values are + * expected to monotonically increase since device boot. */ - public NetworkStats readNetworkStatsDetail(int limitUid) throws IllegalStateException { + @VisibleForTesting + public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid) + throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 24); @@ -188,13 +202,13 @@ public class NetworkStatsFactory { ProcFileReader reader = null; try { // open and consume header line - reader = new ProcFileReader(new FileInputStream(mStatsXtUid)); + reader = new ProcFileReader(new FileInputStream(detailPath)); reader.finishLine(); while (reader.hasMoreData()) { idx = reader.nextInt(); if (idx != lastIdx + 1) { - throw new IllegalStateException( + throw new ProtocolException( "inconsistent idx=" + idx + " after lastIdx=" + lastIdx); } lastIdx = idx; @@ -215,11 +229,9 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException e) { - throw new IllegalStateException("problem parsing idx " + idx, e); + throw new ProtocolException("problem parsing idx " + idx, e); } catch (NumberFormatException e) { - throw new IllegalStateException("problem parsing idx " + idx, e); - } catch (IOException e) { - throw new IllegalStateException("problem parsing idx " + idx, e); + throw new ProtocolException("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -227,4 +239,30 @@ public class NetworkStatsFactory { return stats; } + + public void assertEquals(NetworkStats expected, NetworkStats actual) { + if (expected.size() != actual.size()) { + throw new AssertionError( + "Expected size " + expected.size() + ", actual size " + actual.size()); + } + + NetworkStats.Entry expectedRow = null; + NetworkStats.Entry actualRow = null; + for (int i = 0; i < expected.size(); i++) { + expectedRow = expected.getValues(i, expectedRow); + actualRow = actual.getValues(i, actualRow); + if (!expectedRow.equals(actualRow)) { + throw new AssertionError( + "Expected row " + i + ": " + expectedRow + ", actual row " + actualRow); + } + } + } + + /** + * Parse statistics from file into given {@link NetworkStats} object. Values + * are expected to monotonically increase since device boot. + */ + @VisibleForTesting + public static native int nativeReadNetworkStatsDetail( + NetworkStats stats, String path, int limitUid); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp new file mode 100644 index 0000000000..090659356b --- /dev/null +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -0,0 +1,187 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "NetworkStats" + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace android { + +static jclass gStringClass; + +static struct { + jfieldID size; + jfieldID iface; + jfieldID uid; + jfieldID set; + jfieldID tag; + jfieldID rxBytes; + jfieldID rxPackets; + jfieldID txBytes; + jfieldID txPackets; + jfieldID operations; +} gNetworkStatsClassInfo; + +struct stats_line { + int32_t idx; + char iface[32]; + int32_t uid; + int32_t set; + int32_t tag; + int64_t rxBytes; + int64_t rxPackets; + int64_t txBytes; + int64_t txPackets; +}; + +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, + jstring path, jint limitUid) { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + return -1; + } + + FILE *fp = fopen(path8.c_str(), "r"); + if (fp == NULL) { + return -1; + } + + Vector lines; + + int lastIdx = 1; + char buffer[384]; + while (fgets(buffer, sizeof(buffer), fp) != NULL) { + stats_line s; + int64_t rawTag; + if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx, + &s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, + &s.txBytes, &s.txPackets) == 9) { + if (s.idx != lastIdx + 1) { + ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx); + return -1; + } + lastIdx = s.idx; + + s.tag = rawTag >> 32; + lines.push_back(s); + } + } + + if (fclose(fp) != 0) { + return -1; + } + + int size = lines.size(); + + ScopedLocalRef iface(env, env->NewObjectArray(size, gStringClass, NULL)); + if (iface.get() == NULL) return -1; + ScopedIntArrayRW uid(env, env->NewIntArray(size)); + if (uid.get() == NULL) return -1; + ScopedIntArrayRW set(env, env->NewIntArray(size)); + if (set.get() == NULL) return -1; + ScopedIntArrayRW tag(env, env->NewIntArray(size)); + if (tag.get() == NULL) return -1; + ScopedLongArrayRW rxBytes(env, env->NewLongArray(size)); + if (rxBytes.get() == NULL) return -1; + ScopedLongArrayRW rxPackets(env, env->NewLongArray(size)); + if (rxPackets.get() == NULL) return -1; + ScopedLongArrayRW txBytes(env, env->NewLongArray(size)); + if (txBytes.get() == NULL) return -1; + ScopedLongArrayRW txPackets(env, env->NewLongArray(size)); + if (txPackets.get() == NULL) return -1; + ScopedLongArrayRW operations(env, env->NewLongArray(size)); + if (operations.get() == NULL) return -1; + + for (int i = 0; i < size; i++) { + ScopedLocalRef ifaceString(env, env->NewStringUTF(lines[i].iface)); + env->SetObjectArrayElement(iface.get(), i, ifaceString.get()); + + uid[i] = lines[i].uid; + set[i] = lines[i].set; + tag[i] = lines[i].tag; + rxBytes[i] = lines[i].rxBytes; + rxPackets[i] = lines[i].rxPackets; + txBytes[i] = lines[i].txBytes; + txPackets[i] = lines[i].txPackets; + } + + env->SetIntField(stats, gNetworkStatsClassInfo.size, size); + env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get()); + env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); + + return 0; +} + +static jclass findClass(JNIEnv* env, const char* name) { + ScopedLocalRef localClass(env, env->FindClass(name)); + jclass result = reinterpret_cast(env->NewGlobalRef(localClass.get())); + if (result == NULL) { + ALOGE("failed to find class '%s'", name); + abort(); + } + return result; +} + +static JNINativeMethod gMethods[] = { + { "nativeReadNetworkStatsDetail", + "(Landroid/net/NetworkStats;Ljava/lang/String;I)I", + (void*) readNetworkStatsDetail } +}; + +int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { + int err = AndroidRuntime::registerNativeMethods(env, + "com/android/internal/net/NetworkStatsFactory", gMethods, + NELEM(gMethods)); + + gStringClass = findClass(env, "java/lang/String"); + + jclass clazz = env->FindClass("android/net/NetworkStats"); + gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); + gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); + gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); + gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); + gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); + gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); + gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); + gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); + gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); + gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); + + return err; +} + +} From 6d9c71ab652b30ba2330c0b679390f8f45c57b27 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 8 Feb 2013 16:10:21 -0800 Subject: [PATCH 0182/1150] Remove sscanf() warnings when parsing stats. Change-Id: I15b7ba93d7ec121f9a7e19926f7436f2117b3b1a --- core/jni/android_net_TrafficStats.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 9e60904e0e..0df86387bd 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -87,8 +87,8 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { while (fgets(buffer, sizeof(buffer), fp) != NULL) { int matched = sscanf(buffer, "%31s %llu %llu %llu %llu " - "%*llu %llu %*llu %*llu %*llu %*llu " - "%*llu %llu %*llu %*llu %*llu %*llu", cur_iface, &rxBytes, + "%*u %llu %*u %*u %*u %*u " + "%*u %llu %*u %*u %*u %*u", cur_iface, &rxBytes, &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets); if (matched >= 5) { if (matched == 7) { From 26c10de1b79ac18f3d0ddadbcd0fc76152723fcc Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 25 Feb 2013 10:55:29 -0800 Subject: [PATCH 0183/1150] Require command and argument separation, cleanup. When invoking NativeDaemonCommands, require that base command and arguments are separate. Clean up reverse tethering commands, and remove deprecated throttle events. Change-Id: I302a74130b4f7c3f3045815a56d566e89c8969f6 --- .../android/server/NativeDaemonConnector.java | 74 +++++-------------- 1 file changed, 17 insertions(+), 57 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 5e94a9fc76..c3f2afa04b 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -206,18 +206,19 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo /** * Make command for daemon, escaping arguments as needed. */ - private void makeCommand(StringBuilder builder, String cmd, Object... args) - throws NativeDaemonConnectorException { - // TODO: eventually enforce that cmd doesn't contain arguments + private void makeCommand(StringBuilder builder, String cmd, Object... args) { if (cmd.indexOf('\0') >= 0) { - throw new IllegalArgumentException("unexpected command: " + cmd); + throw new IllegalArgumentException("Unexpected command: " + cmd); + } + if (cmd.indexOf(' ') >= 0) { + throw new IllegalArgumentException("Arguments must be separate from command"); } builder.append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { - throw new IllegalArgumentException("unexpected argument: " + arg); + throw new IllegalArgumentException("Unexpected argument: " + arg); } builder.append(' '); @@ -240,7 +241,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo /** * Issue the given command to the native daemon and return a single expected - * response. + * response. Any arguments must be separated from base command so they can + * be properly escaped. * * @throws NativeDaemonConnectorException when problem communicating with * native daemon, or if the response matches @@ -274,7 +276,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo /** * Issue the given command to the native daemon and return any * {@link NativeDaemonEvent#isClassContinue()} responses, including the - * final terminal response. + * final terminal response. Any arguments must be separated from base + * command so they can be properly escaped. * * @throws NativeDaemonConnectorException when problem communicating with * native daemon, or if the response matches @@ -287,10 +290,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** - * Issue the given command to the native daemon and return any - * {@linke NativeDaemonEvent@isClassContinue()} responses, including the - * final terminal response. Note that the timeout does not count time in - * deep sleep. + * Issue the given command to the native daemon and return any {@linke + * NativeDaemonEvent@isClassContinue()} responses, including the final + * terminal response. Note that the timeout does not count time in deep + * sleep. Any arguments must be separated from base command so they can be + * properly escaped. * * @throws NativeDaemonConnectorException when problem communicating with * native daemon, or if the response matches @@ -352,51 +356,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo return events.toArray(new NativeDaemonEvent[events.size()]); } - /** - * Issue a command to the native daemon and return the raw responses. - * - * @deprecated callers should move to {@link #execute(String, Object...)} - * which returns parsed {@link NativeDaemonEvent}. - */ - @Deprecated - public ArrayList doCommand(String cmd) throws NativeDaemonConnectorException { - final ArrayList rawEvents = Lists.newArrayList(); - final NativeDaemonEvent[] events = executeForList(cmd); - for (NativeDaemonEvent event : events) { - rawEvents.add(event.getRawEvent()); - } - return rawEvents; - } - - /** - * Issues a list command and returns the cooked list of all - * {@link NativeDaemonEvent#getMessage()} which match requested code. - */ - @Deprecated - public String[] doListCommand(String cmd, int expectedCode) - throws NativeDaemonConnectorException { - final ArrayList list = Lists.newArrayList(); - - final NativeDaemonEvent[] events = executeForList(cmd); - for (int i = 0; i < events.length - 1; i++) { - final NativeDaemonEvent event = events[i]; - final int code = event.getCode(); - if (code == expectedCode) { - list.add(event.getMessage()); - } else { - throw new NativeDaemonConnectorException( - "unexpected list response " + code + " instead of " + expectedCode); - } - } - - final NativeDaemonEvent finalEvent = events[events.length - 1]; - if (!finalEvent.isClassOk()) { - throw new NativeDaemonConnectorException("unexpected final event: " + finalEvent); - } - - return list.toArray(new String[list.size()]); - } - /** * Append the given argument to {@link StringBuilder}, escaping as needed, * and surrounding with quotes when it contains spaces. @@ -444,7 +403,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** - * Command builder that handles argument list building. + * Command builder that handles argument list building. Any arguments must + * be separated from base command so they can be properly escaped. */ public static class Command { private String mCmd; From e9d7207f8665fa67ef619a4f7d1eeb19d68b3430 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 25 Feb 2013 15:55:37 -0800 Subject: [PATCH 0184/1150] Add version code constant for JB MR2. Change-Id: I60fc76bbeb3c5e85d716179e9e3ea5758bafaf69 --- core/java/android/net/TrafficStats.java | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a2829109a4..ce1276fb70 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -429,7 +429,7 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

- * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. * * @see android.os.Process#myUid() @@ -445,7 +445,7 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

- * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. * * @see android.os.Process#myUid() @@ -461,7 +461,7 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

- * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. * * @see android.os.Process#myUid() @@ -477,7 +477,7 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

- * Before {@link android.os.Build.VERSION_CODES#K}, this may return + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. * * @see android.os.Process#myUid() @@ -488,7 +488,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidTxBytes(int) @@ -499,7 +499,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidRxBytes(int) @@ -510,7 +510,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidTxBytes(int) @@ -521,7 +521,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidRxBytes(int) @@ -532,7 +532,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidTxPackets(int) @@ -543,7 +543,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidRxPackets(int) @@ -554,7 +554,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidTxPackets(int) @@ -565,7 +565,7 @@ public class TrafficStats { } /** - * @deprecated Starting in {@link android.os.Build.VERSION_CODES#K}, + * @deprecated Starting in {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, * transport layer statistics are no longer available, and will * always return {@link #UNSUPPORTED}. * @see #getUidRxPackets(int) From 7de8125565b173e8f124125481da4d6dc21a9bec Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 1 Mar 2013 23:38:40 -0800 Subject: [PATCH 0185/1150] jni: net.TrafficStats: fix getIfaceStat, have it use the iface. Missing iface8 in call to parseIfaceStats(). Bug: 8304054 Change-Id: Ibb01d86a0f7241cdd8f23401973840673f847efb --- core/jni/android_net_TrafficStats.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 0df86387bd..b4c4a1b709 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -166,7 +166,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { struct Stats stats; memset(&stats, 0, sizeof(Stats)); - if (parseIfaceStats(NULL, &stats) == 0) { + if (parseIfaceStats(iface8.c_str(), &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { return UNKNOWN; From 39fb9cd9c2ea669249b45c40de8ff2ca21776ab5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 26 Mar 2013 13:46:05 -0700 Subject: [PATCH 0186/1150] Update TrafficStats docs to reflect behavior. Bug: 8399623 Change-Id: If9ccd305e8a077f318a09ac1bb160b8efbf903aa --- core/java/android/net/TrafficStats.java | 133 +++++++++++++----------- 1 file changed, 72 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ce1276fb70..786439e5d8 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -119,6 +119,8 @@ public class TrafficStats { * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and * used internally by system services like {@link DownloadManager} when * performing traffic on behalf of an application. + * + * @see #clearThreadStatsTag() */ public static void setThreadStatsTag(int tag) { NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); @@ -128,11 +130,19 @@ public class TrafficStats { * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. * {@link #tagSocket(Socket)}. + * + * @see #setThreadStatsTag(int) */ public static int getThreadStatsTag() { return NetworkManagementSocketTagger.getThreadSocketStatsTag(); } + /** + * Clear any active tag set to account {@link Socket} traffic originating + * from the current thread. + * + * @see #setThreadStatsTag(int) + */ public static void clearThreadStatsTag() { NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); } @@ -148,7 +158,7 @@ public class TrafficStats { * To take effect, caller must hold * {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission. * - * {@hide} + * @hide */ public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); @@ -260,10 +270,13 @@ public class TrafficStats { } /** - * Get the total number of packets transmitted through the mobile interface. - * - * @return number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of packets transmitted across mobile networks since device + * boot. Counts packets across all mobile network interfaces, and always + * increases monotonically since device boot. Statistics are measured at the + * network layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getMobileTxPackets() { long total = 0; @@ -274,10 +287,13 @@ public class TrafficStats { } /** - * Get the total number of packets received through the mobile interface. - * - * @return number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of packets received across mobile networks since device + * boot. Counts packets across all mobile network interfaces, and always + * increases monotonically since device boot. Statistics are measured at the + * network layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getMobileRxPackets() { long total = 0; @@ -288,10 +304,13 @@ public class TrafficStats { } /** - * Get the total number of bytes transmitted through the mobile interface. - * - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of bytes transmitted across mobile networks since device + * boot. Counts packets across all mobile network interfaces, and always + * increases monotonically since device boot. Statistics are measured at the + * network layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getMobileTxBytes() { long total = 0; @@ -302,10 +321,13 @@ public class TrafficStats { } /** - * Get the total number of bytes received through the mobile interface. - * - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of bytes received across mobile networks since device boot. + * Counts packets across all mobile network interfaces, and always increases + * monotonically since device boot. Statistics are measured at the network + * layer, so they include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getMobileRxBytes() { long total = 0; @@ -339,85 +361,73 @@ public class TrafficStats { return total; } - /** - * Get the total number of packets transmitted through the specified interface. - * - * @return number of packets. If the statistics are not supported by this interface, - * {@link #UNSUPPORTED} will be returned. - * @hide - */ + /** {@hide} */ public static long getTxPackets(String iface) { return nativeGetIfaceStat(iface, TYPE_TX_PACKETS); } - /** - * Get the total number of packets received through the specified interface. - * - * @return number of packets. If the statistics are not supported by this interface, - * {@link #UNSUPPORTED} will be returned. - * @hide - */ + /** {@hide} */ public static long getRxPackets(String iface) { return nativeGetIfaceStat(iface, TYPE_RX_PACKETS); } - /** - * Get the total number of bytes transmitted through the specified interface. - * - * @return number of bytes. If the statistics are not supported by this interface, - * {@link #UNSUPPORTED} will be returned. - * @hide - */ + /** {@hide} */ public static long getTxBytes(String iface) { return nativeGetIfaceStat(iface, TYPE_TX_BYTES); } - /** - * Get the total number of bytes received through the specified interface. - * - * @return number of bytes. If the statistics are not supported by this interface, - * {@link #UNSUPPORTED} will be returned. - * @hide - */ + /** {@hide} */ public static long getRxBytes(String iface) { return nativeGetIfaceStat(iface, TYPE_RX_BYTES); } /** - * Get the total number of packets sent through all network interfaces. - * - * @return the number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of packets transmitted since device boot. Counts packets + * across all network interfaces, and always increases monotonically since + * device boot. Statistics are measured at the network layer, so they + * include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxPackets() { return nativeGetTotalStat(TYPE_TX_PACKETS); } /** - * Get the total number of packets received through all network interfaces. - * - * @return number of packets. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of packets received since device boot. Counts packets + * across all network interfaces, and always increases monotonically since + * device boot. Statistics are measured at the network layer, so they + * include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxPackets() { return nativeGetTotalStat(TYPE_RX_PACKETS); } /** - * Get the total number of bytes sent through all network interfaces. - * - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of bytes transmitted since device boot. Counts packets + * across all network interfaces, and always increases monotonically since + * device boot. Statistics are measured at the network layer, so they + * include both TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxBytes() { return nativeGetTotalStat(TYPE_TX_BYTES); } /** - * Get the total number of bytes received through all network interfaces. - * - * @return number of bytes. If the statistics are not supported by this device, - * {@link #UNSUPPORTED} will be returned. + * Return number of bytes received since device boot. Counts packets across + * all network interfaces, and always increases monotonically since device + * boot. Statistics are measured at the network layer, so they include both + * TCP and UDP usage. + *

+ * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxBytes() { return nativeGetTotalStat(TYPE_RX_BYTES); @@ -580,6 +590,7 @@ public class TrafficStats { * special permission. */ private static NetworkStats getDataLayerSnapshotForUid(Context context) { + // TODO: take snapshot locally, since proc file is now visible final int uid = android.os.Process.myUid(); try { return getStatsService().getDataLayerSnapshotForUid(uid); From 54824c9538cc44a7357cf3f093093e20d455e990 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 28 Mar 2013 10:15:44 -0700 Subject: [PATCH 0187/1150] Add support for setMiracastMode Usage is setMiracastMode(WifiP2pManager.MIRACAST_SOURCE) or setMiracastMode(WifiP2pManager.MIRACAST_SINK) as an example. Only available for internal use and can be called as long as driver is active. P2p connection is not needed for it to be called Bug: 8493089 Change-Id: I1f87eaf3311212aae980077de26c05651a8cc811 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index 381a450187..1c9c40d193 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -26,5 +26,6 @@ import android.os.Messenger; interface IWifiP2pManager { Messenger getMessenger(); + void setMiracastMode(int mode); } From 7aa7bb4dfb01e3d32ad040eff8b35245a8bf2292 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 2 May 2013 15:45:32 -0700 Subject: [PATCH 0188/1150] Fix sync problem in NsdManager The NsdManager init was thinking it was done before the AsyncChannel was fully setup and if the setup were slow and the app fast, the app could make calls to the NsdManager that it wasn't ready for. bug:8545006 Change-Id: I2cb2a7c0a1c7f3d2b81ac0f66d37346e6d2d720d --- core/java/android/net/nsd/NsdManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 08ba728f65..9c3e405f44 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -306,10 +306,9 @@ public final class NsdManager { switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - mConnected.countDown(); break; case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: - // Ignore + mConnected.countDown(); break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: Log.e(TAG, "Channel lost"); From f7c56ef9dd0605a37de7ca4e5e40070f6d7f0b54 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 30 Apr 2013 17:24:15 -0700 Subject: [PATCH 0189/1150] Start combining threads in system process. This introduces four generic thread that services can use in the system process: - Background: part of the framework for all processes, for work that is purely background (no timing constraint). - UI: for time-critical display of UI. - Foreground: normal foreground work. - IO: performing IO operations. I went through and moved services into these threads in the places I felt relatively comfortable about understanding what they are doing. There are still a bunch more we need to look at -- lots of networking stuff left, 3 or so different native daemon connectors which I didn't know how much would block, audio stuff, etc. Also updated Watchdog to be aware of and check these new threads, with a new API for other threads to also participate in this checking. Change-Id: Ie2f11061cebde5f018d7383b3a910fbbd11d5e11 --- .../java/com/android/server/NativeDaemonConnector.java | 5 +---- .../java/com/android/server/net/NetworkStatsService.java | 7 ++----- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c3f2afa04b..abcd8eeb35 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -19,7 +19,6 @@ package com.android.server; import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Handler; -import android.os.HandlerThread; import android.os.Message; import android.os.SystemClock; import android.util.LocalLog; @@ -81,9 +80,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo @Override public void run() { - HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); - thread.start(); - mCallbackHandler = new Handler(thread.getLooper(), this); + mCallbackHandler = new Handler(FgThread.get().getLooper(), this); while (true) { try { diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 74be472d38..5074409694 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -96,7 +96,6 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; -import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; @@ -120,6 +119,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; +import com.android.server.IoThread; import com.android.server.connectivity.Tethering; import com.google.android.collect.Maps; @@ -240,7 +240,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - private final HandlerThread mHandlerThread; private final Handler mHandler; private boolean mSystemReady; @@ -271,9 +270,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mHandlerThread = new HandlerThread(TAG); - mHandlerThread.start(); - mHandler = new Handler(mHandlerThread.getLooper(), mHandlerCallback); + mHandler = new Handler(IoThread.get().getLooper(), mHandlerCallback); mSystemDir = checkNotNull(systemDir); mBaseDir = new File(systemDir, "netstats"); From 682fa4bd0b1ae77282a54748823b97bfb5b23b40 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 7 Jun 2013 15:09:15 -0700 Subject: [PATCH 0190/1150] Avoid logging sensitive data. When building commands to send across NativeDaemonConnector, scrub sensitive arguments to prevent them from being logged. Bug: 8609800 Change-Id: I84b16791749264a010f7e59f9918f68d71bac6b9 --- .../android/server/NativeDaemonConnector.java | 80 +++++++++++++------ .../server/NativeDaemonConnectorTest.java | 27 +++++++ 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c3f2afa04b..47840e0882 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -203,10 +203,29 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } + /** + * Wrapper around argument that indicates it's sensitive and shouldn't be + * logged. + */ + public static class SensitiveArg { + private final Object mArg; + + public SensitiveArg(Object arg) { + mArg = arg; + } + + @Override + public String toString() { + return String.valueOf(mArg); + } + } + /** * Make command for daemon, escaping arguments as needed. */ - private void makeCommand(StringBuilder builder, String cmd, Object... args) { + @VisibleForTesting + static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, + String cmd, Object... args) { if (cmd.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected command: " + cmd); } @@ -214,16 +233,26 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new IllegalArgumentException("Arguments must be separate from command"); } - builder.append(cmd); + rawBuilder.append(sequenceNumber).append(' ').append(cmd); + logBuilder.append(sequenceNumber).append(' ').append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected argument: " + arg); } - builder.append(' '); - appendEscaped(builder, argString); + rawBuilder.append(' '); + logBuilder.append(' '); + + appendEscaped(rawBuilder, argString); + if (arg instanceof SensitiveArg) { + logBuilder.append("[scrubbed]"); + } else { + appendEscaped(logBuilder, argString); + } } + + rawBuilder.append('\0'); } /** @@ -303,27 +332,27 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { - final ArrayList events = Lists.newArrayList(); - - final int sequenceNumber = mSequenceNumber.incrementAndGet(); - final StringBuilder cmdBuilder = - new StringBuilder(Integer.toString(sequenceNumber)).append(' '); final long startTime = SystemClock.elapsedRealtime(); - makeCommand(cmdBuilder, cmd, args); + final ArrayList events = Lists.newArrayList(); + + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); + final int sequenceNumber = mSequenceNumber.incrementAndGet(); + + makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); + + final String rawCmd = rawBuilder.toString(); + final String logCmd = logBuilder.toString(); - final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ log("SND -> {" + logCmd + "}"); - cmdBuilder.append('\0'); - final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ - synchronized (mDaemonLock) { if (mOutputStream == null) { throw new NativeDaemonConnectorException("missing output stream"); } else { try { - mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + mOutputStream.write(rawCmd.getBytes(Charsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } @@ -332,7 +361,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo NativeDaemonEvent event = null; do { - event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); + event = mResponseQueue.remove(sequenceNumber, timeout, logCmd); if (event == null) { loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); @@ -447,10 +476,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private static class ResponseQueue { private static class PendingCmd { - public int cmdNum; + public final int cmdNum; + public final String logCmd; + public BlockingQueue responses = new ArrayBlockingQueue(10); - public String request; // The availableResponseCount member is used to track when we can remove this // instance from the ResponseQueue. @@ -468,7 +498,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // hold references to this instance already so it can be removed from // mPendingCmds queue. public int availableResponseCount; - public PendingCmd(int c, String r) {cmdNum = c; request = r;} + + public PendingCmd(int cmdNum, String logCmd) { + this.cmdNum = cmdNum; + this.logCmd = logCmd; + } } private final LinkedList mPendingCmds; @@ -497,7 +531,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // let any waiter timeout waiting for this PendingCmd pendingCmd = mPendingCmds.remove(); Slog.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.request + " (" + + "Removing request: " + pendingCmd.logCmd + " (" + pendingCmd.cmdNum + ")"); } found = new PendingCmd(cmdNum, null); @@ -515,7 +549,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // note that the timeout does not count time in deep sleep. If you don't want // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) { PendingCmd found = null; synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { @@ -525,7 +559,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } if (found == null) { - found = new PendingCmd(cmdNum, origCmd); + found = new PendingCmd(cmdNum, logCmd); mPendingCmds.add(found); } found.availableResponseCount--; @@ -547,7 +581,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo pw.println("Pending requests:"); synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.request); + pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); } } } diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java index 275d807645..e2253a2151 100644 --- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java +++ b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java @@ -17,10 +17,13 @@ package com.android.server; import static com.android.server.NativeDaemonConnector.appendEscaped; +import static com.android.server.NativeDaemonConnector.makeCommand; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.MediumTest; +import com.android.server.NativeDaemonConnector.SensitiveArg; + /** * Tests for {@link NativeDaemonConnector}. */ @@ -67,4 +70,28 @@ public class NativeDaemonConnectorTest extends AndroidTestCase { appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); } + + public void testSensitiveArgs() throws Exception { + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo bar baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", + new SensitiveArg("wat")); + assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); + } } From 060837348200306e617645b11f9c1ff1c8b60e09 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 7 Jun 2013 15:09:15 -0700 Subject: [PATCH 0191/1150] Avoid logging sensitive data. When building commands to send across NativeDaemonConnector, scrub sensitive arguments to prevent them from being logged. Bug: 8609800 Change-Id: I84b16791749264a010f7e59f9918f68d71bac6b9 --- .../android/server/NativeDaemonConnector.java | 80 +++++++++++++------ .../server/NativeDaemonConnectorTest.java | 27 +++++++ 2 files changed, 84 insertions(+), 23 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index c3f2afa04b..47840e0882 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -203,10 +203,29 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } + /** + * Wrapper around argument that indicates it's sensitive and shouldn't be + * logged. + */ + public static class SensitiveArg { + private final Object mArg; + + public SensitiveArg(Object arg) { + mArg = arg; + } + + @Override + public String toString() { + return String.valueOf(mArg); + } + } + /** * Make command for daemon, escaping arguments as needed. */ - private void makeCommand(StringBuilder builder, String cmd, Object... args) { + @VisibleForTesting + static void makeCommand(StringBuilder rawBuilder, StringBuilder logBuilder, int sequenceNumber, + String cmd, Object... args) { if (cmd.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected command: " + cmd); } @@ -214,16 +233,26 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new IllegalArgumentException("Arguments must be separate from command"); } - builder.append(cmd); + rawBuilder.append(sequenceNumber).append(' ').append(cmd); + logBuilder.append(sequenceNumber).append(' ').append(cmd); for (Object arg : args) { final String argString = String.valueOf(arg); if (argString.indexOf('\0') >= 0) { throw new IllegalArgumentException("Unexpected argument: " + arg); } - builder.append(' '); - appendEscaped(builder, argString); + rawBuilder.append(' '); + logBuilder.append(' '); + + appendEscaped(rawBuilder, argString); + if (arg instanceof SensitiveArg) { + logBuilder.append("[scrubbed]"); + } else { + appendEscaped(logBuilder, argString); + } } + + rawBuilder.append('\0'); } /** @@ -303,27 +332,27 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) throws NativeDaemonConnectorException { - final ArrayList events = Lists.newArrayList(); - - final int sequenceNumber = mSequenceNumber.incrementAndGet(); - final StringBuilder cmdBuilder = - new StringBuilder(Integer.toString(sequenceNumber)).append(' '); final long startTime = SystemClock.elapsedRealtime(); - makeCommand(cmdBuilder, cmd, args); + final ArrayList events = Lists.newArrayList(); + + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); + final int sequenceNumber = mSequenceNumber.incrementAndGet(); + + makeCommand(rawBuilder, logBuilder, sequenceNumber, cmd, args); + + final String rawCmd = rawBuilder.toString(); + final String logCmd = logBuilder.toString(); - final String logCmd = cmdBuilder.toString(); /* includes cmdNum, cmd, args */ log("SND -> {" + logCmd + "}"); - cmdBuilder.append('\0'); - final String sentCmd = cmdBuilder.toString(); /* logCmd + \0 */ - synchronized (mDaemonLock) { if (mOutputStream == null) { throw new NativeDaemonConnectorException("missing output stream"); } else { try { - mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + mOutputStream.write(rawCmd.getBytes(Charsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } @@ -332,7 +361,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo NativeDaemonEvent event = null; do { - event = mResponseQueue.remove(sequenceNumber, timeout, sentCmd); + event = mResponseQueue.remove(sequenceNumber, timeout, logCmd); if (event == null) { loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); @@ -447,10 +476,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private static class ResponseQueue { private static class PendingCmd { - public int cmdNum; + public final int cmdNum; + public final String logCmd; + public BlockingQueue responses = new ArrayBlockingQueue(10); - public String request; // The availableResponseCount member is used to track when we can remove this // instance from the ResponseQueue. @@ -468,7 +498,11 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // hold references to this instance already so it can be removed from // mPendingCmds queue. public int availableResponseCount; - public PendingCmd(int c, String r) {cmdNum = c; request = r;} + + public PendingCmd(int cmdNum, String logCmd) { + this.cmdNum = cmdNum; + this.logCmd = logCmd; + } } private final LinkedList mPendingCmds; @@ -497,7 +531,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // let any waiter timeout waiting for this PendingCmd pendingCmd = mPendingCmds.remove(); Slog.e("NativeDaemonConnector.ResponseQueue", - "Removing request: " + pendingCmd.request + " (" + + "Removing request: " + pendingCmd.logCmd + " (" + pendingCmd.cmdNum + ")"); } found = new PendingCmd(cmdNum, null); @@ -515,7 +549,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // note that the timeout does not count time in deep sleep. If you don't want // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String origCmd) { + public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) { PendingCmd found = null; synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { @@ -525,7 +559,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } if (found == null) { - found = new PendingCmd(cmdNum, origCmd); + found = new PendingCmd(cmdNum, logCmd); mPendingCmds.add(found); } found.availableResponseCount--; @@ -547,7 +581,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo pw.println("Pending requests:"); synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { - pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.request); + pw.println(" Cmd " + pendingCmd.cmdNum + " - " + pendingCmd.logCmd); } } } diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java index 275d807645..e2253a2151 100644 --- a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java +++ b/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java @@ -17,10 +17,13 @@ package com.android.server; import static com.android.server.NativeDaemonConnector.appendEscaped; +import static com.android.server.NativeDaemonConnector.makeCommand; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.MediumTest; +import com.android.server.NativeDaemonConnector.SensitiveArg; + /** * Tests for {@link NativeDaemonConnector}. */ @@ -67,4 +70,28 @@ public class NativeDaemonConnectorTest extends AndroidTestCase { appendEscaped(builder, "caf\u00E9 c\u00F6ffee"); assertEquals("\"caf\u00E9 c\u00F6ffee\"", builder.toString()); } + + public void testSensitiveArgs() throws Exception { + final StringBuilder rawBuilder = new StringBuilder(); + final StringBuilder logBuilder = new StringBuilder(); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", "bar", "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo bar baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("bar"), "baz"); + assertEquals("1 foo bar baz\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] baz", logBuilder.toString()); + + rawBuilder.setLength(0); + logBuilder.setLength(0); + makeCommand(rawBuilder, logBuilder, 1, "foo", new SensitiveArg("foo bar"), "baz baz", + new SensitiveArg("wat")); + assertEquals("1 foo \"foo bar\" \"baz baz\" wat\0", rawBuilder.toString()); + assertEquals("1 foo [scrubbed] \"baz baz\" [scrubbed]", logBuilder.toString()); + } } From 930a8513db45379686f207340359cc2f10d68dec Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Tue, 25 Jun 2013 19:45:03 -0700 Subject: [PATCH 0192/1150] Fix an NPE in NsdManager The NPE happens because NSD Manager doesn't always notify with a 'good' notification for SERVICE_FOUND. It can get in a situation where a SERVICE_FOUND is recevied from MDnsDs demon when processing StopDiscovery on the messaging thread. When that happens, NsdService sends a message to NsdManager with an invalid index of the listener. The fix is twofold. First, we fix NsdService to not generate a message if it doesn't have a good listener index. And second, we also fix NsdManager to watch for invalid index. Change-Id: I3d63af10bded13c72e8e437a1ebf74a666760432 --- services/java/com/android/server/NsdService.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index faa72a2c85..e0f415bfea 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -417,7 +417,15 @@ public class NsdService extends INsdManager.Stub { int keyId = clientInfo.mClientIds.indexOfValue(id); if (keyId != -1) { clientId = clientInfo.mClientIds.keyAt(keyId); + } else { + // This can happen because of race conditions. For example, + // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY, + // and we may get in this situation. + Slog.d(TAG, "Notification for a listener that is no longer active: " + id); + handled = false; + return handled; } + switch (code) { case NativeResponseCode.SERVICE_FOUND: /* NNN uniqueId serviceName regType domain */ From aa40ac667e7a4bcb13489f0fffd05f1ddf9ef24f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 28 Jun 2013 16:24:48 -0700 Subject: [PATCH 0193/1150] Switch frameworks/base over from @hidden Charsets to public StandardCharsets. Bug: 3484927 Change-Id: I5d136d2ee629588538602766a182ae14ce5fc63c --- .../java/com/android/server/NativeDaemonConnector.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index 5e94a9fc76..e423780ddd 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -28,12 +28,12 @@ import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.google.android.collect.Lists; -import java.nio.charset.Charsets; import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.ArrayBlockingQueue; @@ -142,7 +142,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo for (int i = 0; i < count; i++) { if (buffer[i] == 0) { final String rawEvent = new String( - buffer, start, i - start, Charsets.UTF_8); + buffer, start, i - start, StandardCharsets.UTF_8); log("RCV <- {" + rawEvent + "}"); try { @@ -163,7 +163,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } if (start == 0) { - final String rawEvent = new String(buffer, start, count, Charsets.UTF_8); + final String rawEvent = new String(buffer, start, count, StandardCharsets.UTF_8); log("RCV incomplete <- {" + rawEvent + "}"); } @@ -319,7 +319,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo throw new NativeDaemonConnectorException("missing output stream"); } else { try { - mOutputStream.write(sentCmd.getBytes(Charsets.UTF_8)); + mOutputStream.write(sentCmd.getBytes(StandardCharsets.UTF_8)); } catch (IOException e) { throw new NativeDaemonConnectorException("problem sending command", e); } From f20d6b326fbb541f35badd3cfa042363bff38e13 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 11 Jul 2013 11:18:53 -0700 Subject: [PATCH 0194/1150] Recover from corrupt network stats. When encountering corrupt stats, throw as IOException to allow recovery at a higher level. Bug: 9794832 Change-Id: I38d000b3bd8a4c99389c40a87ee0699efb6e9049 --- core/java/android/net/NetworkStatsHistory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 382b25e377..62d8738ba6 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -639,6 +639,7 @@ public class NetworkStatsHistory implements Parcelable { @Deprecated public static long[] readFullLongArray(DataInputStream in) throws IOException { final int size = in.readInt(); + if (size < 0) throw new ProtocolException("negative array size"); final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { values[i] = in.readLong(); @@ -680,6 +681,7 @@ public class NetworkStatsHistory implements Parcelable { public static long[] readVarLongArray(DataInputStream in) throws IOException { final int size = in.readInt(); if (size == -1) return null; + if (size < 0) throw new ProtocolException("negative array size"); final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { values[i] = readVarLong(in); From c64874ae5085c24bdb9ccb1364b516cc07e95100 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 11 Jul 2013 11:18:53 -0700 Subject: [PATCH 0195/1150] Recover from corrupt network stats. When encountering corrupt stats, throw as IOException to allow recovery at a higher level. Bug: 9794832 Change-Id: I38d000b3bd8a4c99389c40a87ee0699efb6e9049 --- core/java/android/net/NetworkStatsHistory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 382b25e377..62d8738ba6 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -639,6 +639,7 @@ public class NetworkStatsHistory implements Parcelable { @Deprecated public static long[] readFullLongArray(DataInputStream in) throws IOException { final int size = in.readInt(); + if (size < 0) throw new ProtocolException("negative array size"); final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { values[i] = in.readLong(); @@ -680,6 +681,7 @@ public class NetworkStatsHistory implements Parcelable { public static long[] readVarLongArray(DataInputStream in) throws IOException { final int size = in.readInt(); if (size == -1) return null; + if (size < 0) throw new ProtocolException("negative array size"); final long[] values = new long[size]; for (int i = 0; i < values.length; i++) { values[i] = readVarLong(in); From 9fa19313dd9210902a3085b5a3a52bd8fd29686d Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 11 Jul 2013 14:43:13 -0700 Subject: [PATCH 0196/1150] Batch alarms to reduce device wakeups The default Alarm Manager behavior for KLP+ apps will be to aggressively coalesce alarms, trading exact timeliness of delivery for minimizing the number of alarm-delivery points, especially wakeup points. There is new API in AlarmManager, setExact() and setExactRepeating(), for use by apps that absolutely *must* get their alarms at a specific point in time. Bug 9532215 Change-Id: I40b4eea90220211cc958172d2629664b921ff051 --- .../server/net/NetworkStatsService.java | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 5074409694..05eeb36195 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -154,7 +154,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Context mContext; private final INetworkManagementService mNetworkManager; - private final IAlarmManager mAlarmManager; + private final AlarmManager mAlarmManager; private final TrustedTime mTime; private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; @@ -261,10 +261,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsSettings settings) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); - mAlarmManager = checkNotNull(alarmManager, "missing IAlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); + mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); final PowerManager powerManager = (PowerManager) context.getSystemService( Context.POWER_SERVICE); @@ -420,20 +420,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. */ private void registerPollAlarmLocked() { - try { - if (mPollIntent != null) { - mAlarmManager.remove(mPollIntent); - } - - mPollIntent = PendingIntent.getBroadcast( - mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); - - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), mPollIntent); - } catch (RemoteException e) { - // ignored; service lives in system_server + if (mPollIntent != null) { + mAlarmManager.cancel(mPollIntent); } + + mPollIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, + mSettings.getPollInterval(), mPollIntent); } /** From c5697c326e47a1b4ba2a3ad179b0bf331ed27799 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Tue, 23 Jul 2013 18:17:08 -0700 Subject: [PATCH 0197/1150] replace cutils/logger.h with log/logger.h and remove it from files that don't use it. Change-Id: Ieb44a3f1f75c2d2b277f0d01ca926a92211e3fe6 --- core/jni/android_net_TrafficStats.cpp | 1 - core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index b4c4a1b709..f904b62e29 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -23,7 +23,6 @@ #include #include -#include #include #include #include diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 090659356b..ec19f0ab38 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -21,7 +21,6 @@ #include #include -#include #include #include From e79657d5fbb4e19f466e614aec50e38550d2c400 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 20 Aug 2013 22:51:24 +0900 Subject: [PATCH 0198/1150] Add a simple test for NetworkManagementService. For now, this only tests network observers. It works by starting NetworkManagementService with a fake netd socket, feeding it inputs, and seeing if the appropriate observer methods are called. Bug: 10232006 Change-Id: I827681575642a4ee13ae48b81272521544b676bd --- .../android/server/NativeDaemonConnector.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java index a9942e3fd0..417d6d81cd 100644 --- a/services/java/com/android/server/NativeDaemonConnector.java +++ b/services/java/com/android/server/NativeDaemonConnector.java @@ -18,6 +18,7 @@ package com.android.server; import android.net.LocalSocket; import android.net.LocalSocketAddress; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.SystemClock; @@ -105,13 +106,24 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo return true; } + private LocalSocketAddress determineSocketAddress() { + // If we're testing, set up a socket in a namespace that's accessible to test code. + // In order to ensure that unprivileged apps aren't able to impersonate native daemons on + // production devices, even if said native daemons ill-advisedly pick a socket name that + // starts with __test__, only allow this on debug builds. + if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) { + return new LocalSocketAddress(mSocket); + } else { + return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); + } + } + private void listenToSocket() throws IOException { LocalSocket socket = null; try { socket = new LocalSocket(); - LocalSocketAddress address = new LocalSocketAddress(mSocket, - LocalSocketAddress.Namespace.RESERVED); + LocalSocketAddress address = determineSocketAddress(); socket.connect(address); From 73c92d5077187e1a3fa23a156d26838667f3198c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Sep 2013 21:03:27 -0700 Subject: [PATCH 0199/1150] Request all tethering interfaces, fix corruption. netd now tracks statistics for tethered interfaces across tethering sessions, so switch to asking for all tethering stats. (Currently we're double-counting all tethering data, ever since it started tracking across sessions.) Also catch OOME to handle corrupt stats files, which we then dump to DropBox and then start over. Bug: 5868832, 9796109 Change-Id: I2eb2a1bf01b993dd198597d770fe0e022466c6b9 --- .../com/android/server/net/NetworkStatsRecorder.java | 9 +++++++++ .../java/com/android/server/net/NetworkStatsService.java | 5 +++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/java/com/android/server/net/NetworkStatsRecorder.java index 2b32b41506..cea084b518 100644 --- a/services/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/java/com/android/server/net/NetworkStatsRecorder.java @@ -135,6 +135,9 @@ public class NetworkStatsRecorder { } catch (IOException e) { Log.wtf(TAG, "problem completely reading network stats", e); recoverFromWtf(); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem completely reading network stats", e); + recoverFromWtf(); } } return complete; @@ -226,6 +229,9 @@ public class NetworkStatsRecorder { } catch (IOException e) { Log.wtf(TAG, "problem persisting pending stats", e); recoverFromWtf(); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem persisting pending stats", e); + recoverFromWtf(); } } } @@ -241,6 +247,9 @@ public class NetworkStatsRecorder { } catch (IOException e) { Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); recoverFromWtf(); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); + recoverFromWtf(); } // Remove any pending stats diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 05eeb36195..1e8a7b0176 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -412,6 +412,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } catch (IOException e) { Log.wtf(TAG, "problem during legacy upgrade", e); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem during legacy upgrade", e); } } @@ -1186,8 +1188,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private NetworkStats getNetworkStatsTethering() throws RemoteException { try { - final String[] tetheredIfacePairs = mConnManager.getTetheredIfacePairs(); - return mNetworkManager.getNetworkStatsTethering(tetheredIfacePairs); + return mNetworkManager.getNetworkStatsTethering(); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); return new NetworkStats(0L, 10); From e91f98c61d5a077b42705de636a076e3a451921d Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 18 Sep 2013 16:28:50 -0700 Subject: [PATCH 0200/1150] Use a separate thread for services that do NTP lookup Some services do periodic network time lookups and can wedge the other operations on BackgroundThread and IO Thread, causing Watchdog to kill the runtime. So best to put those handlers on separate threads. Going forward, should convert NTP lookups to be async with callbacks. Bug: 10646480 Change-Id: I8c7ba6052cb3539575712c2099a706b14ff60196 --- .../java/com/android/server/net/NetworkStatsService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 1e8a7b0176..5d6adc2268 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -96,6 +96,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; @@ -119,7 +120,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; -import com.android.server.IoThread; import com.android.server.connectivity.Tethering; import com.google.android.collect.Maps; @@ -270,7 +270,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mHandler = new Handler(IoThread.get().getLooper(), mHandlerCallback); + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mHandler = new Handler(thread.getLooper(), mHandlerCallback); mSystemDir = checkNotNull(systemDir); mBaseDir = new File(systemDir, "netstats"); From 109acc1b1566729d39be41324830572c05ebcdd8 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 18 Sep 2013 16:28:50 -0700 Subject: [PATCH 0201/1150] Use a separate thread for services that do NTP lookup Some services do periodic network time lookups and can wedge the other operations on BackgroundThread and IO Thread, causing Watchdog to kill the runtime. So best to put those handlers on separate threads. Going forward, should convert NTP lookups to be async with callbacks. Bug: 10646480 Change-Id: I8c7ba6052cb3539575712c2099a706b14ff60196 --- .../java/com/android/server/net/NetworkStatsService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 1e8a7b0176..5d6adc2268 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -96,6 +96,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; @@ -119,7 +120,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; -import com.android.server.IoThread; import com.android.server.connectivity.Tethering; import com.google.android.collect.Maps; @@ -270,7 +270,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Context.POWER_SERVICE); mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mHandler = new Handler(IoThread.get().getLooper(), mHandlerCallback); + HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mHandler = new Handler(thread.getLooper(), mHandlerCallback); mSystemDir = checkNotNull(systemDir); mBaseDir = new File(systemDir, "netstats"); From 9a101919d91907ed71501afbc7fcbfb19dcecf8d Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 7 Oct 2013 14:32:00 -0700 Subject: [PATCH 0202/1150] Fix issue #11113111: `dumpsys activity service` is broken Change-Id: Ie02d27b377c562085ef7eb5dea144ce2f382c11d From cbfd66262ea05e993c42a88818bc66527c286fb5 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Fri, 1 Nov 2013 14:57:30 -0700 Subject: [PATCH 0203/1150] Fix the race condition for b/11458382 Change-Id: I862da57a70283a2afd5d67751aec87fb808760d2 --- .../com/android/server/net/NetworkStatsService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/java/com/android/server/net/NetworkStatsService.java index 5d6adc2268..271e9e9b22 100644 --- a/services/java/com/android/server/net/NetworkStatsService.java +++ b/services/java/com/android/server/net/NetworkStatsService.java @@ -464,21 +464,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsCollection mUidTagComplete; private NetworkStatsCollection getUidComplete() { - if (mUidComplete == null) { - synchronized (mStatsLock) { + synchronized (mStatsLock) { + if (mUidComplete == null) { mUidComplete = mUidRecorder.getOrLoadCompleteLocked(); } + return mUidComplete; } - return mUidComplete; } private NetworkStatsCollection getUidTagComplete() { - if (mUidTagComplete == null) { - synchronized (mStatsLock) { + synchronized (mStatsLock) { + if (mUidTagComplete == null) { mUidTagComplete = mUidTagRecorder.getOrLoadCompleteLocked(); } + return mUidTagComplete; } - return mUidTagComplete; } @Override From 4429e878fb22733cfa2dfae20efceeb8dbf0338b Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Tue, 12 Nov 2013 15:36:37 -0800 Subject: [PATCH 0204/1150] Get rid of a race in NsdService in stopResolveService and getAddrInfo Both requests are made using same id; and there is a chance that stopResolve() is not fully completed when getAddrInfo() is issued. That results getAddrInfo() failure, because both are using same requestId. This change fixes this problem by creating a new unique id to call getAddrInfo() with. Bug: 11597153 Change-Id: I56bd78740e8a40bd31c52705dc797486aff53a50 --- services/java/com/android/server/NsdService.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index e0f415bfea..16d2468e7c 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -483,10 +483,14 @@ public class NsdService extends INsdManager.Stub { clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); stopResolveService(id); - if (!getAddrInfo(id, cooked[3])) { + removeRequestMap(clientId, id, clientInfo); + + int id2 = getUniqueId(); + if (getAddrInfo(id2, cooked[3])) { + storeRequestMap(clientId, id2, clientInfo); + } else { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR, clientId); - removeRequestMap(clientId, id, clientInfo); clientInfo.mResolvedService = null; } break; From 84ae0f4bc6ce39136b504244df636e471732a06e Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Tue, 19 Nov 2013 16:54:46 -0500 Subject: [PATCH 0205/1150] Remove unused imports from frameworks/base. Change-Id: Ia1f99bd2c1105b0b0f70aa614f1f4a67b2840906 --- core/java/android/net/nsd/NsdManager.java | 2 -- services/java/com/android/server/NsdService.java | 10 ---------- 2 files changed, 12 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 9c3e405f44..684020722e 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -19,8 +19,6 @@ package android.net.nsd; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; -import android.os.Binder; -import android.os.IBinder; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 16d2468e7c..74633ae87d 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -26,11 +26,8 @@ import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.os.Binder; -import android.os.Handler; -import android.os.HandlerThread; import android.os.Message; import android.os.Messenger; -import android.os.IBinder; import android.os.UserHandle; import android.provider.Settings; import android.util.Slog; @@ -39,20 +36,13 @@ import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.concurrent.CountDownLatch; -import com.android.internal.app.IBatteryStats; -import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.am.BatteryStatsService; -import com.android.server.NativeDaemonConnector.Command; -import com.android.internal.R; /** * Network Service Discovery Service handles remote service discovery operation requests by From fb4d3e7a4a870e685070a4dfb5b1e02a09b738ac Mon Sep 17 00:00:00 2001 From: Kristian Monsen Date: Wed, 11 Dec 2013 19:46:41 -0800 Subject: [PATCH 0206/1150] Fix one and hide the other warnings from core/jni Most of the warnings are unused parameter from skia functions. Change-Id: I9df57718d117c26b96163f751ccb056ca86ac072 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index ec19f0ab38..0b9ad9b39e 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -80,7 +80,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, stats_line s; int64_t rawTag; if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx, - &s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, + s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 9) { if (s.idx != lastIdx + 1) { ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx); From 9254db342a57ee04908dbcb871f34c99c0113265 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 13 Dec 2013 12:00:26 -0800 Subject: [PATCH 0207/1150] Use java.util.Objects instead on internal API Not needed since java.util.Objects implements all the needed functionality. Change-Id: Icd31d49a9801d1705427f028e9ac927d58e7d34c --- core/java/android/net/NetworkIdentity.java | 8 ++++---- core/java/android/net/NetworkStats.java | 6 +++--- core/java/android/net/NetworkTemplate.java | 13 +++++++------ .../android/server/net/NetworkStatsCollection.java | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 3c67bf9e84..36dd2fdfbc 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -26,7 +26,7 @@ import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; -import com.android.internal.util.Objects; +import java.util.Objects; /** * Network definition that includes strong identity. Analogous to combining @@ -60,7 +60,7 @@ public class NetworkIdentity { @Override public int hashCode() { - return Objects.hashCode(mType, mSubType, mSubscriberId, mNetworkId, mRoaming); + return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming); } @Override @@ -68,8 +68,8 @@ public class NetworkIdentity { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming - && Objects.equal(mSubscriberId, ident.mSubscriberId) - && Objects.equal(mNetworkId, ident.mNetworkId); + && Objects.equals(mSubscriberId, ident.mSubscriberId) + && Objects.equals(mNetworkId, ident.mNetworkId); } return false; } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9cb904d4c4..a7aae2ad36 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -23,12 +23,12 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; -import com.android.internal.util.Objects; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; +import java.util.Objects; /** * Collection of active network statistics. Can contain summary details across @@ -337,7 +337,7 @@ public class NetworkStats implements Parcelable { public int findIndex(String iface, int uid, int set, int tag) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && Objects.equal(iface, this.iface[i])) { + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -362,7 +362,7 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && Objects.equal(iface, this.iface[i])) { + && Objects.equals(iface, this.iface[i])) { return i; } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c189ba4cd6..27197cc8a3 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,8 +34,9 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Objects; /** * Template definition used to generically match {@link NetworkIdentity}, @@ -176,7 +177,7 @@ public class NetworkTemplate implements Parcelable { @Override public int hashCode() { - return Objects.hashCode(mMatchRule, mSubscriberId, mNetworkId); + return Objects.hash(mMatchRule, mSubscriberId, mNetworkId); } @Override @@ -184,8 +185,8 @@ public class NetworkTemplate implements Parcelable { if (obj instanceof NetworkTemplate) { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule - && Objects.equal(mSubscriberId, other.mSubscriberId) - && Objects.equal(mNetworkId, other.mNetworkId); + && Objects.equals(mSubscriberId, other.mSubscriberId) + && Objects.equals(mNetworkId, other.mNetworkId); } return false; } @@ -235,7 +236,7 @@ public class NetworkTemplate implements Parcelable { return true; } else { return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) - && Objects.equal(mSubscriberId, ident.mSubscriberId)); + && Objects.equals(mSubscriberId, ident.mSubscriberId)); } } @@ -280,7 +281,7 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equal( + return Objects.equals( removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); default: return false; diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/java/com/android/server/net/NetworkStatsCollection.java index 3169035786..475482f6dd 100644 --- a/services/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/java/com/android/server/net/NetworkStatsCollection.java @@ -34,7 +34,6 @@ import android.util.AtomicFile; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import com.android.internal.util.Objects; import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -50,6 +49,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import java.util.Objects; import libcore.io.IoUtils; @@ -508,7 +508,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { this.uid = uid; this.set = set; this.tag = tag; - hashCode = Objects.hashCode(ident, uid, set, tag); + hashCode = Objects.hash(ident, uid, set, tag); } @Override @@ -521,7 +521,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { if (obj instanceof Key) { final Key key = (Key) obj; return uid == key.uid && set == key.set && tag == key.tag - && Objects.equal(ident, key.ident); + && Objects.equals(ident, key.ident); } return false; } From 59e808f5491ded962445be7bff490e1fb32480ab Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Fri, 22 Nov 2013 08:25:26 -0800 Subject: [PATCH 0208/1150] Move some system services to separate directories Refactored the directory structure so that services can be optionally excluded. This is step 1. Will be followed by another change that makes it possible to remove services from the build. Change-Id: Ideacedfd34b5e213217ad3ff4ebb21c4a8e73f85 --- .../java/com/android/server/INativeDaemonConnectorCallbacks.java | 0 .../{ => core}/java/com/android/server/NativeDaemonConnector.java | 0 .../java/com/android/server/NativeDaemonConnectorException.java | 0 .../{ => core}/java/com/android/server/NativeDaemonEvent.java | 0 services/{ => core}/java/com/android/server/NsdService.java | 0 .../java/com/android/server/net/NetworkIdentitySet.java | 0 .../java/com/android/server/net/NetworkStatsCollection.java | 0 .../java/com/android/server/net/NetworkStatsRecorder.java | 0 .../java/com/android/server/net/NetworkStatsService.java | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename services/{ => core}/java/com/android/server/INativeDaemonConnectorCallbacks.java (100%) rename services/{ => core}/java/com/android/server/NativeDaemonConnector.java (100%) rename services/{ => core}/java/com/android/server/NativeDaemonConnectorException.java (100%) rename services/{ => core}/java/com/android/server/NativeDaemonEvent.java (100%) rename services/{ => core}/java/com/android/server/NsdService.java (100%) rename services/{ => core}/java/com/android/server/net/NetworkIdentitySet.java (100%) rename services/{ => core}/java/com/android/server/net/NetworkStatsCollection.java (100%) rename services/{ => core}/java/com/android/server/net/NetworkStatsRecorder.java (100%) rename services/{ => core}/java/com/android/server/net/NetworkStatsService.java (100%) diff --git a/services/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java similarity index 100% rename from services/java/com/android/server/INativeDaemonConnectorCallbacks.java rename to services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java similarity index 100% rename from services/java/com/android/server/NativeDaemonConnector.java rename to services/core/java/com/android/server/NativeDaemonConnector.java diff --git a/services/java/com/android/server/NativeDaemonConnectorException.java b/services/core/java/com/android/server/NativeDaemonConnectorException.java similarity index 100% rename from services/java/com/android/server/NativeDaemonConnectorException.java rename to services/core/java/com/android/server/NativeDaemonConnectorException.java diff --git a/services/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java similarity index 100% rename from services/java/com/android/server/NativeDaemonEvent.java rename to services/core/java/com/android/server/NativeDaemonEvent.java diff --git a/services/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java similarity index 100% rename from services/java/com/android/server/NsdService.java rename to services/core/java/com/android/server/NsdService.java diff --git a/services/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java similarity index 100% rename from services/java/com/android/server/net/NetworkIdentitySet.java rename to services/core/java/com/android/server/net/NetworkIdentitySet.java diff --git a/services/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java similarity index 100% rename from services/java/com/android/server/net/NetworkStatsCollection.java rename to services/core/java/com/android/server/net/NetworkStatsCollection.java diff --git a/services/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java similarity index 100% rename from services/java/com/android/server/net/NetworkStatsRecorder.java rename to services/core/java/com/android/server/net/NetworkStatsRecorder.java diff --git a/services/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java similarity index 100% rename from services/java/com/android/server/net/NetworkStatsService.java rename to services/core/java/com/android/server/net/NetworkStatsService.java From fe6e53b48cac3e46cbd6b2782cf40253e0ff6b8c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Fri, 21 Feb 2014 16:19:05 -0800 Subject: [PATCH 0209/1150] Improve how battery stats collects network stats. This optimizes the path for battery stats to collect per-uid network usage. It now collects wifi and mobile usage separately, with a path that allows it to recycle all data structures and filter out stats it isn't interested in before they come back to java. This is setting us up for the actual goal, to collect mobile stats independently each time the mobile radio goes down, allowing us to distribute mobile radio usage across uids based on the number of packets they transferred during a session. Change-Id: I21a0f517cf087ea5aa8b8dd535e20b46e361a52b --- core/java/android/net/NetworkStats.java | 72 +++++-- .../internal/net/NetworkStatsFactory.java | 33 ++- ...droid_internal_net_NetworkStatsFactory.cpp | 193 +++++++++++++++--- 3 files changed, 243 insertions(+), 55 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index a7aae2ad36..25514f4c25 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -44,6 +44,8 @@ public class NetworkStats implements Parcelable { public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; + /** {@link #tag} value matching any tag. */ + public static final int TAG_ALL = -1; /** {@link #set} value when all sets combined. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ @@ -59,8 +61,9 @@ public class NetworkStats implements Parcelable { * {@link SystemClock#elapsedRealtime()} timestamp when this data was * generated. */ - private final long elapsedRealtime; + private long elapsedRealtime; private int size; + private int capacity; private String[] iface; private int[] uid; private int[] set; @@ -152,20 +155,27 @@ public class NetworkStats implements Parcelable { public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; - this.iface = new String[initialSize]; - this.uid = new int[initialSize]; - this.set = new int[initialSize]; - this.tag = new int[initialSize]; - this.rxBytes = new long[initialSize]; - this.rxPackets = new long[initialSize]; - this.txBytes = new long[initialSize]; - this.txPackets = new long[initialSize]; - this.operations = new long[initialSize]; + if (initialSize >= 0) { + this.capacity = initialSize; + this.iface = new String[initialSize]; + this.uid = new int[initialSize]; + this.set = new int[initialSize]; + this.tag = new int[initialSize]; + this.rxBytes = new long[initialSize]; + this.rxPackets = new long[initialSize]; + this.txBytes = new long[initialSize]; + this.txPackets = new long[initialSize]; + this.operations = new long[initialSize]; + } else { + // Special case for use by NetworkStatsFactory to start out *really* empty. + this.capacity = 0; + } } public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); + capacity = parcel.readInt(); iface = parcel.createStringArray(); uid = parcel.createIntArray(); set = parcel.createIntArray(); @@ -181,6 +191,7 @@ public class NetworkStats implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeLong(elapsedRealtime); dest.writeInt(size); + dest.writeInt(capacity); dest.writeStringArray(iface); dest.writeIntArray(uid); dest.writeIntArray(set); @@ -222,8 +233,8 @@ public class NetworkStats implements Parcelable { * object can be recycled across multiple calls. */ public NetworkStats addValues(Entry entry) { - if (size >= this.iface.length) { - final int newLength = Math.max(iface.length, 10) * 3 / 2; + if (size >= capacity) { + final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); @@ -233,6 +244,7 @@ public class NetworkStats implements Parcelable { txBytes = Arrays.copyOf(txBytes, newLength); txPackets = Arrays.copyOf(txPackets, newLength); operations = Arrays.copyOf(operations, newLength); + capacity = newLength; } iface[size] = entry.iface; @@ -270,6 +282,10 @@ public class NetworkStats implements Parcelable { return elapsedRealtime; } + public void setElapsedRealtime(long time) { + elapsedRealtime = time; + } + /** * Return age of this {@link NetworkStats} object with respect to * {@link SystemClock#elapsedRealtime()}. @@ -284,7 +300,7 @@ public class NetworkStats implements Parcelable { @VisibleForTesting public int internalSize() { - return iface.length; + return capacity; } @Deprecated @@ -507,8 +523,25 @@ public class NetworkStats implements Parcelable { * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. */ - public static NetworkStats subtract( - NetworkStats left, NetworkStats right, NonMonotonicObserver observer, C cookie) { + public static NetworkStats subtract(NetworkStats left, NetworkStats right, + NonMonotonicObserver observer, C cookie) { + return subtract(left, right, observer, cookie, null); + } + + /** + * Subtract the two given {@link NetworkStats} objects, returning the delta + * between two snapshots in time. Assumes that statistics rows collect over + * time, and that none of them have disappeared. + *

+ * If counters have rolled backwards, they are clamped to {@code 0} and + * reported to the given {@link NonMonotonicObserver}. + *

+ * If recycle is supplied, this NetworkStats object will be + * reused (and returned) as the result if it is large enough to contain + * the data. + */ + public static NetworkStats subtract(NetworkStats left, NetworkStats right, + NonMonotonicObserver observer, C cookie, NetworkStats recycle) { long deltaRealtime = left.elapsedRealtime - right.elapsedRealtime; if (deltaRealtime < 0) { if (observer != null) { @@ -519,7 +552,14 @@ public class NetworkStats implements Parcelable { // result will have our rows, and elapsed time between snapshots final Entry entry = new Entry(); - final NetworkStats result = new NetworkStats(deltaRealtime, left.size); + final NetworkStats result; + if (recycle != null && recycle.capacity >= left.size) { + result = recycle; + result.size = 0; + result.elapsedRealtime = deltaRealtime; + } else { + result = new NetworkStats(deltaRealtime, left.size); + } for (int i = 0; i < left.size; i++) { entry.iface = left.iface[i]; entry.uid = left.uid[i]; diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8282d237b3..e2a2b1eb2a 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -17,6 +17,7 @@ package com.android.internal.net; import static android.net.NetworkStats.SET_ALL; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; @@ -26,6 +27,7 @@ import android.os.StrictMode; import android.os.SystemClock; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; import java.io.File; @@ -165,22 +167,32 @@ public class NetworkStatsFactory { } public NetworkStats readNetworkStatsDetail() throws IOException { - return readNetworkStatsDetail(UID_ALL); + return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); } - public NetworkStats readNetworkStatsDetail(int limitUid) throws IOException { + public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, + NetworkStats lastStats) + throws IOException { if (USE_NATIVE_PARSING) { - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0); - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid) != 0) { + final NetworkStats stats; + if (lastStats != null) { + stats = lastStats; + stats.setElapsedRealtime(SystemClock.elapsedRealtime()); + } else { + stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); + } + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, + limitIfaces, limitTag) != 0) { throw new IOException("Failed to parse network stats"); } if (SANITY_CHECK_NATIVE) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid); + final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid, + limitIfaces, limitTag); assertEquals(javaStats, stats); } return stats; } else { - return javaReadNetworkStatsDetail(mStatsXtUid, limitUid); + return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag); } } @@ -189,7 +201,8 @@ public class NetworkStatsFactory { * expected to monotonically increase since device boot. */ @VisibleForTesting - public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid) + public static NetworkStats javaReadNetworkStatsDetail(File detailPath, int limitUid, + String[] limitIfaces, int limitTag) throws IOException { final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -222,7 +235,9 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - if (limitUid == UID_ALL || limitUid == entry.uid) { + if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) + && (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag)) { stats.addValues(entry); } @@ -264,5 +279,5 @@ public class NetworkStatsFactory { */ @VisibleForTesting public static native int nativeReadNetworkStatsDetail( - NetworkStats stats, String path, int limitUid); + NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 0b9ad9b39e..c84a466690 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -37,6 +37,7 @@ static jclass gStringClass; static struct { jfieldID size; + jfieldID capacity; jfieldID iface; jfieldID uid; jfieldID set; @@ -49,7 +50,6 @@ static struct { } gNetworkStatsClassInfo; struct stats_line { - int32_t idx; char iface[32]; int32_t uid; int32_t set; @@ -60,8 +60,41 @@ struct stats_line { int64_t txPackets; }; +static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) +{ + if (!grow) { + jobjectArray array = (jobjectArray)env->GetObjectField(obj, field); + if (array != NULL) { + return array; + } + } + return env->NewObjectArray(size, gStringClass, NULL); +} + +static jintArray get_int_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) +{ + if (!grow) { + jintArray array = (jintArray)env->GetObjectField(obj, field); + if (array != NULL) { + return array; + } + } + return env->NewIntArray(size); +} + +static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) +{ + if (!grow) { + jlongArray array = (jlongArray)env->GetObjectField(obj, field); + if (array != NULL) { + return array; + } + } + return env->NewLongArray(size); +} + static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, - jstring path, jint limitUid) { + jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) { ScopedUtfChars path8(env, path); if (path8.c_str() == NULL) { return -1; @@ -72,50 +105,146 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, return -1; } + Vector limitIfaces; + if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { + int num = env->GetArrayLength(limitIfacesObj); + limitIfaces.setCapacity(num); + for (int i=0; iGetObjectArrayElement(limitIfacesObj, i); + ScopedUtfChars string8(env, string); + if (string8.c_str() != NULL) { + limitIfaces.add(String8(string8.c_str())); + } + } + } + Vector lines; int lastIdx = 1; + int idx; char buffer[384]; while (fgets(buffer, sizeof(buffer), fp) != NULL) { stats_line s; int64_t rawTag; - if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx, - s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, - &s.txBytes, &s.txPackets) == 9) { - if (s.idx != lastIdx + 1) { - ALOGE("inconsistent idx=%d after lastIdx=%d", s.idx, lastIdx); - return -1; + char* pos = buffer; + char* endPos; + // First field is the index. + idx = (int)strtol(pos, &endPos, 10); + //ALOGI("Index #%d: %s", idx, buffer); + if (pos == endPos) { + // Skip lines that don't start with in index. In particular, + // this will skip the initial header line. + continue; + } + if (idx != lastIdx + 1) { + ALOGE("inconsistent idx=%d after lastIdx=%d: %s", idx, lastIdx, buffer); + fclose(fp); + return -1; + } + lastIdx = idx; + pos = endPos; + // Skip whitespace. + while (*pos == ' ') { + pos++; + } + // Next field is iface. + int ifaceIdx = 0; + while (*pos != ' ' && *pos != 0 && ifaceIdx < (int)(sizeof(s.iface)-1)) { + s.iface[ifaceIdx] = *pos; + ifaceIdx++; + pos++; + } + if (*pos != ' ') { + ALOGE("bad iface: %s", buffer); + fclose(fp); + return -1; + } + s.iface[ifaceIdx] = 0; + if (limitIfaces.size() > 0) { + // Is this an iface the caller is interested in? + int i = 0; + while (i < (int)limitIfaces.size()) { + if (limitIfaces[i] == s.iface) { + break; + } + i++; + } + if (i >= (int)limitIfaces.size()) { + // Nothing matched; skip this line. + //ALOGI("skipping due to iface: %s", buffer); + continue; + } + } + // Skip whitespace. + while (*pos == ' ') { + pos++; + } + // Next field is tag. + rawTag = strtoll(pos, &endPos, 16); + //ALOGI("Index #%d: %s", idx, buffer); + if (pos == endPos) { + ALOGE("bad tag: %s", pos); + fclose(fp); + return -1; + } + s.tag = rawTag >> 32; + if (limitTag != -1 && s.tag != limitTag) { + //ALOGI("skipping due to tag: %s", buffer); + continue; + } + pos = endPos; + // Skip whitespace. + while (*pos == ' ') { + pos++; + } + // Parse remaining fields. + if (sscanf(pos, "%u %u %llu %llu %llu %llu", + &s.uid, &s.set, &s.rxBytes, &s.rxPackets, + &s.txBytes, &s.txPackets) == 6) { + if (limitUid != -1 && limitUid != s.uid) { + //ALOGI("skipping due to uid: %s", buffer); + continue; } - lastIdx = s.idx; - - s.tag = rawTag >> 32; lines.push_back(s); + } else { + //ALOGI("skipping due to bad remaining fields: %s", pos); } } if (fclose(fp) != 0) { + ALOGE("Failed to close netstats file"); return -1; } int size = lines.size(); + bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); - ScopedLocalRef iface(env, env->NewObjectArray(size, gStringClass, NULL)); + ScopedLocalRef iface(env, get_string_array(env, stats, + gNetworkStatsClassInfo.iface, size, grow)); if (iface.get() == NULL) return -1; - ScopedIntArrayRW uid(env, env->NewIntArray(size)); + ScopedIntArrayRW uid(env, get_int_array(env, stats, + gNetworkStatsClassInfo.uid, size, grow)); if (uid.get() == NULL) return -1; - ScopedIntArrayRW set(env, env->NewIntArray(size)); + ScopedIntArrayRW set(env, get_int_array(env, stats, + gNetworkStatsClassInfo.set, size, grow)); if (set.get() == NULL) return -1; - ScopedIntArrayRW tag(env, env->NewIntArray(size)); + ScopedIntArrayRW tag(env, get_int_array(env, stats, + gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; - ScopedLongArrayRW rxBytes(env, env->NewLongArray(size)); + ScopedLongArrayRW rxBytes(env, get_long_array(env, stats, + gNetworkStatsClassInfo.rxBytes, size, grow)); if (rxBytes.get() == NULL) return -1; - ScopedLongArrayRW rxPackets(env, env->NewLongArray(size)); + ScopedLongArrayRW rxPackets(env, get_long_array(env, stats, + gNetworkStatsClassInfo.rxPackets, size, grow)); if (rxPackets.get() == NULL) return -1; - ScopedLongArrayRW txBytes(env, env->NewLongArray(size)); + ScopedLongArrayRW txBytes(env, get_long_array(env, stats, + gNetworkStatsClassInfo.txBytes, size, grow)); if (txBytes.get() == NULL) return -1; - ScopedLongArrayRW txPackets(env, env->NewLongArray(size)); + ScopedLongArrayRW txPackets(env, get_long_array(env, stats, + gNetworkStatsClassInfo.txPackets, size, grow)); if (txPackets.get() == NULL) return -1; - ScopedLongArrayRW operations(env, env->NewLongArray(size)); + ScopedLongArrayRW operations(env, get_long_array(env, stats, + gNetworkStatsClassInfo.operations, size, grow)); if (operations.get() == NULL) return -1; for (int i = 0; i < size; i++) { @@ -132,15 +261,18 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, } env->SetIntField(stats, gNetworkStatsClassInfo.size, size); - env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get()); - env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); - env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); + if (grow) { + env->SetIntField(stats, gNetworkStatsClassInfo.capacity, size); + env->SetObjectField(stats, gNetworkStatsClassInfo.iface, iface.get()); + env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); + } return 0; } @@ -157,7 +289,7 @@ static jclass findClass(JNIEnv* env, const char* name) { static JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;Ljava/lang/String;I)I", + "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", (void*) readNetworkStatsDetail } }; @@ -170,6 +302,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { jclass clazz = env->FindClass("android/net/NetworkStats"); gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); + gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); From 4cba7916fae4c1fa8d1d9d8c8c9efaf507638f2b Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 26 Feb 2014 12:35:32 -0800 Subject: [PATCH 0210/1150] Collect per-uid mobile radio usage. We now compute radio active time per application, by distributing the active time across all applications each time the radio goes down, weighting it by the number of packets transferred. Per-app radio power use is now computed using this radio active time. This also gives us a new metric "ms per packet", which give an idea of how effectively an application is using the radio. This is collected and reported as a new set of stats in the human- readable checkin. (It can be computed from the raw checkin data). Also improve sync reporting to include the sync source as used in wake locks, not just the component name. Change-Id: I0b0185fadd1e47ae749090ed36728ab78ac24c5e --- core/java/android/net/NetworkStats.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25514f4c25..54d43d380a 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -506,6 +506,17 @@ public class NetworkStats implements Parcelable { return entry; } + /** + * Fast path for battery stats. + */ + public long getTotalPackets() { + long total = 0; + for (int i = size-1; i >= 0; i--) { + total += rxPackets[i] + txPackets[i]; + } + return total; + } + /** * Subtract the given {@link NetworkStats}, effectively leaving the delta * between two snapshots in time. Assumes that statistics rows collect over From 9cd0fea5194594038fb749c6fc200aeae3e327e1 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 26 Feb 2014 16:20:52 -0800 Subject: [PATCH 0211/1150] Hold a wake lock while dispatching network activity events. Also add new API for determining whether the current data network is active, and thus better scheduling network operations. This API is designed to not be tied to a mobile network -- regardless of the network, apps can use it to determine whether they should initiate activity or wait. On non-mobile networks, it simply always reports as the network being active. This changed involved reworking how the idle timers are done so that we only register an idle timer with the current default network. This way, we can know whether we currently expect to get callbacks about the network being active, or should just always report that it is active. (Ultimately we need to be getting this radio active data from the radio itself.) Change-Id: Iaf6cc91a960d7542a70b72f87a7db26d12c4ea8e --- .../INativeDaemonConnectorCallbacks.java | 1 + .../android/server/NativeDaemonConnector.java | 28 +++++++++++++++++-- .../java/com/android/server/NsdService.java | 6 +++- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java index 6fbf713d3f..0cf9dcde01 100644 --- a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java +++ b/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java @@ -20,5 +20,6 @@ package com.android.server; interface INativeDaemonConnectorCallbacks { void onDaemonConnected(); + boolean onCheckHoldWakeLock(int code); boolean onEvent(int code, String raw, String[] cooked); } diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 417d6d81cd..265b95704b 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -21,6 +21,7 @@ import android.net.LocalSocketAddress; import android.os.Build; import android.os.Handler; import android.os.Message; +import android.os.PowerManager; import android.os.SystemClock; import android.util.LocalLog; import android.util.Slog; @@ -56,6 +57,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private final ResponseQueue mResponseQueue; + private final PowerManager.WakeLock mWakeLock; + private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; @@ -70,10 +73,14 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private final int BUFFER_SIZE = 4096; NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag, int maxLogSize) { + int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new ResponseQueue(responseQueueSize); + mWakeLock = wl; + if (mWakeLock != null) { + mWakeLock.setReferenceCounted(true); + } mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); @@ -102,6 +109,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } catch (Exception e) { loge("Error handling '" + event + "': " + e); + } finally { + if (mCallbacks.onCheckHoldWakeLock(msg.what)) { + mWakeLock.release(); + } } return true; } @@ -154,18 +165,29 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo buffer, start, i - start, StandardCharsets.UTF_8); log("RCV <- {" + rawEvent + "}"); + boolean releaseWl = false; try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( rawEvent); if (event.isClassUnsolicited()) { // TODO: migrate to sending NativeDaemonEvent instances - mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( - event.getCode(), event.getRawEvent())); + if (mCallbacks.onCheckHoldWakeLock(event.getCode())) { + mWakeLock.acquire(); + releaseWl = true; + } + if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( + event.getCode(), event.getRawEvent()))) { + releaseWl = false; + } } else { mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { log("Problem parsing message: " + rawEvent + " - " + e); + } finally { + if (releaseWl) { + mWakeLock.acquire(); + } } start = i + 1; diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 74633ae87d..c9f9a25666 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -534,7 +534,7 @@ public class NsdService extends INsdManager.Stub { mContentResolver = context.getContentResolver(); mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10, - MDNS_TAG, 25); + MDNS_TAG, 25, null); mNsdStateMachine = new NsdStateMachine(TAG); mNsdStateMachine.start(); @@ -622,6 +622,10 @@ public class NsdService extends INsdManager.Stub { mNativeDaemonConnected.countDown(); } + public boolean onCheckHoldWakeLock(int code) { + return false; + } + public boolean onEvent(int code, String raw, String[] cooked) { // TODO: NDC translates a message to a callback, we could enhance NDC to // directly interact with a state machine through messages From a6dc93df7ba11ab30c05a266f880ad3f5135d48e Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Thu, 27 Feb 2014 16:16:20 -0800 Subject: [PATCH 0212/1150] Harden NsdManager against null-dereference crashes Due to race conditions or programming errors, the NsdManager can attempt to process an asynchronous status message (and issue a callback to the listener) after the listener has already been removed from the NsdManager state. This causes dereferencing of null objects, and a crash. Split out the three async-queue message cases: these are ones in which message.arg2 does not hold an NsdManager array index and the code should not interpret this field as if it were. Add an explicit check for "null listener" (the array index in the message has already been released), log a warning, and exit early. Safeguard accesses to the "NSD service type" string from a (possibly null) NsdServiceInfo object... return a constant "?" string rather than crashing. Bug: 9016259 Change-Id: I40aabdfc65d86fdd0eaac7a1e7e56e6ff69796cf --- core/java/android/net/nsd/NsdManager.java | 47 ++++++++++++++--------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 9c3e405f44..7b2c623140 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -301,27 +301,36 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - Object listener = getListener(message.arg2); - boolean listenerRemove = true; switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - break; + return; case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: mConnected.countDown(); - break; + return; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: Log.e(TAG, "Channel lost"); + return; + default: break; + } + Object listener = getListener(message.arg2); + if (listener == null) { + Log.d(TAG, "Stale key " + message.arg2); + return; + } + boolean listenerRemove = true; + NsdServiceInfo ns = getNsdService(message.arg2); + switch (message.what) { case DISCOVER_SERVICES_STARTED: - String s = ((NsdServiceInfo) message.obj).getServiceType(); + String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); // Keep listener until stop discovery listenerRemove = false; break; case DISCOVER_SERVICES_FAILED: - ((DiscoveryListener) listener).onStartDiscoveryFailed( - getNsdService(message.arg2).getServiceType(), message.arg1); + ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), + message.arg1); break; case SERVICE_FOUND: ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); @@ -334,16 +343,14 @@ public final class NsdManager { listenerRemove = false; break; case STOP_DISCOVERY_FAILED: - ((DiscoveryListener) listener).onStopDiscoveryFailed( - getNsdService(message.arg2).getServiceType(), message.arg1); + ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), + message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - ((DiscoveryListener) listener).onDiscoveryStopped( - getNsdService(message.arg2).getServiceType()); + ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - ((RegistrationListener) listener).onRegistrationFailed( - getNsdService(message.arg2), message.arg1); + ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: ((RegistrationListener) listener).onServiceRegistered( @@ -352,16 +359,13 @@ public final class NsdManager { listenerRemove = false; break; case UNREGISTER_SERVICE_FAILED: - ((RegistrationListener) listener).onUnregistrationFailed( - getNsdService(message.arg2), message.arg1); + ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: - ((RegistrationListener) listener).onServiceUnregistered( - getNsdService(message.arg2)); + ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - ((ResolveListener) listener).onResolveFailed( - getNsdService(message.arg2), message.arg1); + ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); @@ -421,6 +425,11 @@ public final class NsdManager { } + private String getNsdServiceInfoType(NsdServiceInfo s) { + if (s == null) return "?"; + return s.getServiceType(); + } + /** * Initialize AsyncChannel */ From feff2af5c0ed726bb84bb9c979ddf921bd328a6f Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Fri, 7 Mar 2014 14:48:22 -0800 Subject: [PATCH 0213/1150] NsdService does not clean up after exiting clients When a client of the NsdService exits, NsdService should clean up the requests it has sent to the mDNS daemon: cancel any pending resource-discovery and resource-resolution queries, and remove any services registered by this client. If this isn't done, several bad things happen. The daemon will continue to run unnecessarily, will report service discoveries that can't be forwarded on to the client, and will continue to advertise service ports for an application which is no longer running until the device is rebooted (mDNS pollution). Bug: 9801184 Change-Id: I0aa7311480322aefcff16f902fbbf34f50985d38 --- .../java/com/android/server/NsdService.java | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/services/java/com/android/server/NsdService.java b/services/java/com/android/server/NsdService.java index 16d2468e7c..93799550dc 100644 --- a/services/java/com/android/server/NsdService.java +++ b/services/java/com/android/server/NsdService.java @@ -152,25 +152,40 @@ public class NsdService extends INsdManager.Stub { class DefaultState extends State { @Override public boolean processMessage(Message msg) { + ClientInfo cInfo = null; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { AsyncChannel c = (AsyncChannel) msg.obj; if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + cInfo = new ClientInfo(c, msg.replyTo); mClients.put(msg.replyTo, cInfo); } else { Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + switch (msg.arg1) { + case AsyncChannel.STATUS_SEND_UNSUCCESSFUL: + Slog.e(TAG, "Send failed, client connection lost"); + break; + case AsyncChannel.STATUS_REMOTE_DISCONNECTION: + if (DBG) Slog.d(TAG, "Client disconnected"); + break; + default: + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + break; + } + cInfo = mClients.get(msg.replyTo); + if (cInfo != null) { + cInfo.expungeAllRequests(); + mClients.remove(msg.replyTo); + } + //Last client + if (mClients.size() == 0) { + stopMDnsDaemon(); } - mClients.remove(msg.replyTo); break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -248,13 +263,15 @@ public class NsdService extends INsdManager.Stub { return false; } - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { clientInfo.mClientIds.put(clientId, globalId); + clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.remove(clientId); + clientInfo.mClientRequests.remove(clientId); mIdToClientInfoMap.remove(globalId); } @@ -274,10 +291,6 @@ public class NsdService extends INsdManager.Stub { result = NOT_HANDLED; break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - //Last client - if (mClients.size() == 1) { - stopMDnsDaemon(); - } result = NOT_HANDLED; break; case NsdManager.DISABLE: @@ -301,7 +314,7 @@ public class NsdService extends INsdManager.Stub { Slog.d(TAG, "Discover " + msg.arg2 + " " + id + servInfo.getServiceType()); } - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); } else { stopServiceDiscovery(id); @@ -340,7 +353,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); // Return success after mDns reports success } else { unregisterService(id); @@ -381,7 +394,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); } else { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -487,7 +500,7 @@ public class NsdService extends INsdManager.Stub { int id2 = getUniqueId(); if (getAddrInfo(id2, cooked[3])) { - storeRequestMap(clientId, id2, clientInfo); + storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR, clientId); @@ -827,6 +840,9 @@ public class NsdService extends INsdManager.Stub { /* A map from client id to unique id sent to mDns */ private SparseArray mClientIds = new SparseArray(); + /* A map from client id to the type of the request we had received */ + private SparseArray mClientRequests = new SparseArray(); + private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; mMessenger = m; @@ -840,10 +856,41 @@ public class NsdService extends INsdManager.Stub { sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); for(int i = 0; i< mClientIds.size(); i++) { - sb.append("clientId ").append(mClientIds.keyAt(i)); - sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n"); + int clientID = mClientIds.keyAt(i); + sb.append("clientId ").append(clientID). + append(" mDnsId ").append(mClientIds.valueAt(i)). + append(" type ").append(mClientRequests.get(clientID)).append("\n"); } return sb.toString(); } + + // Remove any pending requests from the global map when we get rid of a client, + // and send cancellations to the daemon. + private void expungeAllRequests() { + int globalId, clientId, i; + for (i = 0; i < mClientIds.size(); i++) { + clientId = mClientIds.keyAt(i); + globalId = mClientIds.valueAt(i); + mIdToClientInfoMap.remove(globalId); + if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId + + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + switch (mClientRequests.get(clientId)) { + case NsdManager.DISCOVER_SERVICES: + stopServiceDiscovery(globalId); + break; + case NsdManager.RESOLVE_SERVICE: + stopResolveService(globalId); + break; + case NsdManager.REGISTER_SERVICE: + unregisterService(globalId); + break; + default: + break; + } + } + mClientIds.clear(); + mClientRequests.clear(); + } + } } From febcdae1ba1ac3c0e10e2bd9c3f53f8d53af8a24 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Thu, 13 Mar 2014 17:27:03 -0700 Subject: [PATCH 0214/1150] Harden NsdManager against null-dereference crashes Due to race conditions or programming errors, the NsdManager can attempt to process an asynchronous status message (and issue a callback to the listener) after the listener has already been removed from the NsdManager state. This causes dereferencing of null objects, and a crash. Split out the three async-queue message cases: these are ones in which message.arg2 does not hold an NsdManager array index and the code should not interpret this field as if it were. Add an explicit check for "null listener" (the array index in the message has already been released), log a warning, and exit early. Safeguard accesses to the "NSD service type" string from a possibly null) NsdServiceInfo object... return a constant "?" string rather than crashing. Bug: 9016259 Manual cherrypick of commit b1fbb14122a99c62363a949dd634294f5e887ef, change-ID I7a6ff6842cf035cefbafe2a023ae1fd43734081e in master. Change-Id: I8d9b7a1763d47d061a0f46b3cb453de4bdb8c2ed --- core/java/android/net/nsd/NsdManager.java | 47 ++++++++++++++--------- 1 file changed, 28 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 9c3e405f44..7b2c623140 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -301,27 +301,36 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - Object listener = getListener(message.arg2); - boolean listenerRemove = true; switch (message.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - break; + return; case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: mConnected.countDown(); - break; + return; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: Log.e(TAG, "Channel lost"); + return; + default: break; + } + Object listener = getListener(message.arg2); + if (listener == null) { + Log.d(TAG, "Stale key " + message.arg2); + return; + } + boolean listenerRemove = true; + NsdServiceInfo ns = getNsdService(message.arg2); + switch (message.what) { case DISCOVER_SERVICES_STARTED: - String s = ((NsdServiceInfo) message.obj).getServiceType(); + String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); // Keep listener until stop discovery listenerRemove = false; break; case DISCOVER_SERVICES_FAILED: - ((DiscoveryListener) listener).onStartDiscoveryFailed( - getNsdService(message.arg2).getServiceType(), message.arg1); + ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), + message.arg1); break; case SERVICE_FOUND: ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); @@ -334,16 +343,14 @@ public final class NsdManager { listenerRemove = false; break; case STOP_DISCOVERY_FAILED: - ((DiscoveryListener) listener).onStopDiscoveryFailed( - getNsdService(message.arg2).getServiceType(), message.arg1); + ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), + message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - ((DiscoveryListener) listener).onDiscoveryStopped( - getNsdService(message.arg2).getServiceType()); + ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - ((RegistrationListener) listener).onRegistrationFailed( - getNsdService(message.arg2), message.arg1); + ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: ((RegistrationListener) listener).onServiceRegistered( @@ -352,16 +359,13 @@ public final class NsdManager { listenerRemove = false; break; case UNREGISTER_SERVICE_FAILED: - ((RegistrationListener) listener).onUnregistrationFailed( - getNsdService(message.arg2), message.arg1); + ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: - ((RegistrationListener) listener).onServiceUnregistered( - getNsdService(message.arg2)); + ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - ((ResolveListener) listener).onResolveFailed( - getNsdService(message.arg2), message.arg1); + ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); @@ -421,6 +425,11 @@ public final class NsdManager { } + private String getNsdServiceInfoType(NsdServiceInfo s) { + if (s == null) return "?"; + return s.getServiceType(); + } + /** * Initialize AsyncChannel */ From 87522f50e18e54bf559cb4ad1a0389f0d964555c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 24 Mar 2014 13:36:46 -0700 Subject: [PATCH 0215/1150] Battery stats: wake locks, radio active, cleanup. - Improve wake lock work source updates to also update the current history tag, in case the new work source gets recorded in the history. - Fix bug in recording radio active time that was not distributing any time to apps. - No longer hold a wake lock while dispatching data conn active call, since it comes with its own timestamp. - Fix issue where the top app was not being cleared while the screen was off. - Remove obsolete STATS_LAST stats type. - Fix bug that was not clearing the total run time when resetting the stats. Change-Id: Iabe17a9edf34f762374ae09fcffb8a819cf72e30 --- .../core/java/com/android/server/NativeDaemonConnector.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 265b95704b..62eb6632eb 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -110,7 +110,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } catch (Exception e) { loge("Error handling '" + event + "': " + e); } finally { - if (mCallbacks.onCheckHoldWakeLock(msg.what)) { + if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) { mWakeLock.release(); } } @@ -171,7 +171,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo rawEvent); if (event.isClassUnsolicited()) { // TODO: migrate to sending NativeDaemonEvent instances - if (mCallbacks.onCheckHoldWakeLock(event.getCode())) { + if (mCallbacks.onCheckHoldWakeLock(event.getCode()) + && mWakeLock != null) { mWakeLock.acquire(); releaseWl = true; } From 4cba56df4e9c2917ee10cf6f2eb06c0494b10047 Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Fri, 28 Mar 2014 13:33:04 -0700 Subject: [PATCH 0216/1150] Document and enforce "one request per Listener" rule The API and implementation of NsdManager imply that a separate Listener is to be used for each active registration or discovery request. This isn't formally documented or properly enforced, and weird and unpredictable things happen if an application uses a Listener for more than one request at a time. Update documentation to make this an explicit requirement. Enforce the restriction when a new request is submitted for processing; if the Listener is already being used to track an active request, throw an exception. Document the fact that apps should unregister services and cancel service discoveries when the app is stopped (in KitKat and prior releases, they'll leak if this isn't done.) Re-order "release the Listener" operation to occur before the Listener callback, so that the Listener can be reused by the application once the callback has been entered - this eliminates a race condition. Document this. Pass 2: typos, added documentation about API level, changed to using an explicitly defined return value for "busy listener". Bug: 13512512 Change-Id: Ic164110759204b27d8a14376777b593ebe1865fa --- core/java/android/net/nsd/NsdManager.java | 82 ++++++++++++++++------- 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index d8e8e2c2de..377ed88997 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -211,6 +211,7 @@ public final class NsdManager { private Context mContext; private static final int INVALID_LISTENER_KEY = 0; + private static final int BUSY_LISTENER_KEY = -1; private int mListenerKey = 1; private final SparseArray mListenerMap = new SparseArray(); private final SparseArray mServiceMap = new SparseArray(); @@ -317,71 +318,74 @@ public final class NsdManager { Log.d(TAG, "Stale key " + message.arg2); return; } - boolean listenerRemove = true; NsdServiceInfo ns = getNsdService(message.arg2); switch (message.what) { case DISCOVER_SERVICES_STARTED: String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); - // Keep listener until stop discovery - listenerRemove = false; break; case DISCOVER_SERVICES_FAILED: + removeListener(message.arg2); ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case SERVICE_FOUND: ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); - // Keep listener until stop discovery - listenerRemove = false; break; case SERVICE_LOST: ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); - // Keep listener until stop discovery - listenerRemove = false; break; case STOP_DISCOVERY_FAILED: + removeListener(message.arg2); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: + removeListener(message.arg2); ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: + removeListener(message.arg2); ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: ((RegistrationListener) listener).onServiceRegistered( (NsdServiceInfo) message.obj); - // Keep listener until unregister - listenerRemove = false; break; case UNREGISTER_SERVICE_FAILED: + removeListener(message.arg2); ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: + removeListener(message.arg2); ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: + removeListener(message.arg2); ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: + removeListener(message.arg2); ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); break; default: Log.d(TAG, "Ignored " + message); break; } - if (listenerRemove) { - removeListener(message.arg2); - } } } + // if the listener is already in the map, reject it. Otherwise, add it and + // return its key. + private int putListener(Object listener, NsdServiceInfo s) { if (listener == null) return INVALID_LISTENER_KEY; int key; synchronized (mMapLock) { + int valueIndex = mListenerMap.indexOfValue(listener); + if (valueIndex != -1) { + return BUSY_LISTENER_KEY; + } do { key = mListenerKey++; } while (key == INVALID_LISTENER_KEY); @@ -422,7 +426,6 @@ public final class NsdManager { return INVALID_LISTENER_KEY; } - private String getNsdServiceInfoType(NsdServiceInfo s) { if (s == null) return "?"; return s.getServiceType(); @@ -449,14 +452,18 @@ public final class NsdManager { * Register a service to be discovered by other services. * *

The function call immediately returns after sending a request to register service - * to the framework. The application is notified of a success to initiate - * discovery through the callback {@link RegistrationListener#onServiceRegistered} or a failure + * to the framework. The application is notified of a successful registration + * through the callback {@link RegistrationListener#onServiceRegistered} or a failure * through {@link RegistrationListener#onRegistrationFailed}. * + *

The application should call {@link #unregisterService} when the service + * registration is no longer required, and/or whenever the application is stopped. + * * @param serviceInfo The service being registered * @param protocolType The service discovery protocol * @param listener The listener notifies of a successful registration and is used to * unregister this service through a call on {@link #unregisterService}. Cannot be null. + * Cannot be in use for an active service registration. */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { @@ -473,8 +480,11 @@ public final class NsdManager { if (protocolType != PROTOCOL_DNS_SD) { throw new IllegalArgumentException("Unsupported protocol"); } - mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, putListener(listener, serviceInfo), - serviceInfo); + int key = putListener(listener, serviceInfo); + if (key == BUSY_LISTENER_KEY) { + throw new IllegalArgumentException("listener already in use"); + } + mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); } /** @@ -484,7 +494,11 @@ public final class NsdManager { * * @param listener This should be the listener object that was passed to * {@link #registerService}. It identifies the service that should be unregistered - * and notifies of a successful unregistration. + * and notifies of a successful or unsuccessful unregistration via the listener + * callbacks. In API versions 20 and above, the listener object may be used for + * another service registration once the callback has been called. In API versions <= 19, + * there is no entirely reliable way to know when a listener may be re-used, and a new + * listener should be created for each service registration request. */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); @@ -514,12 +528,16 @@ public final class NsdManager { *

Upon failure to start, service discovery is not active and application does * not need to invoke {@link #stopServiceDiscovery} * + *

The application should call {@link #stopServiceDiscovery} when discovery of this + * service type is no longer required, and/or whenever the application is paused or + * stopped. + * * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers * @param protocolType The service discovery protocol * @param listener The listener notifies of a successful discovery and is used * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - * Cannot be null. + * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { if (listener == null) { @@ -535,11 +553,17 @@ public final class NsdManager { NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, putListener(listener, s), s); + + int key = putListener(listener, s); + if (key == BUSY_LISTENER_KEY) { + throw new IllegalArgumentException("listener already in use"); + } + + mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); } /** - * Stop service discovery initiated with {@link #discoverServices}. An active service + * Stop service discovery initiated with {@link #discoverServices}. An active service * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} * and it stays active until the application invokes a stop service discovery. A successful * stop is notified to with a call to {@link DiscoveryListener#onDiscoveryStopped}. @@ -548,7 +572,11 @@ public final class NsdManager { * {@link DiscoveryListener#onStopDiscoveryFailed}. * * @param listener This should be the listener object that was passed to {@link #discoverServices}. - * It identifies the discovery that should be stopped and notifies of a successful stop. + * It identifies the discovery that should be stopped and notifies of a successful or + * unsuccessful stop. In API versions 20 and above, the listener object may be used for + * another service discovery once the callback has been called. In API versions <= 19, + * there is no entirely reliable way to know when a listener may be re-used, and a new + * listener should be created for each service discovery request. */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); @@ -568,6 +596,7 @@ public final class NsdManager { * * @param serviceInfo service to be resolved * @param listener to receive callback upon success or failure. Cannot be null. + * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { if (TextUtils.isEmpty(serviceInfo.getServiceName()) || @@ -577,8 +606,13 @@ public final class NsdManager { if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); } - mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, putListener(listener, serviceInfo), - serviceInfo); + + int key = putListener(listener, serviceInfo); + + if (key == BUSY_LISTENER_KEY) { + throw new IllegalArgumentException("listener already in use"); + } + mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); } /** Internal use only @hide */ From 5da9a4181121e6803ab3d48303f29d3fb3b33b6a Mon Sep 17 00:00:00 2001 From: Dave Platt Date: Thu, 13 Mar 2014 23:35:15 +0000 Subject: [PATCH 0217/1150] Merge "NsdService does not clean up after exiting clients" --- .../java/com/android/server/NsdService.java | 81 +++++++++++++++---- 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 16d2468e7c..93799550dc 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -152,25 +152,40 @@ public class NsdService extends INsdManager.Stub { class DefaultState extends State { @Override public boolean processMessage(Message msg) { + ClientInfo cInfo = null; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { AsyncChannel c = (AsyncChannel) msg.obj; if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - ClientInfo cInfo = new ClientInfo(c, msg.replyTo); + cInfo = new ClientInfo(c, msg.replyTo); mClients.put(msg.replyTo, cInfo); } else { Slog.e(TAG, "Client connection failure, error=" + msg.arg1); } break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { - Slog.e(TAG, "Send failed, client connection lost"); - } else { - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + switch (msg.arg1) { + case AsyncChannel.STATUS_SEND_UNSUCCESSFUL: + Slog.e(TAG, "Send failed, client connection lost"); + break; + case AsyncChannel.STATUS_REMOTE_DISCONNECTION: + if (DBG) Slog.d(TAG, "Client disconnected"); + break; + default: + if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); + break; + } + cInfo = mClients.get(msg.replyTo); + if (cInfo != null) { + cInfo.expungeAllRequests(); + mClients.remove(msg.replyTo); + } + //Last client + if (mClients.size() == 0) { + stopMDnsDaemon(); } - mClients.remove(msg.replyTo); break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -248,13 +263,15 @@ public class NsdService extends INsdManager.Stub { return false; } - private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { + private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) { clientInfo.mClientIds.put(clientId, globalId); + clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.remove(clientId); + clientInfo.mClientRequests.remove(clientId); mIdToClientInfoMap.remove(globalId); } @@ -274,10 +291,6 @@ public class NsdService extends INsdManager.Stub { result = NOT_HANDLED; break; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - //Last client - if (mClients.size() == 1) { - stopMDnsDaemon(); - } result = NOT_HANDLED; break; case NsdManager.DISABLE: @@ -301,7 +314,7 @@ public class NsdService extends INsdManager.Stub { Slog.d(TAG, "Discover " + msg.arg2 + " " + id + servInfo.getServiceType()); } - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); } else { stopServiceDiscovery(id); @@ -340,7 +353,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); // Return success after mDns reports success } else { unregisterService(id); @@ -381,7 +394,7 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(msg.arg2, id, clientInfo); + storeRequestMap(msg.arg2, id, clientInfo, msg.what); } else { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -487,7 +500,7 @@ public class NsdService extends INsdManager.Stub { int id2 = getUniqueId(); if (getAddrInfo(id2, cooked[3])) { - storeRequestMap(clientId, id2, clientInfo); + storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR, clientId); @@ -827,6 +840,9 @@ public class NsdService extends INsdManager.Stub { /* A map from client id to unique id sent to mDns */ private SparseArray mClientIds = new SparseArray(); + /* A map from client id to the type of the request we had received */ + private SparseArray mClientRequests = new SparseArray(); + private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; mMessenger = m; @@ -840,10 +856,41 @@ public class NsdService extends INsdManager.Stub { sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); for(int i = 0; i< mClientIds.size(); i++) { - sb.append("clientId ").append(mClientIds.keyAt(i)); - sb.append(" mDnsId ").append(mClientIds.valueAt(i)).append("\n"); + int clientID = mClientIds.keyAt(i); + sb.append("clientId ").append(clientID). + append(" mDnsId ").append(mClientIds.valueAt(i)). + append(" type ").append(mClientRequests.get(clientID)).append("\n"); } return sb.toString(); } + + // Remove any pending requests from the global map when we get rid of a client, + // and send cancellations to the daemon. + private void expungeAllRequests() { + int globalId, clientId, i; + for (i = 0; i < mClientIds.size(); i++) { + clientId = mClientIds.keyAt(i); + globalId = mClientIds.valueAt(i); + mIdToClientInfoMap.remove(globalId); + if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId + + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + switch (mClientRequests.get(clientId)) { + case NsdManager.DISCOVER_SERVICES: + stopServiceDiscovery(globalId); + break; + case NsdManager.RESOLVE_SERVICE: + stopResolveService(globalId); + break; + case NsdManager.REGISTER_SERVICE: + unregisterService(globalId); + break; + default: + break; + } + } + mClientIds.clear(); + mClientRequests.clear(); + } + } } From 0f2cc36572dfb92542e4e910124b725b79dae96c Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Mon, 17 Mar 2014 16:35:45 -0700 Subject: [PATCH 0218/1150] Add support for custom TXT records in NSD Change-Id: I8e6dc9852ad4d273c71ad6a63a7fbd28a206806d --- core/java/android/net/nsd/NsdServiceInfo.java | 188 +++++++++++++++--- .../java/com/android/server/NsdService.java | 26 ++- 2 files changed, 186 insertions(+), 28 deletions(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 205a21d95b..6fdb0d0f84 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -18,8 +18,15 @@ package android.net.nsd; import android.os.Parcelable; import android.os.Parcel; +import android.util.Log; +import android.util.ArrayMap; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; +import java.nio.charset.StandardCharsets; +import java.util.Collections; +import java.util.Map; + /** * A class representing service information for network service discovery @@ -27,11 +34,13 @@ import java.net.InetAddress; */ public final class NsdServiceInfo implements Parcelable { + private static final String TAG = "NsdServiceInfo"; + private String mServiceName; private String mServiceType; - private DnsSdTxtRecord mTxtRecord; + private final ArrayMap mTxtRecord = new ArrayMap(); private InetAddress mHost; @@ -41,10 +50,9 @@ public final class NsdServiceInfo implements Parcelable { } /** @hide */ - public NsdServiceInfo(String sn, String rt, DnsSdTxtRecord tr) { + public NsdServiceInfo(String sn, String rt) { mServiceName = sn; mServiceType = rt; - mTxtRecord = tr; } /** Get the service name */ @@ -67,16 +75,6 @@ public final class NsdServiceInfo implements Parcelable { mServiceType = s; } - /** @hide */ - public DnsSdTxtRecord getTxtRecord() { - return mTxtRecord; - } - - /** @hide */ - public void setTxtRecord(DnsSdTxtRecord t) { - mTxtRecord = new DnsSdTxtRecord(t); - } - /** Get the host address. The host address is valid for a resolved service. */ public InetAddress getHost() { return mHost; @@ -97,14 +95,134 @@ public final class NsdServiceInfo implements Parcelable { mPort = p; } + /** @hide */ + public void setAttribute(String key, byte[] value) { + // Key must be printable US-ASCII, excluding =. + for (int i = 0; i < key.length(); ++i) { + char character = key.charAt(i); + if (character < 0x20 || character > 0x7E) { + throw new IllegalArgumentException("Key strings must be printable US-ASCII"); + } else if (character == 0x3D) { + throw new IllegalArgumentException("Key strings must not include '='"); + } + } + + // Key length + value length must be < 255. + if (key.length() + (value == null ? 0 : value.length) >= 255) { + throw new IllegalArgumentException("Key length + value length must be < 255 bytes"); + } + + // Warn if key is > 9 characters, as recommended by RFC 6763 section 6.4. + if (key.length() > 9) { + Log.w(TAG, "Key lengths > 9 are discouraged: " + key); + } + + // Check against total TXT record size limits. + // Arbitrary 400 / 1300 byte limits taken from RFC 6763 section 6.2. + int txtRecordSize = getTxtRecordSize(); + int futureSize = txtRecordSize + key.length() + (value == null ? 0 : value.length) + 2; + if (futureSize > 1300) { + throw new IllegalArgumentException("Total length of attributes must be < 1300 bytes"); + } else if (futureSize > 400) { + Log.w(TAG, "Total length of all attributes exceeds 400 bytes; truncation may occur"); + } + + mTxtRecord.put(key, value); + } + + /** + * Add a service attribute as a key/value pair. + * + *

Service attributes are included as DNS-SD TXT record pairs. + * + *

The key must be US-ASCII printable characters, excluding the '=' character. Values may + * be UTF-8 strings or null. The total length of key + value must be less than 255 bytes. + * + *

Keys should be short, ideally no more than 9 characters, and unique per instance of + * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite + * first value. + */ + public void setAttribute(String key, String value) { + try { + setAttribute(key, value == null ? (byte []) null : value.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + throw new IllegalArgumentException("Value must be UTF-8"); + } + } + + /** Remove an attribute by key */ + public void removeAttribute(String key) { + mTxtRecord.remove(key); + } + + /** + * Retrive attributes as a map of String keys to byte[] values. + * + *

The returned map is unmodifiable; changes must be made through {@link #setAttribute} and + * {@link #removeAttribute}. + */ + public Map getAttributes() { + return Collections.unmodifiableMap(mTxtRecord); + } + + private int getTxtRecordSize() { + int txtRecordSize = 0; + for (Map.Entry entry : mTxtRecord.entrySet()) { + txtRecordSize += 2; // One for the length byte, one for the = between key and value. + txtRecordSize += entry.getKey().length(); + byte[] value = entry.getValue(); + txtRecordSize += value == null ? 0 : value.length; + } + return txtRecordSize; + } + + /** @hide */ + public byte[] getTxtRecord() { + int txtRecordSize = getTxtRecordSize(); + if (txtRecordSize == 0) { + return null; + } + + byte[] txtRecord = new byte[txtRecordSize]; + int ptr = 0; + for (Map.Entry entry : mTxtRecord.entrySet()) { + String key = entry.getKey(); + byte[] value = entry.getValue(); + + // One byte to record the length of this key/value pair. + txtRecord[ptr++] = (byte) (key.length() + (value == null ? 0 : value.length) + 1); + + // The key, in US-ASCII. + // Note: use the StandardCharsets const here because it doesn't raise exceptions and we + // already know the key is ASCII at this point. + System.arraycopy(key.getBytes(StandardCharsets.US_ASCII), 0, txtRecord, ptr, + key.length()); + ptr += key.length(); + + // US-ASCII '=' character. + txtRecord[ptr++] = (byte)'='; + + // The value, as any raw bytes. + if (value != null) { + System.arraycopy(value, 0, txtRecord, ptr, value.length); + ptr += value.length; + } + } + return txtRecord; + } + public String toString() { StringBuffer sb = new StringBuffer(); - sb.append("name: ").append(mServiceName). - append("type: ").append(mServiceType). - append("host: ").append(mHost). - append("port: ").append(mPort). - append("txtRecord: ").append(mTxtRecord); + sb.append("name: ").append(mServiceName) + .append(", type: ").append(mServiceType) + .append(", host: ").append(mHost) + .append(", port: ").append(mPort); + + byte[] txtRecord = getTxtRecord(); + if (txtRecord != null) { + sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); + } return sb.toString(); } @@ -117,14 +235,27 @@ public final class NsdServiceInfo implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeString(mServiceName); dest.writeString(mServiceType); - dest.writeParcelable(mTxtRecord, flags); if (mHost != null) { - dest.writeByte((byte)1); + dest.writeInt(1); dest.writeByteArray(mHost.getAddress()); } else { - dest.writeByte((byte)0); + dest.writeInt(0); } dest.writeInt(mPort); + + // TXT record key/value pairs. + dest.writeInt(mTxtRecord.size()); + for (String key : mTxtRecord.keySet()) { + byte[] value = mTxtRecord.get(key); + if (value != null) { + dest.writeInt(1); + dest.writeInt(value.length); + dest.writeByteArray(value); + } else { + dest.writeInt(0); + } + dest.writeString(key); + } } /** Implement the Parcelable interface */ @@ -134,15 +265,26 @@ public final class NsdServiceInfo implements Parcelable { NsdServiceInfo info = new NsdServiceInfo(); info.mServiceName = in.readString(); info.mServiceType = in.readString(); - info.mTxtRecord = in.readParcelable(null); - if (in.readByte() == 1) { + if (in.readInt() == 1) { try { info.mHost = InetAddress.getByAddress(in.createByteArray()); } catch (java.net.UnknownHostException e) {} } info.mPort = in.readInt(); + + // TXT record key/value pairs. + int recordCount = in.readInt(); + for (int i = 0; i < recordCount; ++i) { + byte[] valueArray = null; + if (in.readInt() == 1) { + int valueLength = in.readInt(); + valueArray = new byte[valueLength]; + in.readByteArray(valueArray); + } + info.mTxtRecord.put(in.readString(), valueArray); + } return info; } diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 93799550dc..8df93f1283 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -38,10 +38,13 @@ import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; import java.util.concurrent.CountDownLatch; import com.android.internal.app.IBatteryStats; @@ -443,14 +446,14 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_FOUND: /* NNN uniqueId serviceName regType domain */ if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + servInfo = new NsdServiceInfo(cooked[2], cooked[3]); clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, clientId, servInfo); break; case NativeResponseCode.SERVICE_LOST: /* NNN uniqueId serviceName regType domain */ if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], cooked[3], null); + servInfo = new NsdServiceInfo(cooked[2], cooked[3]); clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, clientId, servInfo); break; @@ -463,7 +466,7 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_REGISTERED: /* NNN regId serviceName regType */ if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw); - servInfo = new NsdServiceInfo(cooked[2], null, null); + servInfo = new NsdServiceInfo(cooked[2], null); clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, id, clientId, servInfo); break; @@ -679,9 +682,22 @@ public class NsdService extends INsdManager.Stub { private boolean registerService(int regId, NsdServiceInfo service) { if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); try { - //Add txtlen and txtdata - mNativeConnector.execute("mdnssd", "register", regId, service.getServiceName(), + Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(), service.getServiceType(), service.getPort()); + + // Add TXT records as additional arguments. + Map txtRecords = service.getAttributes(); + for (String key : txtRecords.keySet()) { + try { + // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data. + cmd.appendArg(String.format(Locale.US, "%s=%s", key, + new String(txtRecords.get(key), "UTF_8"))); + } catch (UnsupportedEncodingException e) { + Slog.e(TAG, "Failed to encode txtRecord " + e); + } + } + + mNativeConnector.execute(cmd); } catch(NativeDaemonConnectorException e) { Slog.e(TAG, "Failed to execute registerService " + e); return false; From b6e0448851034f130a9b1649ebdba542142ac393 Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Mon, 14 Apr 2014 16:31:27 -0700 Subject: [PATCH 0219/1150] Fix build Change-Id: I20168fb1c29ba6eb695f0d24c6ca512420b2b319 --- services/core/java/com/android/server/NsdService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 7b3b65bd58..fa803e2d3a 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -47,6 +47,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.server.NativeDaemonConnector.Command; /** * Network Service Discovery Service handles remote service discovery operation requests by From af9766d22698081d68d950d4cd7a3c0ec866dc9f Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 16 Apr 2014 10:28:37 -0700 Subject: [PATCH 0220/1150] frameworks: 64 bit compile issues ToDo: core/jni/com_android_internal_net_NetworkStatsFactory.cpp (merge issues) Change-Id: I5cf0bbb868e6c18e86c97c6491b6ee983a8ee1a2 --- core/jni/android_net_TrafficStats.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index f904b62e29..031637f41d 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -85,9 +86,9 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) { uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets; while (fgets(buffer, sizeof(buffer), fp) != NULL) { - int matched = sscanf(buffer, "%31s %llu %llu %llu %llu " - "%*u %llu %*u %*u %*u %*u " - "%*u %llu %*u %*u %*u %*u", cur_iface, &rxBytes, + int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64 + " %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u " + "%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes, &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets); if (matched >= 5) { if (matched == 7) { @@ -129,9 +130,11 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) { uint64_t tag, rxBytes, rxPackets, txBytes, txPackets; while (fgets(buffer, sizeof(buffer), fp) != NULL) { - if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &idx, - iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, &txBytes, - &txPackets) == 9) { + if (sscanf(buffer, + "%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64 + " %" SCNu64 " %" SCNu64 "", + &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, + &txBytes, &txPackets) == 9) { if (uid == cur_uid && tag == 0L) { stats->rxBytes += rxBytes; stats->rxPackets += rxPackets; From 0cc4425b3b9c4578145e094dc14d006a7c20eed0 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 21 Apr 2014 15:56:18 -0700 Subject: [PATCH 0221/1150] Start collecting mobile radio activity from the radio. Hook in to the new radio API to find out when the radio is active and use that to track its state in batter stats. We also still have the data being tracked from the kernel's emulation, and continue to use that if we don't get data from the radio. Currently this monitoring is turned off until some issues in the radio can be fixed that are providing bad data. Also add a new API to get estimated drain and charge times. Change-Id: Ifc4900fabb8f848f9cda361dce698664ea75f175 --- .../com/android/server/NativeDaemonConnector.java | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 62eb6632eb..0d1e122afc 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -20,6 +20,7 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Build; import android.os.Handler; +import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; @@ -59,6 +60,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private final PowerManager.WakeLock mWakeLock; + private final Looper mLooper; + private INativeDaemonConnectorCallbacks mCallbacks; private Handler mCallbackHandler; @@ -74,6 +77,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { + this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl, + FgThread.get().getLooper()); + } + + NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, + int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl, + Looper looper) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new ResponseQueue(responseQueueSize); @@ -81,6 +91,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (mWakeLock != null) { mWakeLock.setReferenceCounted(true); } + mLooper = looper; mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); @@ -88,7 +99,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo @Override public void run() { - mCallbackHandler = new Handler(FgThread.get().getLooper(), this); + mCallbackHandler = new Handler(mLooper, this); while (true) { try { From 7441122e2360aa17177f077f92d7088715f306f0 Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Fri, 25 Apr 2014 18:39:07 -0700 Subject: [PATCH 0222/1150] Fix incorrect "listener no longer active" errors Was incorrectly using .indexOfValue to search for Integer objects in the client map. Change-Id: I54e2e1725e0fff0a7d35a22376714cc8266a9eee --- .../java/com/android/server/NsdService.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index fa803e2d3a..fe97c71f5e 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -421,11 +421,8 @@ public class NsdService extends INsdManager.Stub { } /* This goes in response as msg.arg2 */ - int clientId = -1; - int keyId = clientInfo.mClientIds.indexOfValue(id); - if (keyId != -1) { - clientId = clientInfo.mClientIds.keyAt(keyId); - } else { + int clientId = clientInfo.getClientId(id); + if (clientId < 0) { // This can happen because of race conditions. For example, // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY, // and we may get in this situation. @@ -904,5 +901,18 @@ public class NsdService extends INsdManager.Stub { mClientRequests.clear(); } + // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, + // return the corresponding listener id. mDnsClient id is also called a global id. + private int getClientId(final int globalId) { + // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals) + // while also coercing the int primitives to Integer objects. + for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) { + int mDnsId = mClientIds.valueAt(i); + if (globalId == mDnsId) { + return mClientIds.keyAt(i); + } + } + return -1; + } } } From 1aa516467c398d43751130d4964fc626489e63b7 Mon Sep 17 00:00:00 2001 From: Justin Koh Date: Mon, 5 May 2014 15:12:31 -0700 Subject: [PATCH 0223/1150] Hide NsdServiceInfo additions for KKWT DO NOT MERGE Hide NsdServiceInfo additions for KKWT. Bug: 14116162 Change-Id: I98755a2524168be5e833a634192fd49ff3c32346 --- core/java/android/net/nsd/NsdServiceInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 6fdb0d0f84..8f52a7cc86 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -141,6 +141,7 @@ public final class NsdServiceInfo implements Parcelable { *

Keys should be short, ideally no more than 9 characters, and unique per instance of * {@link NsdServiceInfo}. Calling {@link #setAttribute} twice with the same key will overwrite * first value. + * @hide */ public void setAttribute(String key, String value) { try { @@ -150,7 +151,10 @@ public final class NsdServiceInfo implements Parcelable { } } - /** Remove an attribute by key */ + /** + * Remove an attribute by key + * @hide + */ public void removeAttribute(String key) { mTxtRecord.remove(key); } @@ -160,6 +164,7 @@ public final class NsdServiceInfo implements Parcelable { * *

The returned map is unmodifiable; changes must be made through {@link #setAttribute} and * {@link #removeAttribute}. + * @hide */ public Map getAttributes() { return Collections.unmodifiableMap(mTxtRecord); From 61c34fd2a2b047b21a9ea553db7a4af6891bca39 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 7 May 2014 23:49:08 -0700 Subject: [PATCH 0224/1150] Turn down the logging. Cut per-msg logging by 1/3 in NDC so we see that much more. Change-Id: I406297d98f2649a88b16c7be3cf90757d009c762 --- .../core/java/com/android/server/NativeDaemonConnector.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 0d1e122afc..96f9ab061c 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -50,6 +50,8 @@ import java.util.LinkedList; final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { private static final boolean LOGD = false; + private final static boolean VDBG = false; + private final String TAG; private String mSocket; @@ -409,7 +411,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonFailureException(logCmd, event); } - log("RMV <- {" + event + "}"); + if (VDBG) log("RMV <- {" + event + "}"); events.add(event); } while (event.isClassContinue()); From e36bfe74f3fa909930c71586386c2c0876022e32 Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 10 Mar 2014 17:10:51 +0900 Subject: [PATCH 0225/1150] Move IP config from WifiConfiguration to IpConfiguration. This is so that Ethernet can use it in the future. Bug: 7606609 Bug: 8687763 Change-Id: I5d1189682b13f1088848809604690648d8d9ecca --- .../android/server/net/DelayedDiskWrite.java | 92 +++++ .../com/android/server/net/IpConfigStore.java | 327 ++++++++++++++++++ 2 files changed, 419 insertions(+) create mode 100644 services/core/java/com/android/server/net/DelayedDiskWrite.java create mode 100644 services/core/java/com/android/server/net/IpConfigStore.java diff --git a/services/core/java/com/android/server/net/DelayedDiskWrite.java b/services/core/java/com/android/server/net/DelayedDiskWrite.java new file mode 100644 index 0000000000..6ed277de1e --- /dev/null +++ b/services/core/java/com/android/server/net/DelayedDiskWrite.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import android.os.Handler; +import android.os.HandlerThread; +import android.text.TextUtils; +import android.util.Log; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; + +public class DelayedDiskWrite { + private HandlerThread mDiskWriteHandlerThread; + private Handler mDiskWriteHandler; + /* Tracks multiple writes on the same thread */ + private int mWriteSequence = 0; + private final String TAG = "DelayedDiskWrite"; + + public interface Writer { + public void onWriteCalled(DataOutputStream out) throws IOException; + } + + public void write(final String filePath, final Writer w) { + if (TextUtils.isEmpty(filePath)) { + throw new IllegalArgumentException("empty file path"); + } + + /* Do a delayed write to disk on a separate handler thread */ + synchronized (this) { + if (++mWriteSequence == 1) { + mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread"); + mDiskWriteHandlerThread.start(); + mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper()); + } + } + + mDiskWriteHandler.post(new Runnable() { + @Override + public void run() { + doWrite(filePath, w); + } + }); + } + + private void doWrite(String filePath, Writer w) { + DataOutputStream out = null; + try { + out = new DataOutputStream(new BufferedOutputStream( + new FileOutputStream(filePath))); + w.onWriteCalled(out); + } catch (IOException e) { + loge("Error writing data file " + filePath); + } finally { + if (out != null) { + try { + out.close(); + } catch (Exception e) {} + } + + // Quit if no more writes sent + synchronized (this) { + if (--mWriteSequence == 0) { + mDiskWriteHandler.getLooper().quit(); + mDiskWriteHandler = null; + mDiskWriteHandlerThread = null; + } + } + } + } + + private void loge(String s) { + Log.e(TAG, s); + } +} + diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java new file mode 100644 index 0000000000..6ccbec0104 --- /dev/null +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkUtils; +import android.net.ProxyInfo; +import android.net.RouteInfo; +import android.os.Handler; +import android.os.HandlerThread; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import com.android.server.net.DelayedDiskWrite; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.EOFException; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.util.Map; + +public class IpConfigStore { + private static final String TAG = "IpConfigStore"; + private static final boolean DBG = true; + + protected final DelayedDiskWrite mWriter; + + /* IP and proxy configuration keys */ + protected static final String ID_KEY = "id"; + protected static final String IP_ASSIGNMENT_KEY = "ipAssignment"; + protected static final String LINK_ADDRESS_KEY = "linkAddress"; + protected static final String GATEWAY_KEY = "gateway"; + protected static final String DNS_KEY = "dns"; + protected static final String PROXY_SETTINGS_KEY = "proxySettings"; + protected static final String PROXY_HOST_KEY = "proxyHost"; + protected static final String PROXY_PORT_KEY = "proxyPort"; + protected static final String PROXY_PAC_FILE = "proxyPac"; + protected static final String EXCLUSION_LIST_KEY = "exclusionList"; + protected static final String EOS = "eos"; + + protected static final int IPCONFIG_FILE_VERSION = 2; + + public IpConfigStore() { + mWriter = new DelayedDiskWrite(); + } + + private boolean writeConfig(DataOutputStream out, int configKey, + IpConfiguration config) throws IOException { + boolean written = false; + + try { + LinkProperties linkProperties = config.linkProperties; + switch (config.ipAssignment) { + case STATIC: + out.writeUTF(IP_ASSIGNMENT_KEY); + out.writeUTF(config.ipAssignment.toString()); + for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { + out.writeUTF(LINK_ADDRESS_KEY); + out.writeUTF(linkAddr.getAddress().getHostAddress()); + out.writeInt(linkAddr.getNetworkPrefixLength()); + } + for (RouteInfo route : linkProperties.getRoutes()) { + out.writeUTF(GATEWAY_KEY); + LinkAddress dest = route.getDestination(); + if (dest != null) { + out.writeInt(1); + out.writeUTF(dest.getAddress().getHostAddress()); + out.writeInt(dest.getNetworkPrefixLength()); + } else { + out.writeInt(0); + } + if (route.getGateway() != null) { + out.writeInt(1); + out.writeUTF(route.getGateway().getHostAddress()); + } else { + out.writeInt(0); + } + } + for (InetAddress inetAddr : linkProperties.getDnses()) { + out.writeUTF(DNS_KEY); + out.writeUTF(inetAddr.getHostAddress()); + } + written = true; + break; + case DHCP: + out.writeUTF(IP_ASSIGNMENT_KEY); + out.writeUTF(config.ipAssignment.toString()); + written = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + loge("Ignore invalid ip assignment while writing"); + break; + } + + switch (config.proxySettings) { + case STATIC: + ProxyInfo proxyProperties = linkProperties.getHttpProxy(); + String exclusionList = proxyProperties.getExclusionListAsString(); + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.proxySettings.toString()); + out.writeUTF(PROXY_HOST_KEY); + out.writeUTF(proxyProperties.getHost()); + out.writeUTF(PROXY_PORT_KEY); + out.writeInt(proxyProperties.getPort()); + out.writeUTF(EXCLUSION_LIST_KEY); + out.writeUTF(exclusionList); + written = true; + break; + case PAC: + ProxyInfo proxyPacProperties = linkProperties.getHttpProxy(); + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.proxySettings.toString()); + out.writeUTF(PROXY_PAC_FILE); + out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); + written = true; + break; + case NONE: + out.writeUTF(PROXY_SETTINGS_KEY); + out.writeUTF(config.proxySettings.toString()); + written = true; + break; + case UNASSIGNED: + /* Ignore */ + break; + default: + loge("Ignore invalid proxy settings while writing"); + break; + } + + if (written) { + out.writeUTF(ID_KEY); + out.writeInt(configKey); + } + } catch (NullPointerException e) { + loge("Failure in writing " + config.linkProperties + e); + } + out.writeUTF(EOS); + + return written; + } + + public void writeIpAndProxyConfigurations(String filePath, + final SparseArray networks) { + mWriter.write(filePath, new DelayedDiskWrite.Writer() { + public void onWriteCalled(DataOutputStream out) throws IOException{ + out.writeInt(IPCONFIG_FILE_VERSION); + for(int i = 0; i < networks.size(); i++) { + writeConfig(out, networks.keyAt(i), networks.valueAt(i)); + } + } + }); + } + + public SparseArray readIpAndProxyConfigurations(String filePath) { + SparseArray networks = new SparseArray(); + + DataInputStream in = null; + try { + in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); + + int version = in.readInt(); + if (version != 2 && version != 1) { + loge("Bad version on IP configuration file, ignore read"); + return null; + } + + while (true) { + int id = -1; + // Default is DHCP with no proxy + IpAssignment ipAssignment = IpAssignment.DHCP; + ProxySettings proxySettings = ProxySettings.NONE; + LinkProperties linkProperties = new LinkProperties(); + String proxyHost = null; + String pacFileUrl = null; + int proxyPort = -1; + String exclusionList = null; + String key; + + do { + key = in.readUTF(); + try { + if (key.equals(ID_KEY)) { + id = in.readInt(); + } else if (key.equals(IP_ASSIGNMENT_KEY)) { + ipAssignment = IpAssignment.valueOf(in.readUTF()); + } else if (key.equals(LINK_ADDRESS_KEY)) { + LinkAddress linkAddr = new LinkAddress( + NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); + linkProperties.addLinkAddress(linkAddr); + } else if (key.equals(GATEWAY_KEY)) { + LinkAddress dest = null; + InetAddress gateway = null; + if (version == 1) { + // only supported default gateways - leave the dest/prefix empty + gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + } else { + if (in.readInt() == 1) { + dest = new LinkAddress( + NetworkUtils.numericToInetAddress(in.readUTF()), + in.readInt()); + } + if (in.readInt() == 1) { + gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + } + } + linkProperties.addRoute(new RouteInfo(dest, gateway)); + } else if (key.equals(DNS_KEY)) { + linkProperties.addDns( + NetworkUtils.numericToInetAddress(in.readUTF())); + } else if (key.equals(PROXY_SETTINGS_KEY)) { + proxySettings = ProxySettings.valueOf(in.readUTF()); + } else if (key.equals(PROXY_HOST_KEY)) { + proxyHost = in.readUTF(); + } else if (key.equals(PROXY_PORT_KEY)) { + proxyPort = in.readInt(); + } else if (key.equals(PROXY_PAC_FILE)) { + pacFileUrl = in.readUTF(); + } else if (key.equals(EXCLUSION_LIST_KEY)) { + exclusionList = in.readUTF(); + } else if (key.equals(EOS)) { + break; + } else { + loge("Ignore unknown key " + key + "while reading"); + } + } catch (IllegalArgumentException e) { + loge("Ignore invalid address while reading" + e); + } + } while (true); + + if (id != -1) { + IpConfiguration config = new IpConfiguration(); + networks.put(id, config); + + config.linkProperties = linkProperties; + switch (ipAssignment) { + case STATIC: + case DHCP: + config.ipAssignment = ipAssignment; + break; + case UNASSIGNED: + loge("BUG: Found UNASSIGNED IP on file, use DHCP"); + config.ipAssignment = IpAssignment.DHCP; + break; + default: + loge("Ignore invalid ip assignment while reading."); + config.ipAssignment = IpAssignment.UNASSIGNED; + break; + } + + switch (proxySettings) { + case STATIC: + config.proxySettings = proxySettings; + ProxyInfo ProxyInfo = + new ProxyInfo(proxyHost, proxyPort, exclusionList); + linkProperties.setHttpProxy(ProxyInfo); + break; + case PAC: + config.proxySettings = proxySettings; + ProxyInfo proxyPacProperties = + new ProxyInfo(pacFileUrl); + linkProperties.setHttpProxy(proxyPacProperties); + break; + case NONE: + config.proxySettings = proxySettings; + break; + case UNASSIGNED: + loge("BUG: Found UNASSIGNED proxy on file, use NONE"); + config.proxySettings = ProxySettings.NONE; + break; + default: + loge("Ignore invalid proxy settings while reading"); + config.proxySettings = ProxySettings.UNASSIGNED; + break; + } + } else { + if (DBG) log("Missing id while parsing configuration"); + } + } + } catch (EOFException ignore) { + } catch (IOException e) { + loge("Error parsing configuration" + e); + } finally { + if (in != null) { + try { + in.close(); + } catch (Exception e) {} + } + } + + return networks; + } + + protected void loge(String s) { + Log.e(TAG, s); + } + + protected void log(String s) { + Log.d(TAG, s); + } +} From eeae94e9cd5826d87d813b941e58399ec0a4a7b4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 21 May 2014 16:30:22 -0700 Subject: [PATCH 0226/1150] Fix a typo in IpConfigStore. Change-Id: I1fc845bf4547ae9a86db02ed29b6d5ba60a01277 --- services/core/java/com/android/server/net/IpConfigStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 6ccbec0104..aee7679225 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -305,7 +305,7 @@ public class IpConfigStore { } } catch (EOFException ignore) { } catch (IOException e) { - loge("Error parsing configuration" + e); + loge("Error parsing configuration: " + e); } finally { if (in != null) { try { From 2edad7a1605167ba3b23f48a290b6a8615f291a6 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 21 May 2014 16:23:43 -0700 Subject: [PATCH 0227/1150] Add an EthernetManager. The implementation will live in frameworks/opt/net/ethernet. Bug: 7606609 Bug: 8687763 Bug: 14993642 Bug: 14981801 Change-Id: Ic771e268b0c78f0fc32f46af6fe0dd7c634a426e --- core/java/android/net/EthernetManager.java | 73 +++++++++++++++++++++ core/java/android/net/IEthernetManager.aidl | 30 +++++++++ 2 files changed, 103 insertions(+) create mode 100644 core/java/android/net/EthernetManager.java create mode 100644 core/java/android/net/IEthernetManager.aidl diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java new file mode 100644 index 0000000000..70cc708b94 --- /dev/null +++ b/core/java/android/net/EthernetManager.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.content.Context; +import android.net.IEthernetManager; +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkProperties; +import android.os.RemoteException; + +/** + * A class representing the IP configuration of the Ethernet network. + * + * @hide + */ +public class EthernetManager { + private static final String TAG = "EthernetManager"; + + private final Context mContext; + private final IEthernetManager mService; + + /** + * Create a new EthernetManager instance. + * Applications will almost always want to use + * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve + * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. + */ + public EthernetManager(Context context, IEthernetManager service) { + mContext = context; + mService = service; + } + + /** + * Get Ethernet configuration + * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + */ + public IpConfiguration getConfiguration() { + try { + return mService.getConfiguration(); + } catch (RemoteException e) { + return new IpConfiguration(IpAssignment.UNASSIGNED, + ProxySettings.UNASSIGNED, + new LinkProperties()); + } + } + + /** + * Set Ethernet configuration + * @return true if setting success + */ + public void setConfiguration(IpConfiguration config) { + try { + mService.setConfiguration(config); + } catch (RemoteException e) { + } + } +} diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl new file mode 100644 index 0000000000..3fa08f81a8 --- /dev/null +++ b/core/java/android/net/IEthernetManager.aidl @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.IpConfiguration; + +/** + * Interface that answers queries about, and allows changing + * ethernet configuration. + */ +/** {@hide} */ +interface IEthernetManager +{ + IpConfiguration getConfiguration(); + void setConfiguration(in IpConfiguration config); +} From 56e4e58eaeb3b5be3dcd0f4c4d6e4035fd910a07 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 22 May 2014 11:51:27 -0700 Subject: [PATCH 0228/1150] Fix Ethernet documentation. 1. Remove incorrect @return tag for void function. 2. Fix build breakage by removing the reference to #ETHERNET_SERVICE, which is hidden. Change-Id: Ia893464bafc8257e48e0bd710d27954b535fcece --- core/java/android/net/EthernetManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 70cc708b94..5df4bafc46 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -47,7 +47,7 @@ public class EthernetManager { } /** - * Get Ethernet configuration + * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { @@ -61,8 +61,7 @@ public class EthernetManager { } /** - * Set Ethernet configuration - * @return true if setting success + * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { try { From 7308875a27487b07466794614abde964d7714c31 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 22 May 2014 11:51:27 -0700 Subject: [PATCH 0229/1150] Fix Ethernet documentation. 1. Remove incorrect @return tag for void function. 2. Fix build breakage by removing the reference to #ETHERNET_SERVICE, which is hidden. Change-Id: Ia893464bafc8257e48e0bd710d27954b535fcece (cherry picked from commit ff7e406df8a46256e47fff70abc9116ad3f94c23) --- core/java/android/net/EthernetManager.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 70cc708b94..5df4bafc46 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -47,7 +47,7 @@ public class EthernetManager { } /** - * Get Ethernet configuration + * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { @@ -61,8 +61,7 @@ public class EthernetManager { } /** - * Set Ethernet configuration - * @return true if setting success + * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { try { From 690790088db18979e3877cfcd6c0ff0092249910 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Jun 2014 10:30:11 -0700 Subject: [PATCH 0230/1150] Fix public API of LinkProperties. bug:15142362 Change-Id: I1457111da7d3bd09998f7e010febb8bb4c45c8bc --- services/core/java/com/android/server/net/IpConfigStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index aee7679225..bb0d5fe608 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -100,7 +100,7 @@ public class IpConfigStore { out.writeInt(0); } } - for (InetAddress inetAddr : linkProperties.getDnses()) { + for (InetAddress inetAddr : linkProperties.getDnsServers()) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } @@ -232,7 +232,7 @@ public class IpConfigStore { } linkProperties.addRoute(new RouteInfo(dest, gateway)); } else if (key.equals(DNS_KEY)) { - linkProperties.addDns( + linkProperties.addDnsServer( NetworkUtils.numericToInetAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); From c447220e53c5ef80382ee199a500e7d17d463f34 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 3 Jun 2014 18:41:43 -0700 Subject: [PATCH 0231/1150] Add a new IpPrefix class and use it in RouteInfo. This change uses IpPrefix only in the public API and continues to use LinkAddress for everything else. It does not change the callers to use the new APIs, with the exception of changing all current uses of getDestination to getDestinationLinkAddress to make room for the new getDestination method that returns an IpPrefix. Based on Sreeram's earlier change: https://googleplex-android-review.git.corp.google.com/#/c/477874/ but a bit simplified and with a bit more documentation. Bug: 15142362 Bug: 13885501 Change-Id: Ib4cd96b22cbff4ea31bb26a7853989f50da8de4e --- services/core/java/com/android/server/net/IpConfigStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index bb0d5fe608..35bc6ec4cd 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -85,7 +85,7 @@ public class IpConfigStore { } for (RouteInfo route : linkProperties.getRoutes()) { out.writeUTF(GATEWAY_KEY); - LinkAddress dest = route.getDestination(); + LinkAddress dest = route.getDestinationLinkAddress(); if (dest != null) { out.writeInt(1); out.writeUTF(dest.getAddress().getHostAddress()); From 8e33e456a111948bf49c91eff88db6975959eb9d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 9 Jun 2014 22:58:46 +0900 Subject: [PATCH 0232/1150] Minor changes to the LinkAddress API docs. 1. Rename getNetworkPrefixLength to getPrefixLength. Update all callers in frameworks/base and add a shim method and a TODO for the rest. 2. @hide isSameAddressAs. It doesn't add much, and it's just one-liner that callers can implement if they want. 3. Fix the alignment of the initial paragraph (

    should have been
). 4. Remove the documentation that talks about creating LinkAddresses, since there's no public API for creating them. With these changes I think LinkAddress is fine as a public API. Bug: 15142362 Change-Id: Iaf3b1db577745bb68a9e1dd7f96d666dd3f3ec7c --- services/core/java/com/android/server/net/IpConfigStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 35bc6ec4cd..907eeb2418 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -81,7 +81,7 @@ public class IpConfigStore { for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(linkAddr.getAddress().getHostAddress()); - out.writeInt(linkAddr.getNetworkPrefixLength()); + out.writeInt(linkAddr.getPrefixLength()); } for (RouteInfo route : linkProperties.getRoutes()) { out.writeUTF(GATEWAY_KEY); @@ -89,7 +89,7 @@ public class IpConfigStore { if (dest != null) { out.writeInt(1); out.writeUTF(dest.getAddress().getHostAddress()); - out.writeInt(dest.getNetworkPrefixLength()); + out.writeInt(dest.getPrefixLength()); } else { out.writeInt(0); } From 81c858241ed03b64250214298f0c8b6b7725767e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 9 Jun 2014 22:58:46 +0900 Subject: [PATCH 0233/1150] Minor changes to the LinkAddress API docs. 1. Rename getNetworkPrefixLength to getPrefixLength. Update all callers in frameworks/base and add a shim method and a TODO for the rest. 2. @hide isSameAddressAs. It doesn't add much, and it's just one-liner that callers can implement if they want. 3. Fix the alignment of the initial paragraph (
    should have been
). 4. Remove the documentation that talks about creating LinkAddresses, since there's no public API for creating them. With these changes I think LinkAddress is fine as a public API. Bug: 15142362 Change-Id: Iaf3b1db577745bb68a9e1dd7f96d666dd3f3ec7c (cherry picked from commit 9ab53650cfcd91a2a151b44b3fd1381841f76269) --- services/core/java/com/android/server/net/IpConfigStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index aee7679225..dc4dc2eaaa 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -81,7 +81,7 @@ public class IpConfigStore { for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(linkAddr.getAddress().getHostAddress()); - out.writeInt(linkAddr.getNetworkPrefixLength()); + out.writeInt(linkAddr.getPrefixLength()); } for (RouteInfo route : linkProperties.getRoutes()) { out.writeUTF(GATEWAY_KEY); @@ -89,7 +89,7 @@ public class IpConfigStore { if (dest != null) { out.writeInt(1); out.writeUTF(dest.getAddress().getHostAddress()); - out.writeInt(dest.getNetworkPrefixLength()); + out.writeInt(dest.getPrefixLength()); } else { out.writeInt(0); } From c879e20e423a0611a4effcfce1b90251710e1b4c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Jun 2014 10:30:11 -0700 Subject: [PATCH 0234/1150] Fix public API of LinkProperties. bug:15142362 (cherry picked from commit 51d898fd0223a4b7c728980ab987dd985c02df5f) Change-Id: I1457111da7d3bd09998f7e010febb8bb4c45c8bc --- services/core/java/com/android/server/net/IpConfigStore.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index aee7679225..bb0d5fe608 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -100,7 +100,7 @@ public class IpConfigStore { out.writeInt(0); } } - for (InetAddress inetAddr : linkProperties.getDnses()) { + for (InetAddress inetAddr : linkProperties.getDnsServers()) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } @@ -232,7 +232,7 @@ public class IpConfigStore { } linkProperties.addRoute(new RouteInfo(dest, gateway)); } else if (key.equals(DNS_KEY)) { - linkProperties.addDns( + linkProperties.addDnsServer( NetworkUtils.numericToInetAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); From 3097cf618621f0b31d4215aa4b5d375f0835972f Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 3 Jun 2014 18:41:43 -0700 Subject: [PATCH 0235/1150] Add a new IpPrefix class and use it in RouteInfo. This change uses IpPrefix only in the public API and continues to use LinkAddress for everything else. It does not change the callers to use the new APIs, with the exception of changing all current uses of getDestination to getDestinationLinkAddress to make room for the new getDestination method that returns an IpPrefix. Based on Sreeram's earlier change: https://googleplex-android-review.git.corp.google.com/#/c/477874/ but a bit simplified and with a bit more documentation. Bug: 15142362 Bug: 13885501 Change-Id: Ib4cd96b22cbff4ea31bb26a7853989f50da8de4e (cherry picked from commit 7d3b4b9a3d4de9673119632da0ebd583e50126f7) --- services/core/java/com/android/server/net/IpConfigStore.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index bb0d5fe608..35bc6ec4cd 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -85,7 +85,7 @@ public class IpConfigStore { } for (RouteInfo route : linkProperties.getRoutes()) { out.writeUTF(GATEWAY_KEY); - LinkAddress dest = route.getDestination(); + LinkAddress dest = route.getDestinationLinkAddress(); if (dest != null) { out.writeInt(1); out.writeUTF(dest.getAddress().getHostAddress()); From aecbb5c7104e214ae801c1552504ec6d145fd330 Mon Sep 17 00:00:00 2001 From: Andres Morales Date: Fri, 7 Feb 2014 16:57:00 -0800 Subject: [PATCH 0236/1150] interface for nfc handover supplicant commands expose: NFC_GET_HANDOVER_SEL NFC_GET_HANDOVER_REQ NFC_REPORT_HANDOVER These are used in for setting up WFD with NFC and are only accessible given the CONNECTIVITY_INTERNAL permission. Change-Id: Ia43afc137d474822cad896d335530654081a808c --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index 1c9c40d193..ee2e895af5 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -26,6 +26,7 @@ import android.os.Messenger; interface IWifiP2pManager { Messenger getMessenger(); + Messenger getP2pStateMachineMessenger(); void setMiracastMode(int mode); } From 0a998b84bc14ed17af50a80f45b23c99e349d58b Mon Sep 17 00:00:00 2001 From: Joe LaPenna Date: Fri, 4 Jul 2014 17:15:54 -0700 Subject: [PATCH 0237/1150] CW on Master: Disable CaptivePortalTracker, EthernetService BUG: 15143878 Change-Id: I6c534a28c1fcd475982ae70e7f3af69f3a219e24 --- core/java/android/net/EthernetManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 5df4bafc46..608ca28d84 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -51,6 +51,11 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { + if (mService == null) { + return new IpConfiguration(IpAssignment.UNASSIGNED, + ProxySettings.UNASSIGNED, + new LinkProperties()); + } try { return mService.getConfiguration(); } catch (RemoteException e) { @@ -64,6 +69,9 @@ public class EthernetManager { * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { + if (mService == null) { + return; + } try { mService.setConfiguration(config); } catch (RemoteException e) { From b0bdb33876aba6edc0fbf7b65293baa356a47c82 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Wed, 7 May 2014 15:27:40 -0400 Subject: [PATCH 0238/1150] Convert Vpn from NetworkStateTracker to NetworkAgent. This eliminates the need for the ConnectivityService.VpnCallback class. This requires shifting VPNs to the new "network" netd API. VpnService.protect() is modified to no longer go through ConnectivityService. NetworkCapabilities is extended to add a transport type for VPNs and a capability requiring a non-VPN (so the default NetworkRequest isn't satisfied by a VPN). bug:15409918 Change-Id: Ic4498f1961582208add6f375ad16ce376ee9eb95 --- core/java/android/net/UidRange.aidl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl new file mode 100644 index 0000000000..f9be628c16 --- /dev/null +++ b/core/java/android/net/UidRange.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +parcelable UidRange; From fba15596cb41876b333935efbf0792e2b28e985b Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Sat, 19 Jul 2014 23:21:46 -0700 Subject: [PATCH 0239/1150] Cleanup: Delete dead code. Bug: 15413389 Change-Id: I315468832ef18ffc84174e54774ab63b86d284dc --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index fe97c71f5e..cf7e65c0e3 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -603,7 +603,7 @@ public class NsdService extends INsdManager.Stub { return mUniqueId; } - /* These should be in sync with system/netd/mDnsResponseCode.h */ + /* These should be in sync with system/netd/server/ResponseCode.h */ class NativeResponseCode { public static final int SERVICE_DISCOVERY_FAILED = 602; public static final int SERVICE_FOUND = 603; From 5a1878d6cacd63ab2ec37003a91cc10fbeaf3e20 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Wed, 6 Aug 2014 14:19:56 -0700 Subject: [PATCH 0240/1150] Make TrafficStats uid attribution @SystemApi Anything that runs as a singleton may need to attribute traffic to various client apps; in particular, backup transports need to do this. Apropos of which, introduce a @SystemApi method specifically for that purpose, setThreadStatsTagBackup(). Bug 16661321 Change-Id: Id5d22e28bdc68edb53f2a1fdba80b144fcbc61d2 --- core/java/android/net/TrafficStats.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 786439e5d8..3f1851901f 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.content.Context; @@ -126,6 +127,16 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); } + /** + * System API for backup-related support components to tag network traffic + * appropriately. + * @hide + */ + @SystemApi + public static void setThreadStatsTagBackup() { + setThreadStatsTag(TAG_SYSTEM_BACKUP); + } + /** * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -160,11 +171,13 @@ public class TrafficStats { * * @hide */ + @SystemApi public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } /** {@hide} */ + @SystemApi public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } From 3b43a279e3b44684711ddae64e450979a8185785 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 11 Aug 2014 15:22:51 -0700 Subject: [PATCH 0241/1150] Hack and ship: NetworkStats edition. Some devices use clatd for catching raw IPv4 traffic when running on a pure-IPv6 carrier network. In those situations, the per-UID stats are accounted against the clat iface, so framework users need to combine both the "base" and "stacked" iface usage together. This also means that policy rules (like restricting background data or battery saver) need to apply to the stacked ifaces. Finally, we need to massage stats data slightly: -- Currently xt_qtaguid double-counts the clatd traffic *leaving* the device; both against the original UID on the clat iface, and against UID 0 on the final egress interface. -- All clatd traffic *arriving* at the device is missing the extra IPv6 packet header overhead when accounted against the final UID. Bug: 12249687, 15459248, 16296564 Change-Id: I0ee59d96831f52782de7a980e4cce9b061902fff --- .../internal/net/NetworkStatsFactory.java | 70 +++++++++++++++- .../server/net/NetworkStatsService.java | 83 +++++++++++++------ 2 files changed, 123 insertions(+), 30 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index e2a2b1eb2a..506114bd01 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -25,17 +25,20 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; +import android.util.ArrayMap; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; +import libcore.io.IoUtils; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.ProtocolException; - -import libcore.io.IoUtils; +import java.util.Objects; /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} @@ -54,6 +57,19 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; + @GuardedBy("sStackedIfaces") + private static final ArrayMap sStackedIfaces = new ArrayMap<>(); + + public static void noteStackedIface(String stackedIface, String baseIface) { + synchronized (sStackedIfaces) { + if (baseIface != null) { + sStackedIfaces.put(stackedIface, baseIface); + } else { + sStackedIfaces.remove(stackedIface); + } + } + } + public NetworkStatsFactory() { this(new File("/proc/")); } @@ -171,8 +187,54 @@ public class NetworkStatsFactory { } public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, - NetworkStats lastStats) - throws IOException { + NetworkStats lastStats) throws IOException { + final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, + lastStats); + + synchronized (sStackedIfaces) { + // Sigh, xt_qtaguid ends up double-counting tx traffic going through + // clatd interfaces, so we need to subtract it here. + final int size = sStackedIfaces.size(); + for (int i = 0; i < size; i++) { + final String stackedIface = sStackedIfaces.keyAt(i); + final String baseIface = sStackedIfaces.valueAt(i); + + // Count up the tx traffic and subtract from root UID on the + // base interface. + NetworkStats.Entry adjust = new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, + 0L, 0L); + NetworkStats.Entry entry = null; + for (int j = 0; j < stats.size(); j++) { + entry = stats.getValues(j, entry); + if (Objects.equals(entry.iface, stackedIface)) { + adjust.txBytes -= entry.txBytes; + adjust.txPackets -= entry.txPackets; + } + } + stats.combineValues(adjust); + } + } + + // Double sigh, all rx traffic on clat needs to be tweaked to + // account for the dropped IPv6 header size post-unwrap. + NetworkStats.Entry entry = null; + for (int i = 0; i < stats.size(); i++) { + entry = stats.getValues(i, entry); + if (entry.iface != null && entry.iface.startsWith("clat")) { + // Delta between IPv4 header (20b) and IPv6 header (40b) + entry.rxBytes = entry.rxPackets * 20; + entry.rxPackets = 0; + entry.txBytes = 0; + entry.txPackets = 0; + stats.combineValues(entry); + } + } + + return stats; + } + + private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, + int limitTag, NetworkStats lastStats) throws IOException { if (USE_NATIVE_PARSING) { final NetworkStats stats; if (lastStats != null) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 271e9e9b22..e35ca468cd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -62,8 +62,6 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.util.ArrayUtils.appendElement; -import static com.android.internal.util.ArrayUtils.contains; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -107,6 +105,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.MathUtils; @@ -121,14 +121,12 @@ import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; import com.android.server.connectivity.Tethering; -import com.google.android.collect.Maps; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -215,7 +213,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); /** Set of currently active ifaces. */ - private HashMap mActiveIfaces = Maps.newHashMap(); + private final ArrayMap mActiveIfaces = new ArrayMap<>(); + /** Set of currently active ifaces for UID stats. */ + private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -883,30 +883,52 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // rebuild active interfaces based on connected networks + // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); + mActiveUidIfaces.clear(); + final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { - // collect networks under their parent interfaces - final String iface = state.linkProperties.getInterfaceName(); + final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); + final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); - NetworkIdentitySet ident = mActiveIfaces.get(iface); - if (ident == null) { - ident = new NetworkIdentitySet(); - mActiveIfaces.put(iface, ident); + // Traffic occurring on the base interface is always counted for + // both total usage and UID details. + final String baseIface = state.linkProperties.getInterfaceName(); + findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); + if (isMobile) { + mobileIfaces.add(baseIface); } - ident.add(NetworkIdentity.buildNetworkIdentity(mContext, state)); - - // remember any ifaces associated with mobile networks - if (isNetworkTypeMobile(state.networkInfo.getType()) && iface != null) { - if (!contains(mMobileIfaces, iface)) { - mMobileIfaces = appendElement(String.class, mMobileIfaces, iface); + // Traffic occurring on stacked interfaces is usually clatd, + // which is already accounted against its final egress interface + // by the kernel. Thus, we only need to collect stacked + // interface stats at the UID level. + final List stackedLinks = state.linkProperties.getStackedLinks(); + for (LinkProperties stackedLink : stackedLinks) { + final String stackedIface = stackedLink.getInterfaceName(); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + if (isMobile) { + mobileIfaces.add(stackedIface); } } } } + + mobileIfaces.remove(null); + mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); + } + + private static NetworkIdentitySet findOrCreateNetworkIdentitySet( + ArrayMap map, K key) { + NetworkIdentitySet ident = map.get(key); + if (ident == null) { + ident = new NetworkIdentitySet(); + map.put(key, ident); + } + return ident; } /** @@ -926,8 +948,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); @@ -980,8 +1002,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveIfaces, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); @@ -1136,10 +1158,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { pw.println("Active interfaces:"); pw.increaseIndent(); - for (String iface : mActiveIfaces.keySet()) { - final NetworkIdentitySet ident = mActiveIfaces.get(iface); - pw.print("iface="); pw.print(iface); - pw.print(" ident="); pw.println(ident.toString()); + for (int i = 0; i < mActiveIfaces.size(); i++) { + pw.printPair("iface", mActiveIfaces.keyAt(i)); + pw.printPair("ident", mActiveIfaces.valueAt(i)); + pw.println(); + } + pw.decreaseIndent(); + + pw.println("Active UID interfaces:"); + pw.increaseIndent(); + for (int i = 0; i < mActiveUidIfaces.size(); i++) { + pw.printPair("iface", mActiveUidIfaces.keyAt(i)); + pw.printPair("ident", mActiveUidIfaces.valueAt(i)); + pw.println(); } pw.decreaseIndent(); From 5d6a2cd7ca8bef5f7e56264b28e298fd253effea Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 14 Aug 2014 12:55:00 -0700 Subject: [PATCH 0242/1150] Some networks may have null ifaces, I guess? Seems like a bug further upstream, but guard ourselves against it for now. Bug: 17033841 Change-Id: Id0e5895c3389b63d4e34b1fb064efef8b72cd609 --- .../server/net/NetworkStatsService.java | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e35ca468cd..f995deeb8d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -896,10 +896,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Traffic occurring on the base interface is always counted for // both total usage and UID details. final String baseIface = state.linkProperties.getInterfaceName(); - findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); - if (isMobile) { - mobileIfaces.add(baseIface); + if (baseIface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); + if (isMobile) { + mobileIfaces.add(baseIface); + } } // Traffic occurring on stacked interfaces is usually clatd, @@ -909,15 +911,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); - if (isMobile) { - mobileIfaces.add(stackedIface); + if (stackedIface != null) { + findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + if (isMobile) { + mobileIfaces.add(stackedIface); + } } } } } - mobileIfaces.remove(null); mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } From eff82e809982c15e5de1d839e9d6dc0fee5535ba Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 31 Jul 2014 00:48:01 +0900 Subject: [PATCH 0243/1150] Stop using LinkProperties for static configuration. LinkProperties can represent way more complicated configurations than what we can actually apply to interfaces. This makes it error-prone to use it to represent static configuration, both when trying to apply configuration coming from LinkProperties and when trying to save configuration from current LinkProperties. Instead, move static configuration (IPv4 only, since we don't support static IPv6 configuration) into a separate StaticIpConfiguration class. Bug: 16114392 Bug: 16893413 Change-Id: Ib33f35c004e30b6067bb20235ffa43c247d174df --- core/java/android/net/EthernetManager.java | 9 +- .../com/android/server/net/IpConfigStore.java | 90 ++++++++++--------- 2 files changed, 52 insertions(+), 47 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 608ca28d84..d965f27c8f 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -21,7 +21,6 @@ import android.net.IEthernetManager; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; -import android.net.LinkProperties; import android.os.RemoteException; /** @@ -52,16 +51,12 @@ public class EthernetManager { */ public IpConfiguration getConfiguration() { if (mService == null) { - return new IpConfiguration(IpAssignment.UNASSIGNED, - ProxySettings.UNASSIGNED, - new LinkProperties()); + return new IpConfiguration(); } try { return mService.getConfiguration(); } catch (RemoteException e) { - return new IpConfiguration(IpAssignment.UNASSIGNED, - ProxySettings.UNASSIGNED, - new LinkProperties()); + return new IpConfiguration(); } } diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 907eeb2418..857b9e90a0 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -20,10 +20,10 @@ import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; -import android.net.LinkProperties; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; +import android.net.StaticIpConfiguration; import android.os.Handler; import android.os.HandlerThread; import android.text.TextUtils; @@ -41,6 +41,7 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; +import java.net.Inet4Address; import java.util.Map; public class IpConfigStore { @@ -69,40 +70,32 @@ public class IpConfigStore { } private boolean writeConfig(DataOutputStream out, int configKey, - IpConfiguration config) throws IOException { + IpConfiguration config) throws IOException { boolean written = false; try { - LinkProperties linkProperties = config.linkProperties; switch (config.ipAssignment) { case STATIC: out.writeUTF(IP_ASSIGNMENT_KEY); out.writeUTF(config.ipAssignment.toString()); - for (LinkAddress linkAddr : linkProperties.getLinkAddresses()) { - out.writeUTF(LINK_ADDRESS_KEY); - out.writeUTF(linkAddr.getAddress().getHostAddress()); - out.writeInt(linkAddr.getPrefixLength()); - } - for (RouteInfo route : linkProperties.getRoutes()) { - out.writeUTF(GATEWAY_KEY); - LinkAddress dest = route.getDestinationLinkAddress(); - if (dest != null) { - out.writeInt(1); - out.writeUTF(dest.getAddress().getHostAddress()); - out.writeInt(dest.getPrefixLength()); - } else { - out.writeInt(0); + StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; + if (staticIpConfiguration != null) { + if (staticIpConfiguration.ipAddress != null) { + LinkAddress ipAddress = staticIpConfiguration.ipAddress; + out.writeUTF(LINK_ADDRESS_KEY); + out.writeUTF(ipAddress.getAddress().getHostAddress()); + out.writeInt(ipAddress.getPrefixLength()); } - if (route.getGateway() != null) { - out.writeInt(1); - out.writeUTF(route.getGateway().getHostAddress()); - } else { - out.writeInt(0); + if (staticIpConfiguration.gateway != null) { + out.writeUTF(GATEWAY_KEY); + out.writeInt(0); // Default route. + out.writeInt(1); // Have a gateway. + out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); + } + for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { + out.writeUTF(DNS_KEY); + out.writeUTF(inetAddr.getHostAddress()); } - } - for (InetAddress inetAddr : linkProperties.getDnsServers()) { - out.writeUTF(DNS_KEY); - out.writeUTF(inetAddr.getHostAddress()); } written = true; break; @@ -121,7 +114,7 @@ public class IpConfigStore { switch (config.proxySettings) { case STATIC: - ProxyInfo proxyProperties = linkProperties.getHttpProxy(); + ProxyInfo proxyProperties = config.httpProxy; String exclusionList = proxyProperties.getExclusionListAsString(); out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); @@ -134,7 +127,7 @@ public class IpConfigStore { written = true; break; case PAC: - ProxyInfo proxyPacProperties = linkProperties.getHttpProxy(); + ProxyInfo proxyPacProperties = config.httpProxy; out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_PAC_FILE); @@ -159,7 +152,7 @@ public class IpConfigStore { out.writeInt(configKey); } } catch (NullPointerException e) { - loge("Failure in writing " + config.linkProperties + e); + loge("Failure in writing " + config + e); } out.writeUTF(EOS); @@ -196,7 +189,7 @@ public class IpConfigStore { // Default is DHCP with no proxy IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; - LinkProperties linkProperties = new LinkProperties(); + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); String proxyHost = null; String pacFileUrl = null; int proxyPort = -1; @@ -213,13 +206,23 @@ public class IpConfigStore { } else if (key.equals(LINK_ADDRESS_KEY)) { LinkAddress linkAddr = new LinkAddress( NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); - linkProperties.addLinkAddress(linkAddr); + if (linkAddr.getAddress() instanceof Inet4Address && + staticIpConfiguration.ipAddress == null) { + staticIpConfiguration.ipAddress = linkAddr; + } else { + loge("Non-IPv4 or duplicate address: " + linkAddr); + } } else if (key.equals(GATEWAY_KEY)) { LinkAddress dest = null; InetAddress gateway = null; if (version == 1) { // only supported default gateways - leave the dest/prefix empty gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + if (staticIpConfiguration.gateway == null) { + staticIpConfiguration.gateway = gateway; + } else { + loge("Duplicate gateway: " + gateway.getHostAddress()); + } } else { if (in.readInt() == 1) { dest = new LinkAddress( @@ -229,10 +232,16 @@ public class IpConfigStore { if (in.readInt() == 1) { gateway = NetworkUtils.numericToInetAddress(in.readUTF()); } + RouteInfo route = new RouteInfo(dest, gateway); + if (route.isIPv4Default() && + staticIpConfiguration.gateway == null) { + staticIpConfiguration.gateway = gateway; + } else { + loge("Non-IPv4 default or duplicate route: " + route); + } } - linkProperties.addRoute(new RouteInfo(dest, gateway)); } else if (key.equals(DNS_KEY)) { - linkProperties.addDnsServer( + staticIpConfiguration.dnsServers.add( NetworkUtils.numericToInetAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); @@ -258,9 +267,11 @@ public class IpConfigStore { IpConfiguration config = new IpConfiguration(); networks.put(id, config); - config.linkProperties = linkProperties; switch (ipAssignment) { case STATIC: + config.staticIpConfiguration = staticIpConfiguration; + config.ipAssignment = ipAssignment; + break; case DHCP: config.ipAssignment = ipAssignment; break; @@ -276,16 +287,15 @@ public class IpConfigStore { switch (proxySettings) { case STATIC: - config.proxySettings = proxySettings; - ProxyInfo ProxyInfo = + ProxyInfo proxyInfo = new ProxyInfo(proxyHost, proxyPort, exclusionList); - linkProperties.setHttpProxy(ProxyInfo); + config.proxySettings = proxySettings; + config.httpProxy = proxyInfo; break; case PAC: + ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl); config.proxySettings = proxySettings; - ProxyInfo proxyPacProperties = - new ProxyInfo(pacFileUrl); - linkProperties.setHttpProxy(proxyPacProperties); + config.httpProxy = proxyPacProperties; break; case NONE: config.proxySettings = proxySettings; From 04d79e775604c23b4b0136eebcab7fac21a81f93 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 3 Sep 2014 19:59:08 -0700 Subject: [PATCH 0244/1150] Fix use of %llx for sscanf 64 bit values. Change-Id: Ie7a0e243dfcf24722783fe7d697a1412de7efe68 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 0b9ad9b39e..a42b4df2d4 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "NetworkStats" #include +#include #include #include @@ -79,7 +80,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, while (fgets(buffer, sizeof(buffer), fp) != NULL) { stats_line s; int64_t rawTag; - if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx, + if (sscanf(buffer, "%d %31s 0x%llx %u %u %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &s.idx, s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 9) { if (s.idx != lastIdx + 1) { From a53dd7f9ef51ffb1cbd955b89496dd350855dd32 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 3 Sep 2014 15:45:59 -0700 Subject: [PATCH 0245/1150] Unescape strings properly in NsdService. NativeDaemonEvent.unescapeArgs() was improperly skipping the terminating quote in cases like "\\", where the char preceding the quote is a backslash, but the backslash itself is escaped, so the quote is indeed an unescaped terminator. unescapeArgs() doesn't unescape "\xxx" decimal escapes used by mDNS, so fix NsdService to do that sort of unescaping explicitly (which is only applicable when it receives a "fullname", in SERVICE_RESOLVED). Bug: 16983542 Bug: 16986203 Change-Id: Idfa79749336c68424d961bc414f984c525b7e5e6 --- .../com/android/server/NativeDaemonEvent.java | 20 ++++----- .../java/com/android/server/NsdService.java | 45 ++++++++++++++++--- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java index 209515279b..59d50bde1b 100644 --- a/services/core/java/com/android/server/NativeDaemonEvent.java +++ b/services/core/java/com/android/server/NativeDaemonEvent.java @@ -201,20 +201,16 @@ public class NativeDaemonEvent { } while (current < length) { // find the end of the word - if (quoted) { - wordEnd = current; - while ((wordEnd = rawEvent.indexOf('\"', wordEnd)) != -1) { - if (rawEvent.charAt(wordEnd - 1) != '\\') { - break; - } else { - wordEnd++; // skip this escaped quote and keep looking - } + char terminator = quoted ? '\"' : ' '; + wordEnd = current; + while (wordEnd < length && rawEvent.charAt(wordEnd) != terminator) { + if (rawEvent.charAt(wordEnd) == '\\') { + // skip the escaped char + ++wordEnd; } - } else { - wordEnd = rawEvent.indexOf(' ', current); + ++wordEnd; } - // if we didn't find the end-o-word token, take the rest of the string - if (wordEnd == -1) wordEnd = length; + if (wordEnd > length) wordEnd = length; String word = rawEvent.substring(current, wordEnd); current += word.length(); if (!quoted) { diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index cf7e65c0e3..cb1748d30c 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -397,8 +397,7 @@ public class NsdService extends INsdManager.Stub { break; case NsdManager.NATIVE_DAEMON_EVENT: NativeEvent event = (NativeEvent) msg.obj; - if (!handleNativeEvent(event.code, event.raw, - NativeDaemonEvent.unescapeArgs(event.raw))) { + if (!handleNativeEvent(event.code, event.raw, event.cooked)) { result = NOT_HANDLED; } break; @@ -474,8 +473,14 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_RESOLVED: /* NNN resolveId fullName hostName port txtlen txtdata */ if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw); - int index = cooked[2].indexOf("."); - if (index == -1) { + int index = 0; + while (index < cooked[2].length() && cooked[2].charAt(index) != '.') { + if (cooked[2].charAt(index) == '\\') { + ++index; + } + ++index; + } + if (index >= cooked[2].length()) { Slog.e(TAG, "Invalid service found " + raw); break; } @@ -483,6 +488,8 @@ public class NsdService extends INsdManager.Stub { String rest = cooked[2].substring(index); String type = rest.replace(".local.", ""); + name = unescape(name); + clientInfo.mResolvedService.setServiceName(name); clientInfo.mResolvedService.setServiceType(type); clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); @@ -541,6 +548,30 @@ public class NsdService extends INsdManager.Stub { } } + private String unescape(String s) { + StringBuilder sb = new StringBuilder(s.length()); + for (int i = 0; i < s.length(); ++i) { + char c = s.charAt(i); + if (c == '\\') { + if (++i >= s.length()) { + Slog.e(TAG, "Unexpected end of escape sequence in: " + s); + break; + } + c = s.charAt(i); + if (c != '.' && c != '\\') { + if (i + 2 >= s.length()) { + Slog.e(TAG, "Unexpected end of escape sequence in: " + s); + break; + } + c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0')); + i += 2; + } + } + sb.append(c); + } + return sb.toString(); + } + private NativeDaemonConnector mNativeConnector; private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); @@ -625,10 +656,12 @@ public class NsdService extends INsdManager.Stub { private class NativeEvent { final int code; final String raw; + final String[] cooked; - NativeEvent(int code, String raw) { + NativeEvent(int code, String raw, String[] cooked) { this.code = code; this.raw = raw; + this.cooked = cooked; } } @@ -644,7 +677,7 @@ public class NsdService extends INsdManager.Stub { public boolean onEvent(int code, String raw, String[] cooked) { // TODO: NDC translates a message to a callback, we could enhance NDC to // directly interact with a state machine through messages - NativeEvent event = new NativeEvent(code, raw); + NativeEvent event = new NativeEvent(code, raw, cooked); mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event); return true; } From 14966ee4ae4db34d3f1798e6413769e9f721c07f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 9 Sep 2014 12:29:41 -0700 Subject: [PATCH 0246/1150] Use sscanf() for parsing tag values. Neither strtoll() nor strtoull() can parse the %llx formatted tag values coming from the kernel. We know the lowest 32 bits will never be set, so fast-path the 3-character case as 0x0. Bug: 17365163 Change-Id: I238bbd2830c9335e7ab7a53362d6e12b46e0bcb3 --- ...droid_internal_net_NetworkStatsFactory.cpp | 36 +++++++++++-------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c84a466690..2e2d0c7d8d 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -175,17 +175,23 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, continue; } } - // Skip whitespace. - while (*pos == ' ') { - pos++; - } - // Next field is tag. - rawTag = strtoll(pos, &endPos, 16); - //ALOGI("Index #%d: %s", idx, buffer); - if (pos == endPos) { - ALOGE("bad tag: %s", pos); - fclose(fp); - return -1; + + // Ignore whitespace + while (*pos == ' ') pos++; + + // Find end of tag field + endPos = pos; + while (*endPos != ' ') endPos++; + + // Three digit field is always 0x0, otherwise parse + if (endPos - pos == 3) { + rawTag = 0; + } else { + if (sscanf(pos, "%llx", &rawTag) != 1) { + ALOGE("bad tag: %s", pos); + fclose(fp); + return -1; + } } s.tag = rawTag >> 32; if (limitTag != -1 && s.tag != limitTag) { @@ -193,10 +199,10 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, continue; } pos = endPos; - // Skip whitespace. - while (*pos == ' ') { - pos++; - } + + // Ignore whitespace + while (*pos == ' ') pos++; + // Parse remaining fields. if (sscanf(pos, "%u %u %llu %llu %llu %llu", &s.uid, &s.set, &s.rxBytes, &s.rxPackets, From a2a966b884a05494c4ca9ae540ef3a45bd2527b7 Mon Sep 17 00:00:00 2001 From: Vinit Deshpande Date: Wed, 10 Sep 2014 18:05:10 -0700 Subject: [PATCH 0247/1150] Don't require CONNECTIVITY_INTERNAL check for protected broadcasts This change removes requirement that sender has this permission for protected broadcasts (since they can only come from framework) Bug: 17409667 Change-Id: I3431c20a4ed28b3ba2bfc3cf53772e63a3424a2c --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f995deeb8d..b5aa4d83fd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -318,7 +318,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // watch for tethering changes final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED); - mContext.registerReceiver(mTetherReceiver, tetherFilter, CONNECTIVITY_INTERNAL, mHandler); + mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler); // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); From 45cc2ce6ed718b6f9bde87d230d093958db4ef0a Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Sat, 13 Sep 2014 11:13:39 -0700 Subject: [PATCH 0248/1150] Handle null values in registerService Bug: 17491971 Change-Id: I0443a9accd86ab70510d16456a03912845718ca9 --- services/core/java/com/android/server/NsdService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index cb1748d30c..39aa972bab 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -716,8 +716,9 @@ public class NsdService extends INsdManager.Stub { for (String key : txtRecords.keySet()) { try { // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data. + byte[] recordValue = txtRecords.get(key); cmd.appendArg(String.format(Locale.US, "%s=%s", key, - new String(txtRecords.get(key), "UTF_8"))); + recordValue != null ? new String(recordValue, "UTF_8") : "")); } catch (UnsupportedEncodingException e) { Slog.e(TAG, "Failed to encode txtRecord " + e); } From 8e9afdf05f204a3e5bd7101a6b210e477de2a424 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 17 Sep 2014 09:26:28 -0700 Subject: [PATCH 0249/1150] NetworkStats always needs arrays. Internal logic relies on Arrays.copyOf(), so always give ourselves valid arrays, using shared empty objects to save overhead. Bug: 17502649 Change-Id: I5dbb00545bdfe45bbd48144ab505ea08cc92cbcd --- core/java/android/net/NetworkStats.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 54d43d380a..ea5dfd184f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -24,6 +24,8 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import libcore.util.EmptyArray; + import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; @@ -169,6 +171,15 @@ public class NetworkStats implements Parcelable { } else { // Special case for use by NetworkStatsFactory to start out *really* empty. this.capacity = 0; + this.iface = EmptyArray.STRING; + this.uid = EmptyArray.INT; + this.set = EmptyArray.INT; + this.tag = EmptyArray.INT; + this.rxBytes = EmptyArray.LONG; + this.rxPackets = EmptyArray.LONG; + this.txBytes = EmptyArray.LONG; + this.txPackets = EmptyArray.LONG; + this.operations = EmptyArray.LONG; } } From 90c441a71c91334f6f356b621f68954a66d6b3ea Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 24 Oct 2014 13:15:15 -0700 Subject: [PATCH 0250/1150] Drop DEV network stats to save RAM. We migrated to pure XT stats a long time ago, so we no longer need to keep the DEV stats cached in RAM. This saves ~250KB on a typical device. Bug: 18118003 Change-Id: I3d84ba47073fa3500454784afc956c8e53404492 --- .../server/net/NetworkStatsService.java | 54 ++++--------------- 1 file changed, 10 insertions(+), 44 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b5aa4d83fd..150ad34669 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -45,7 +45,6 @@ import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE; import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES; import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Global.NETSTATS_REPORT_XT_OVER_DEV; import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED; import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE; import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION; @@ -184,7 +183,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getPollInterval(); public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); - public boolean getReportXtOverDev(); public static class Config { public final long bucketDuration; @@ -229,8 +227,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsRecorder mUidRecorder; private NetworkStatsRecorder mUidTagRecorder; - /** Cached {@link #mDevRecorder} stats. */ - private NetworkStatsCollection mDevStatsCached; /** Cached {@link #mXtRecorder} stats. */ private NetworkStatsCollection mXtStatsCached; @@ -305,7 +301,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // read historical network stats from disk, since policy service // might need them right away. - mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked(); mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); // bootstrap initial stats to prevent double-counting later @@ -386,7 +381,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidRecorder = null; mUidTagRecorder = null; - mDevStatsCached = null; mXtStatsCached = null; mSystemReady = false; @@ -523,48 +517,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Return network summary, splicing between {@link #mDevStatsCached} - * and {@link #mXtStatsCached} when appropriate. + * Return network summary, splicing between DEV and XT stats when + * appropriate. */ private NetworkStats internalGetSummaryForNetwork( NetworkTemplate template, long start, long end) { - if (!mSettings.getReportXtOverDev()) { - // shortcut when XT reporting disabled - return mDevStatsCached.getSummary(template, start, end); - } - - // splice stats between DEV and XT, switching over from DEV to XT at - // first atomic bucket. - final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); - final NetworkStats dev = mDevStatsCached.getSummary( - template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket)); - final NetworkStats xt = mXtStatsCached.getSummary( - template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket)); - - xt.combineAllValues(dev); - return xt; + // We've been using pure XT stats long enough that we no longer need to + // splice DEV and XT together. + return mXtStatsCached.getSummary(template, start, end); } /** - * Return network history, splicing between {@link #mDevStatsCached} - * and {@link #mXtStatsCached} when appropriate. + * Return network history, splicing between DEV and XT stats when + * appropriate. */ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) { - if (!mSettings.getReportXtOverDev()) { - // shortcut when XT reporting disabled - return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); - } - - // splice stats between DEV and XT, switching over from DEV to XT at - // first atomic bucket. - final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); - final NetworkStatsHistory dev = mDevStatsCached.getHistory( - template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket); - final NetworkStatsHistory xt = mXtStatsCached.getHistory( - template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE); - - xt.recordEntireHistory(dev); - return xt; + // We've been using pure XT stats long enough that we no longer need to + // splice DEV and XT together. + return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); } @Override @@ -1329,10 +1299,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true); } @Override - public boolean getReportXtOverDev() { - return getGlobalBoolean(NETSTATS_REPORT_XT_OVER_DEV, true); - } - @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 201c2f73b61c220cd26c2f132522fd679c726ae4 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Wed, 5 Nov 2014 14:36:34 -0800 Subject: [PATCH 0251/1150] DO NOT MERGE: Don't log passwords returned from vdc Turns off logging of responses from native daemon connector altogether. Proper solution to follow in LMP MR1 Bug: 18260068 Change-Id: I25bc9cb61049a3efdd9a9cd11195864a04ef05fd --- .../core/java/com/android/server/NativeDaemonConnector.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 96f9ab061c..8c3b020f57 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -176,7 +176,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (buffer[i] == 0) { final String rawEvent = new String( buffer, start, i - start, StandardCharsets.UTF_8); - log("RCV <- {" + rawEvent + "}"); boolean releaseWl = false; try { @@ -197,7 +196,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { - log("Problem parsing message: " + rawEvent + " - " + e); } finally { if (releaseWl) { mWakeLock.acquire(); @@ -209,7 +207,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } if (start == 0) { final String rawEvent = new String(buffer, start, count, StandardCharsets.UTF_8); - log("RCV incomplete <- {" + rawEvent + "}"); } // We should end at the amount we read. If not, compact then From 76d0e9f03ee6f239e8fe5822c05d251babf66919 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Wed, 12 Nov 2014 08:03:48 -0800 Subject: [PATCH 0252/1150] Frameworks/base: Wall Werror in core/jni Turn on -Wall -Werror in core/jni. Fix warnings. Clang TODO: For GCC we need to turn off Wunused-but-set-variable in the GL bindings. However, Clang doesn't have that warning and thus complains about an unknown pragma. It is necessary to make the pragma #ifdef-ed on the compiler being GCC. Change-Id: I14cab48d45c2771eef0432082356c47ed44a3d7f --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 2e2d0c7d8d..1fbe016740 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "NetworkStats" #include +#include #include #include @@ -187,7 +188,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, if (endPos - pos == 3) { rawTag = 0; } else { - if (sscanf(pos, "%llx", &rawTag) != 1) { + if (sscanf(pos, "%" PRIx64, &rawTag) != 1) { ALOGE("bad tag: %s", pos); fclose(fp); return -1; @@ -204,7 +205,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, while (*pos == ' ') pos++; // Parse remaining fields. - if (sscanf(pos, "%u %u %llu %llu %llu %llu", + if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 6) { if (limitUid != -1 && limitUid != s.uid) { From 32b3f2ca3677560aa8a2993164d248b41314ff26 Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 20 Oct 2014 12:04:13 +0900 Subject: [PATCH 0253/1150] Add an API to check availability of Ethernet interface. Bug: 18045481 Change-Id: I95358241b431cfe4435ce70c23c9a639b9dc4d58 --- core/java/android/net/EthernetManager.java | 97 +++++++++++++++++-- core/java/android/net/IEthernetManager.aidl | 4 + .../android/net/IEthernetServiceListener.aidl | 23 +++++ 3 files changed, 114 insertions(+), 10 deletions(-) create mode 100644 core/java/android/net/IEthernetServiceListener.aidl diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index d965f27c8f..f45737a66e 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -18,11 +18,14 @@ package android.net; import android.content.Context; import android.net.IEthernetManager; +import android.net.IEthernetServiceListener; import android.net.IpConfiguration; -import android.net.IpConfiguration.IpAssignment; -import android.net.IpConfiguration.ProxySettings; +import android.os.Handler; +import android.os.Message; import android.os.RemoteException; +import java.util.ArrayList; + /** * A class representing the IP configuration of the Ethernet network. * @@ -30,9 +33,41 @@ import android.os.RemoteException; */ public class EthernetManager { private static final String TAG = "EthernetManager"; + private static final int MSG_AVAILABILITY_CHANGED = 1000; private final Context mContext; private final IEthernetManager mService; + private final Handler mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + if (msg.what == MSG_AVAILABILITY_CHANGED) { + boolean isAvailable = (msg.arg1 == 1); + for (Listener listener : mListeners) { + listener.onAvailabilityChanged(isAvailable); + } + } + } + }; + private final ArrayList mListeners = new ArrayList(); + private final IEthernetServiceListener.Stub mServiceListener = + new IEthernetServiceListener.Stub() { + @Override + public void onAvailabilityChanged(boolean isAvailable) { + mHandler.obtainMessage( + MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget(); + } + }; + + /** + * A listener interface to receive notification on changes in Ethernet. + */ + public interface Listener { + /** + * Called when Ethernet port's availability is changed. + * @param isAvailable {@code true} if one or more Ethernet port exists. + */ + public void onAvailabilityChanged(boolean isAvailable); + } /** * Create a new EthernetManager instance. @@ -50,12 +85,9 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ public IpConfiguration getConfiguration() { - if (mService == null) { - return new IpConfiguration(); - } try { return mService.getConfiguration(); - } catch (RemoteException e) { + } catch (NullPointerException | RemoteException e) { return new IpConfiguration(); } } @@ -64,12 +96,57 @@ public class EthernetManager { * Set Ethernet configuration. */ public void setConfiguration(IpConfiguration config) { - if (mService == null) { - return; - } try { mService.setConfiguration(config); - } catch (RemoteException e) { + } catch (NullPointerException | RemoteException e) { + } + } + + /** + * Indicates whether the system currently has one or more + * Ethernet interfaces. + */ + public boolean isAvailable() { + try { + return mService.isAvailable(); + } catch (NullPointerException | RemoteException e) { + return false; + } + } + + /** + * Adds a listener. + * @param listener A {@link Listener} to add. + * @throws IllegalArgumentException If the listener is null. + */ + public void addListener(Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + mListeners.add(listener); + if (mListeners.size() == 1) { + try { + mService.addListener(mServiceListener); + } catch (NullPointerException | RemoteException e) { + } + } + } + + /** + * Removes a listener. + * @param listener A {@link Listener} to remove. + * @throws IllegalArgumentException If the listener is null. + */ + public void removeListener(Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + mListeners.remove(listener); + if (mListeners.isEmpty()) { + try { + mService.removeListener(mServiceListener); + } catch (NullPointerException | RemoteException e) { + } } } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 3fa08f81a8..7a92eb955a 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.IpConfiguration; +import android.net.IEthernetServiceListener; /** * Interface that answers queries about, and allows changing @@ -27,4 +28,7 @@ interface IEthernetManager { IpConfiguration getConfiguration(); void setConfiguration(in IpConfiguration config); + boolean isAvailable(); + void addListener(in IEthernetServiceListener listener); + void removeListener(in IEthernetServiceListener listener); } diff --git a/core/java/android/net/IEthernetServiceListener.aidl b/core/java/android/net/IEthernetServiceListener.aidl new file mode 100644 index 0000000000..356690e8f7 --- /dev/null +++ b/core/java/android/net/IEthernetServiceListener.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +oneway interface IEthernetServiceListener +{ + void onAvailabilityChanged(boolean isAvailable); +} From 394a29333ef34bde01abbce3b1c76c4c5cc8e7d9 Mon Sep 17 00:00:00 2001 From: Geoffrey Borggaard Date: Thu, 20 Nov 2014 14:35:32 -0500 Subject: [PATCH 0254/1150] Fix null handling in proxies. ProxyInfo.getPacFileUrl() can not be null. It will be equal to Uri.EMPTY. Checking for null was causing global proxies to never be disabled. Or more accurately, global proxies would be disabled, but would reappear after a reboot. ProxyInfo.getExclusionListByString() can be null. If no exclusion list was specified, the proxy settings would not be successfully saved, they would disappear after reboot. Bug: 18453223 Change-Id: I1c27e5dca5b9664bb7468ea909bff489fa110a07 --- .../core/java/com/android/server/net/IpConfigStore.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 857b9e90a0..b5a450dc8b 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -122,8 +122,10 @@ public class IpConfigStore { out.writeUTF(proxyProperties.getHost()); out.writeUTF(PROXY_PORT_KEY); out.writeInt(proxyProperties.getPort()); - out.writeUTF(EXCLUSION_LIST_KEY); - out.writeUTF(exclusionList); + if (exclusionList != null) { + out.writeUTF(EXCLUSION_LIST_KEY); + out.writeUTF(exclusionList); + } written = true; break; case PAC: From 583d9568861f9f8a16824feea7ec768a147567b7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 18 Nov 2014 18:22:21 -0800 Subject: [PATCH 0255/1150] Lightweight checkin output for network stats. Define and print a compact version of network statistics when dump is requested with the "--checkin" flag. Defaults to last 24 hours, but included data can be tweaked with various flags. Groups together detailed network identities into larger umbrella terms like "mobile" and "wifi." Bug: 18415963 Change-Id: I70cf9c828ea5c6e5bb6884837d3608f66fbad2e6 --- core/java/android/net/NetworkIdentity.java | 24 ++++- core/java/android/net/NetworkStats.java | 16 +++ .../java/android/net/NetworkStatsHistory.java | 48 +++++++-- core/java/android/net/NetworkTemplate.java | 28 +++++- .../server/net/NetworkIdentitySet.java | 13 ++- .../server/net/NetworkStatsCollection.java | 99 ++++++++++++++++--- .../server/net/NetworkStatsRecorder.java | 51 +++++++--- .../server/net/NetworkStatsService.java | 36 +++++-- 8 files changed, 261 insertions(+), 54 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 36dd2fdfbc..d36707e4cb 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -34,7 +34,7 @@ import java.util.Objects; * * @hide */ -public class NetworkIdentity { +public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. @@ -76,7 +76,7 @@ public class NetworkIdentity { @Override public String toString() { - final StringBuilder builder = new StringBuilder("["); + final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); if (COMBINE_SUBTYPE_ENABLED) { @@ -95,7 +95,7 @@ public class NetworkIdentity { if (mRoaming) { builder.append(", ROAMING"); } - return builder.append("]").toString(); + return builder.append("}").toString(); } public int getType() { @@ -170,4 +170,22 @@ public class NetworkIdentity { return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); } + + @Override + public int compareTo(NetworkIdentity another) { + int res = Integer.compare(mType, another.mType); + if (res == 0) { + res = Integer.compare(mSubType, another.mSubType); + } + if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) { + res = mSubscriberId.compareTo(another.mSubscriberId); + } + if (res == 0 && mNetworkId != null && another.mNetworkId != null) { + res = mNetworkId.compareTo(another.mNetworkId); + } + if (res == 0) { + res = Boolean.compare(mRoaming, another.mRoaming); + } + return res; + } } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ea5dfd184f..2afe578b6b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -732,6 +732,22 @@ public class NetworkStats implements Parcelable { } } + /** + * Return text description of {@link #set} value. + */ + public static String setToCheckinString(int set) { + switch (set) { + case SET_ALL: + return "all"; + case SET_DEFAULT: + return "def"; + case SET_FOREGROUND: + return "fg"; + default: + return "unk"; + } + } + /** * Return text description of {@link #tag} value. */ diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 62d8738ba6..4a4accbba5 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -26,6 +26,7 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; @@ -38,6 +39,7 @@ import java.io.CharArrayWriter; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; +import java.io.PrintWriter; import java.net.ProtocolException; import java.util.Arrays; import java.util.Random; @@ -573,8 +575,22 @@ public class NetworkStatsHistory implements Parcelable { return (long) (start + (r.nextFloat() * (end - start))); } + /** + * Quickly determine if this history intersects with given window. + */ + public boolean intersects(long start, long end) { + final long dataStart = getStart(); + final long dataEnd = getEnd(); + if (start >= dataStart && start <= dataEnd) return true; + if (end >= dataStart && end <= dataEnd) return true; + if (dataStart >= start && dataStart <= end) return true; + if (dataEnd >= start && dataEnd <= end) return true; + return false; + } + public void dump(IndentingPrintWriter pw, boolean fullHistory) { - pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration); + pw.print("NetworkStatsHistory: bucketDuration="); + pw.println(bucketDuration / SECOND_IN_MILLIS); pw.increaseIndent(); final int start = fullHistory ? 0 : Math.max(0, bucketCount - 32); @@ -583,19 +599,35 @@ public class NetworkStatsHistory implements Parcelable { } for (int i = start; i < bucketCount; i++) { - pw.print("bucketStart="); pw.print(bucketStart[i]); - if (activeTime != null) { pw.print(" activeTime="); pw.print(activeTime[i]); } - if (rxBytes != null) { pw.print(" rxBytes="); pw.print(rxBytes[i]); } - if (rxPackets != null) { pw.print(" rxPackets="); pw.print(rxPackets[i]); } - if (txBytes != null) { pw.print(" txBytes="); pw.print(txBytes[i]); } - if (txPackets != null) { pw.print(" txPackets="); pw.print(txPackets[i]); } - if (operations != null) { pw.print(" operations="); pw.print(operations[i]); } + pw.print("st="); pw.print(bucketStart[i] / SECOND_IN_MILLIS); + if (rxBytes != null) { pw.print(" rb="); pw.print(rxBytes[i]); } + if (rxPackets != null) { pw.print(" rp="); pw.print(rxPackets[i]); } + if (txBytes != null) { pw.print(" tb="); pw.print(txBytes[i]); } + if (txPackets != null) { pw.print(" tp="); pw.print(txPackets[i]); } + if (operations != null) { pw.print(" op="); pw.print(operations[i]); } pw.println(); } pw.decreaseIndent(); } + public void dumpCheckin(PrintWriter pw) { + pw.print("d,"); + pw.print(bucketDuration / SECOND_IN_MILLIS); + pw.println(); + + for (int i = 0; i < bucketCount; i++) { + pw.print("b,"); + pw.print(bucketStart[i] / SECOND_IN_MILLIS); pw.print(','); + if (rxBytes != null) { pw.print(rxBytes[i]); } else { pw.print("*"); } pw.print(','); + if (rxPackets != null) { pw.print(rxPackets[i]); } else { pw.print("*"); } pw.print(','); + if (txBytes != null) { pw.print(txBytes[i]); } else { pw.print("*"); } pw.print(','); + if (txPackets != null) { pw.print(txPackets[i]); } else { pw.print("*"); } pw.print(','); + if (operations != null) { pw.print(operations[i]); } else { pw.print("*"); } + pw.println(); + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 27197cc8a3..b839e0ac69 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -16,6 +16,7 @@ package android.net; +import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; @@ -34,10 +35,10 @@ import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; -import java.util.Objects; - import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * Template definition used to generically match {@link NetworkIdentity}, * usually when collecting statistics. @@ -53,6 +54,7 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_ETHERNET = 5; public static final int MATCH_MOBILE_WILDCARD = 6; public static final int MATCH_WIFI_WILDCARD = 7; + public static final int MATCH_BLUETOOTH = 8; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -134,6 +136,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_ETHERNET, null, null); } + /** + * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style + * networks together. + */ + public static NetworkTemplate buildTemplateBluetooth() { + return new NetworkTemplate(MATCH_BLUETOOTH, null, null); + } + private final int mMatchRule; private final String mSubscriberId; private final String mNetworkId; @@ -222,6 +232,8 @@ public class NetworkTemplate implements Parcelable { return matchesMobileWildcard(ident); case MATCH_WIFI_WILDCARD: return matchesWifiWildcard(ident); + case MATCH_BLUETOOTH: + return matchesBluetooth(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -316,6 +328,16 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Check if matches Bluetooth network template. + */ + private boolean matchesBluetooth(NetworkIdentity ident) { + if (ident.mType == TYPE_BLUETOOTH) { + return true; + } + return false; + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -332,6 +354,8 @@ public class NetworkTemplate implements Parcelable { return "MOBILE_WILDCARD"; case MATCH_WIFI_WILDCARD: return "WIFI_WILDCARD"; + case MATCH_BLUETOOTH: + return "BLUETOOTH"; default: return "UNKNOWN"; } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 397f9f41d8..f230bb39be 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -29,7 +29,8 @@ import java.util.HashSet; * * @hide */ -public class NetworkIdentitySet extends HashSet { +public class NetworkIdentitySet extends HashSet implements + Comparable { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; private static final int VERSION_ADD_NETWORK_ID = 3; @@ -92,4 +93,14 @@ public class NetworkIdentitySet extends HashSet { return null; } } + + @Override + public int compareTo(NetworkIdentitySet another) { + if (isEmpty()) return -1; + if (another.isEmpty()) return 1; + + final NetworkIdentity ident = iterator().next(); + final NetworkIdentity anotherIdent = another.iterator().next(); + return ident.compareTo(anotherIdent); + } } diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 475482f6dd..3ac20f72f9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -22,15 +22,20 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; -import android.text.format.DateUtils; +import android.util.ArrayMap; import android.util.AtomicFile; +import libcore.io.IoUtils; + import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -44,15 +49,13 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.PrintWriter; import java.net.ProtocolException; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; -import java.util.Map; import java.util.Objects; -import libcore.io.IoUtils; - /** * Collection of {@link NetworkStatsHistory}, stored based on combined key of * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. @@ -70,7 +73,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { private static final int VERSION_UNIFIED_INIT = 16; - private HashMap mStats = Maps.newHashMap(); + private ArrayMap mStats = new ArrayMap<>(); private final long mBucketDuration; @@ -145,12 +148,13 @@ public class NetworkStatsCollection implements FileRotator.Reader { NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { final NetworkStatsHistory combined = new NetworkStatsHistory( mBucketDuration, estimateBuckets(), fields); - for (Map.Entry entry : mStats.entrySet()) { - final Key key = entry.getKey(); + for (int i = 0; i < mStats.size(); i++) { + final Key key = mStats.keyAt(i); final boolean setMatches = set == SET_ALL || key.set == set; if (key.uid == uid && setMatches && key.tag == tag && templateMatches(template, key.ident)) { - combined.recordHistory(entry.getValue(), start, end); + final NetworkStatsHistory value = mStats.valueAt(i); + combined.recordHistory(value, start, end); } } return combined; @@ -170,11 +174,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { // shortcut when we know stats will be empty if (start == end) return stats; - for (Map.Entry mapEntry : mStats.entrySet()) { - final Key key = mapEntry.getKey(); + for (int i = 0; i < mStats.size(); i++) { + final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident)) { - final NetworkStatsHistory history = mapEntry.getValue(); - historyEntry = history.getValues(start, end, now, historyEntry); + final NetworkStatsHistory value = mStats.valueAt(i); + historyEntry = value.getValues(start, end, now, historyEntry); entry.iface = IFACE_ALL; entry.uid = key.uid; @@ -225,8 +229,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { * into this collection. */ public void recordCollection(NetworkStatsCollection another) { - for (Map.Entry entry : another.mStats.entrySet()) { - recordHistory(entry.getKey(), entry.getValue()); + for (int i = 0; i < another.mStats.size(); i++) { + final Key key = another.mStats.keyAt(i); + final NetworkStatsHistory value = another.mStats.valueAt(i); + recordHistory(key, value); } } @@ -460,7 +466,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { } private int estimateBuckets() { - return (int) (Math.min(mEndMillis - mStartMillis, DateUtils.WEEK_IN_MILLIS * 5) + return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) / mBucketDuration); } @@ -482,6 +488,54 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + public void dumpCheckin(PrintWriter pw, long start, long end) { + dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); + dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); + dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateEthernet(), "eth"); + dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateBluetooth(), "bt"); + } + + /** + * Dump all contained stats that match requested parameters, but group + * together all matching {@link NetworkTemplate} under a single prefix. + */ + private void dumpCheckin(PrintWriter pw, long start, long end, NetworkTemplate groupTemplate, + String groupPrefix) { + final ArrayMap grouped = new ArrayMap<>(); + + // Walk through all history, grouping by matching network templates + for (int i = 0; i < mStats.size(); i++) { + final Key key = mStats.keyAt(i); + final NetworkStatsHistory value = mStats.valueAt(i); + + if (!templateMatches(groupTemplate, key.ident)) continue; + + final Key groupKey = new Key(null, key.uid, key.set, key.tag); + NetworkStatsHistory groupHistory = grouped.get(groupKey); + if (groupHistory == null) { + groupHistory = new NetworkStatsHistory(value.getBucketDuration()); + grouped.put(groupKey, groupHistory); + } + groupHistory.recordHistory(value, start, end); + } + + for (int i = 0; i < grouped.size(); i++) { + final Key key = grouped.keyAt(i); + final NetworkStatsHistory value = grouped.valueAt(i); + + if (value.size() == 0) continue; + + pw.print("c,"); + pw.print(groupPrefix); pw.print(','); + pw.print(key.uid); pw.print(','); + pw.print(NetworkStats.setToCheckinString(key.set)); pw.print(','); + pw.print(key.tag); + pw.println(); + + value.dumpCheckin(pw); + } + } + /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. @@ -528,7 +582,20 @@ public class NetworkStatsCollection implements FileRotator.Reader { @Override public int compareTo(Key another) { - return Integer.compare(uid, another.uid); + int res = 0; + if (ident != null && another.ident != null) { + res = ident.compareTo(another.ident); + } + if (res == 0) { + res = Integer.compare(uid, another.uid); + } + if (res == 0) { + res = Integer.compare(set, another.set); + } + if (res == 0) { + res = Integer.compare(tag, another.tag); + } + return res; } } } diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index cea084b518..d5d7667630 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,6 +41,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.Arrays; import java.util.HashSet; @@ -124,23 +125,36 @@ public class NetworkStatsRecorder { * as reference is valid. */ public NetworkStatsCollection getOrLoadCompleteLocked() { - NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; - if (complete == null) { - if (LOGD) Slog.d(TAG, "getOrLoadCompleteLocked() reading from disk for " + mCookie); - try { - complete = new NetworkStatsCollection(mBucketDuration); - mRotator.readMatching(complete, Long.MIN_VALUE, Long.MAX_VALUE); - complete.recordCollection(mPending); - mComplete = new WeakReference(complete); - } catch (IOException e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem completely reading network stats", e); - recoverFromWtf(); - } + NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; + if (res == null) { + res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE); + mComplete = new WeakReference(res); } - return complete; + return res; + } + + public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) { + NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; + if (res == null) { + res = loadLocked(start, end); + } + return res; + } + + private NetworkStatsCollection loadLocked(long start, long end) { + if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie); + final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration); + try { + mRotator.readMatching(res, start, end); + res.recordCollection(mPending); + } catch (IOException e) { + Log.wtf(TAG, "problem completely reading network stats", e); + recoverFromWtf(); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem completely reading network stats", e); + recoverFromWtf(); + } + return res; } /** @@ -384,6 +398,11 @@ public class NetworkStatsRecorder { } } + public void dumpCheckin(PrintWriter pw, long start, long end) { + // Only load and dump stats from the requested window + getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end); + } + /** * Recover from {@link FileRotator} failure by dumping state to * {@link DropBoxManager} and deleting contents. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 150ad34669..61f9a267fe 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -104,6 +104,7 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; +import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; @@ -1094,12 +1095,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); + long duration = DateUtils.DAY_IN_MILLIS; final HashSet argSet = new HashSet(); for (String arg : args) { argSet.add(arg); + + if (arg.startsWith("--duration=")) { + try { + duration = Long.parseLong(arg.substring(11)); + } catch (NumberFormatException ignored) { + } + } } // usage: dumpsys netstats --full --uid --tag --poll --checkin @@ -1109,7 +1118,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean includeUid = argSet.contains("--uid") || argSet.contains("detail"); final boolean includeTag = argSet.contains("--tag") || argSet.contains("detail"); - final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); + final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); synchronized (mStatsLock) { if (poll) { @@ -1119,13 +1128,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } if (checkin) { - // list current stats files to verify rotation - pw.println("Current files:"); - pw.increaseIndent(); - for (String file : mBaseDir.list()) { - pw.println(file); + final long end = System.currentTimeMillis(); + final long start = end - duration; + + pw.print("v1,"); + pw.print(start / SECOND_IN_MILLIS); pw.print(','); + pw.print(end / SECOND_IN_MILLIS); pw.println(); + + pw.println("xt"); + mXtRecorder.dumpCheckin(rawWriter, start, end); + + if (includeUid) { + pw.println("uid"); + mUidRecorder.dumpCheckin(rawWriter, start, end); + } + if (includeTag) { + pw.println("tag"); + mUidTagRecorder.dumpCheckin(rawWriter, start, end); } - pw.decreaseIndent(); return; } From b9fd0471a6957f8f2e4601811afb4a04412b5e3b Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Thu, 20 Nov 2014 22:02:20 -0800 Subject: [PATCH 0256/1150] Frameworks/base: Consistency in core/jni Make consistent use of core_jni_helpers for registration. Translate some #ifdefs into const bools. Change-Id: I37639aa053dd50f003a552cbd8550dddecc811c5 --- core/jni/android_net_TrafficStats.cpp | 5 +-- ...droid_internal_net_NetworkStatsFactory.cpp | 41 ++++++++----------- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 031637f41d..7354417435 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -23,7 +23,7 @@ #include #include -#include +#include "core_jni_helpers.h" #include #include #include @@ -192,8 +192,7 @@ static JNINativeMethod gMethods[] = { }; int register_android_net_TrafficStats(JNIEnv* env) { - return AndroidRuntime::registerNativeMethods(env, "android/net/TrafficStats", - gMethods, NELEM(gMethods)); + return RegisterMethodsOrDie(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); } } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 1fbe016740..6c0b756591 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include @@ -284,16 +284,6 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, return 0; } -static jclass findClass(JNIEnv* env, const char* name) { - ScopedLocalRef localClass(env, env->FindClass(name)); - jclass result = reinterpret_cast(env->NewGlobalRef(localClass.get())); - if (result == NULL) { - ALOGE("failed to find class '%s'", name); - abort(); - } - return result; -} - static JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", @@ -301,24 +291,25 @@ static JNINativeMethod gMethods[] = { }; int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { - int err = AndroidRuntime::registerNativeMethods(env, + int err = RegisterMethodsOrDie(env, "com/android/internal/net/NetworkStatsFactory", gMethods, NELEM(gMethods)); - gStringClass = findClass(env, "java/lang/String"); + gStringClass = FindClassOrDie(env, "java/lang/String"); + gStringClass = MakeGlobalRefOrDie(env, gStringClass); - jclass clazz = env->FindClass("android/net/NetworkStats"); - gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); - gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); + jclass clazz = FindClassOrDie(env, "android/net/NetworkStats"); + gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I"); + gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I"); + gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;"); + gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); + gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); + gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); + gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); + gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); + gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J"); + gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J"); return err; } From 1e803d5ed0544fc9fe57199ad32d4310615fcaad Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Nov 2014 17:28:28 +0000 Subject: [PATCH 0257/1150] Revert "DO NOT MERGE: Don't log passwords returned from vdc" This reverts commit 201c2f73b61c220cd26c2f132522fd679c726ae4. The original change disabled all logging of RCVed messages in NativeDaemonConnector. For MR1 we want a much more surgical disabling of sensitive messages. First, though, we have to defeat the automerger. Change-Id: I712919aee2db63f7fc0b2c6d6a2a658325dce596 --- .../core/java/com/android/server/NativeDaemonConnector.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 8c3b020f57..96f9ab061c 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -176,6 +176,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (buffer[i] == 0) { final String rawEvent = new String( buffer, start, i - start, StandardCharsets.UTF_8); + log("RCV <- {" + rawEvent + "}"); boolean releaseWl = false; try { @@ -196,6 +197,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { + log("Problem parsing message: " + rawEvent + " - " + e); } finally { if (releaseWl) { mWakeLock.acquire(); @@ -207,6 +209,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } if (start == 0) { final String rawEvent = new String(buffer, start, count, StandardCharsets.UTF_8); + log("RCV incomplete <- {" + rawEvent + "}"); } // We should end at the amount we read. If not, compact then From 19a1c3f7d96b59ce844b23e2478ddc29a394804c Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Tue, 11 Nov 2014 12:23:22 -0800 Subject: [PATCH 0258/1150] Add mechanism for securely returning parameters though NativeDaemonConnector If the first word in the response is {{sensitive}}, don't log the body of the response. Bug: 18260068 Change-Id: Ibfb5c6abab1d04b4321cdbcf6c7cf6f18f903146 --- .../android/server/NativeDaemonConnector.java | 12 ++++++++---- .../com/android/server/NativeDaemonEvent.java | 17 ++++++++++++++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 96f9ab061c..d2dfc7bbdc 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -174,14 +174,18 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo for (int i = 0; i < count; i++) { if (buffer[i] == 0) { + // Note - do not log this raw message since it may contain + // sensitive data final String rawEvent = new String( buffer, start, i - start, StandardCharsets.UTF_8); - log("RCV <- {" + rawEvent + "}"); boolean releaseWl = false; try { final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( rawEvent); + + log("RCV <- {" + event + "}"); + if (event.isClassUnsolicited()) { // TODO: migrate to sending NativeDaemonEvent instances if (mCallbacks.onCheckHoldWakeLock(event.getCode()) @@ -197,7 +201,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mResponseQueue.add(event.getCmdNumber(), event); } } catch (IllegalArgumentException e) { - log("Problem parsing message: " + rawEvent + " - " + e); + log("Problem parsing message " + e); } finally { if (releaseWl) { mWakeLock.acquire(); @@ -207,9 +211,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo start = i + 1; } } + if (start == 0) { - final String rawEvent = new String(buffer, start, count, StandardCharsets.UTF_8); - log("RCV incomplete <- {" + rawEvent + "}"); + log("RCV incomplete"); } // We should end at the amount we read. If not, compact then diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java index 59d50bde1b..4e61c0b09d 100644 --- a/services/core/java/com/android/server/NativeDaemonEvent.java +++ b/services/core/java/com/android/server/NativeDaemonEvent.java @@ -33,16 +33,21 @@ public class NativeDaemonEvent { private final int mCode; private final String mMessage; private final String mRawEvent; + private final String mLogMessage; private String[] mParsed; - private NativeDaemonEvent(int cmdNumber, int code, String message, String rawEvent) { + private NativeDaemonEvent(int cmdNumber, int code, String message, + String rawEvent, String logMessage) { mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; + mLogMessage = logMessage; mParsed = null; } + static public final String SENSITIVE_MARKER = "{{sensitive}}"; + public int getCmdNumber() { return mCmdNumber; } @@ -62,7 +67,7 @@ public class NativeDaemonEvent { @Override public String toString() { - return mRawEvent; + return mLogMessage; } /** @@ -151,9 +156,15 @@ public class NativeDaemonEvent { } } + String logMessage = rawEvent; + if (parsed.length > 2 && parsed[2].equals(SENSITIVE_MARKER)) { + skiplength += parsed[2].length() + 1; + logMessage = parsed[0] + " " + parsed[1] + " {}"; + } + final String message = rawEvent.substring(skiplength); - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent); + return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage); } /** From ae5a8a5ec8ad17cc2bfe305553a44fc4d929bcea Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 2 Dec 2014 18:30:14 -0800 Subject: [PATCH 0259/1150] Offer to "merge" subscribers for data usage. There are some cases where multiple subscriber identities (IMSI) should be treated as "merged together" from a data usage perspective. This is done by extending the template used for matching purposes to support multiple subscribers. Then, when we query historical usage or set network policies, we normalize the matching template to merge to any other identities that should be included. When normalizing, the "lowest" identity is always used for equality and storage purposes, which allows identities to come and go over time. This change also fixes data usage recording for multi-SIM devices by passing along the concrete subscriber identity for each network interface. Also correctly create default policies for multi-SIM devices. This change also drops setPolicyDataEnable() until it can be wired up to the right underlying NetworkAgent. (This means we still bring up the network, and then rely on iptables rules to block traffic when over the limit, instead of proactively disabling the connection.) Bug: 18012787 Change-Id: If6acf32009fdfea2b836f5aff8e2f3e5e0248b4a --- core/java/android/net/NetworkIdentity.java | 30 ++++++---- core/java/android/net/NetworkTemplate.java | 67 ++++++++++++++++++++-- 2 files changed, 83 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d36707e4cb..6864749875 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.telephony.TelephonyManager; +import android.util.Slog; import java.util.Objects; @@ -35,6 +36,8 @@ import java.util.Objects; * @hide */ public class NetworkIdentity implements Comparable { + private static final String TAG = "NetworkIdentity"; + /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. @@ -132,6 +135,18 @@ public class NetworkIdentity implements Comparable { } } + /** + * Scrub given IMSI on production builds. + */ + public static String[] scrubSubscriberId(String[] subscriberId) { + if (subscriberId == null) return null; + final String[] res = new String[subscriberId.length]; + for (int i = 0; i < res.length; i++) { + res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]); + } + return res; + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. @@ -140,23 +155,18 @@ public class NetworkIdentity implements Comparable { final int type = state.networkInfo.getType(); final int subType = state.networkInfo.getSubtype(); - // TODO: consider moving subscriberId over to LinkCapabilities, so it - // comes from an authoritative source. - String subscriberId = null; String networkId = null; boolean roaming = false; if (isNetworkTypeMobile(type)) { - final TelephonyManager telephony = (TelephonyManager) context.getSystemService( - Context.TELEPHONY_SERVICE); - roaming = telephony.isNetworkRoaming(); - if (state.subscriberId != null) { - subscriberId = state.subscriberId; - } else { - subscriberId = telephony.getSubscriberId(); + if (state.subscriberId == null) { + Slog.w(TAG, "Active mobile network without subscriber!"); } + subscriberId = state.subscriberId; + roaming = state.networkInfo.isRoaming(); + } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b839e0ac69..6cfab92360 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -22,7 +22,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; -import static android.net.NetworkIdentity.scrubSubscriberId; import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -36,7 +35,9 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; +import java.util.Arrays; import java.util.Objects; /** @@ -146,17 +147,35 @@ public class NetworkTemplate implements Parcelable { private final int mMatchRule; private final String mSubscriberId; + + /** + * Ugh, templates are designed to target a single subscriber, but we might + * need to match several "merged" subscribers. These are the subscribers + * that should be considered to match this template. + *

+ * Since the merge set is dynamic, it should not be persisted or + * used for determining equality. + */ + private final String[] mMatchSubscriberIds; + private final String mNetworkId; public NetworkTemplate(int matchRule, String subscriberId, String networkId) { + this(matchRule, subscriberId, new String[] { subscriberId }, networkId); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId) { mMatchRule = matchRule; mSubscriberId = subscriberId; + mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; } private NetworkTemplate(Parcel in) { mMatchRule = in.readInt(); mSubscriberId = in.readString(); + mMatchSubscriberIds = in.createStringArray(); mNetworkId = in.readString(); } @@ -164,6 +183,7 @@ public class NetworkTemplate implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); + dest.writeStringArray(mMatchSubscriberIds); dest.writeString(mNetworkId); } @@ -177,7 +197,12 @@ public class NetworkTemplate implements Parcelable { final StringBuilder builder = new StringBuilder("NetworkTemplate: "); builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); if (mSubscriberId != null) { - builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + builder.append(", subscriberId=").append( + NetworkIdentity.scrubSubscriberId(mSubscriberId)); + } + if (mMatchSubscriberIds != null) { + builder.append(", matchSubscriberIds=").append( + Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds))); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); @@ -201,6 +226,18 @@ public class NetworkTemplate implements Parcelable { return false; } + public boolean isMatchRuleMobile() { + switch (mMatchRule) { + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_MOBILE_ALL: + case MATCH_MOBILE_WILDCARD: + return true; + default: + return false; + } + } + public int getMatchRule() { return mMatchRule; } @@ -247,8 +284,9 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ((sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)) - && Objects.equals(mSubscriberId, ident.mSubscriberId)); + final boolean matchesType = (sForceAllNetworkTypes + || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); + return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } @@ -368,6 +406,27 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Examine the given template and normalize if it refers to a "merged" + * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + *

+ * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that primarily matches + * A, but also matches B. + */ + public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { + if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { + // Requested template subscriber is part of the merge group; return + // a template that matches all merged subscribers. + return new NetworkTemplate(template.mMatchRule, merged[0], merged, + template.mNetworkId); + } else { + return template; + } + } + public static final Creator CREATOR = new Creator() { @Override public NetworkTemplate createFromParcel(Parcel in) { From 5fb4f650df42cd39536b78061085bab04206ee4c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 8 Dec 2014 14:50:12 -0800 Subject: [PATCH 0260/1150] Direct notification of network interface changes. Connectivity broadcasts recently changed and are no longer sent for certain types of network changes. For example, when stacked network interfaces change for a mobile network. To ensure that we pick up all these details, directly wire the two services together. Also remove some unused code for split network types. Bug: 18666753 Change-Id: I0467bd5b330c0e0cb51af2306d821b41ad16337a --- .../android/net/INetworkStatsService.aidl | 4 + core/java/android/net/NetworkIdentity.java | 4 + core/java/android/net/NetworkTemplate.java | 4 + .../server/net/NetworkStatsService.java | 76 ++++--------------- 4 files changed, 25 insertions(+), 63 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index b7b8731855..2c3881c4f7 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -40,8 +40,12 @@ interface INetworkStatsService { /** Mark given UID as being in foreground for stats purposes. */ void setUidForeground(int uid, boolean uidForeground); + + /** Force update of ifaces. */ + void forceUpdateIfaces(); /** Force update of statistics. */ void forceUpdate(); + /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 6864749875..a9de23ef1b 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -41,7 +41,11 @@ public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. + * + * @deprecated we no longer offer to collect statistics on a per-subtype + * basis; this is always disabled. */ + @Deprecated public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 6cfab92360..57eef83431 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -49,7 +49,9 @@ import java.util.Objects; public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_ALL = 1; + @Deprecated public static final int MATCH_MOBILE_3G_LOWER = 2; + @Deprecated public static final int MATCH_MOBILE_4G = 3; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; @@ -293,6 +295,7 @@ public class NetworkTemplate implements Parcelable { /** * Check if mobile network classified 3G or lower with matching IMSI. */ + @Deprecated private boolean matchesMobile3gLower(NetworkIdentity ident) { ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { @@ -311,6 +314,7 @@ public class NetworkTemplate implements Parcelable { /** * Check if mobile network classified 4G with matching IMSI. */ + @Deprecated private boolean matchesMobile4g(NetworkIdentity ident) { ensureSubtypeAvailable(); if (ident.mType == TYPE_WIMAX) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 61f9a267fe..856a07667d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -26,9 +26,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; @@ -55,8 +53,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_DATA_CONNECTION_STATE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -102,7 +98,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; -import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -308,10 +303,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { bootstrapStatsLocked(); } - // watch for network interfaces to be claimed - final IntentFilter connFilter = new IntentFilter(CONNECTIVITY_ACTION_IMMEDIATE); - mContext.registerReceiver(mConnReceiver, connFilter, CONNECTIVITY_INTERNAL, mHandler); - // watch for tethering changes final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED); mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler); @@ -338,12 +329,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // ignored; service lives in system_server } - // watch for networkType changes that aren't broadcast through - // CONNECTIVITY_ACTION_IMMEDIATE above. - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_DATA_CONNECTION_STATE); - } - registerPollAlarmLocked(); registerGlobalAlert(); } @@ -358,16 +343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void shutdownLocked() { - mContext.unregisterReceiver(mConnReceiver); mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); @@ -619,6 +599,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public void forceUpdateIfaces() { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + assertBandwidthControlEnabled(); + + final long token = Binder.clearCallingIdentity(); + try { + updateIfaces(); + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); @@ -675,20 +668,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mGlobalAlertBytes = mSettings.getGlobalAlertBytes(mPersistThreshold); } - /** - * Receiver that watches for {@link IConnectivityManager} to claim network - * interfaces. Used to associate {@link TelephonyManager#getSubscriberId()} - * with mobile interfaces. - */ - private BroadcastReceiver mConnReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - // on background handler thread, and verified CONNECTIVITY_INTERNAL - // permission above. - updateIfaces(); - } - }; - /** * Receiver that watches for {@link Tethering} to claim interface pairs. */ @@ -784,35 +763,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private int mLastPhoneState = TelephonyManager.DATA_UNKNOWN; - private int mLastPhoneNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN; - - /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between network types. - */ - private PhoneStateListener mPhoneListener = new PhoneStateListener() { - @Override - public void onDataConnectionStateChanged(int state, int networkType) { - final boolean stateChanged = state != mLastPhoneState; - final boolean networkTypeChanged = networkType != mLastPhoneNetworkType; - - if (networkTypeChanged && !stateChanged) { - // networkType changed without a state change, which means we - // need to roll our own update. delay long enough for - // ConnectivityManager to process. - // TODO: add direct event to ConnectivityService instead of - // relying on this delay. - if (LOGV) Slog.v(TAG, "triggering delayed updateIfaces()"); - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); - } - - mLastPhoneState = state; - mLastPhoneNetworkType = networkType; - } - }; - private void updateIfaces() { synchronized (mStatsLock) { mWakeLock.acquire(); From ad5bfa5be830d4d864e4bef45133dd828e9ae81c Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Sat, 28 Feb 2015 13:12:17 -0500 Subject: [PATCH 0261/1150] Remove unused imports in frameworks/base. Change-Id: I031443de83f93eb57a98863001826671b18f3b17 --- services/core/java/com/android/server/NsdService.java | 1 - .../core/java/com/android/server/net/IpConfigStore.java | 6 ------ .../java/com/android/server/net/NetworkStatsCollection.java | 2 -- 3 files changed, 9 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 39aa972bab..f4c62259e1 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -38,7 +38,6 @@ import java.io.PrintWriter; import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.HashMap; -import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.CountDownLatch; diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index b5a450dc8b..90e26d8488 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -24,25 +24,19 @@ import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; -import android.os.Handler; -import android.os.HandlerThread; -import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import com.android.server.net.DelayedDiskWrite; import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; import java.net.InetAddress; import java.net.Inet4Address; -import java.util.Map; public class IpConfigStore { private static final String TAG = "IpConfigStore"; diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 3ac20f72f9..20f5f97c4b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -22,10 +22,8 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; -import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; From 9ba4d7429b5298b3b8c1facfd5bf9deb946858be Mon Sep 17 00:00:00 2001 From: Wenchao Tong Date: Thu, 26 Feb 2015 18:13:07 -0800 Subject: [PATCH 0262/1150] NetworkStats to support VPN accounting. Create a new method to migrate underlying network traffic from VPN app to other apps. Bug: 19536273 Change-Id: I3434cad361592e26b01225edf8012f7b16afc98f --- core/java/android/net/NetworkStats.java | 160 ++++++++++++++++++++++++ 1 file changed, 160 insertions(+) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 2afe578b6b..0766253e63 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -19,6 +19,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; +import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; @@ -42,6 +43,7 @@ import java.util.Objects; * @hide */ public class NetworkStats implements Parcelable { + private static final String TAG = "NetworkStats"; /** {@link #iface} value when interface details unavailable. */ public static final String IFACE_ALL = null; /** {@link #uid} value when UID details unavailable. */ @@ -783,4 +785,162 @@ public class NetworkStats implements Parcelable { public void foundNonMonotonic( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); } + + /** + * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. + * + * This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may + * change over time. + * + * This method performs adjustments for one active VPN package and one VPN iface at a time. + * + * It is possible for the VPN software to use multiple underlying networks. This method + * only migrates traffic for the primary underlying network. + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIface the primary underlying network iface used by the VPN application + * @return true if it successfully adjusts the accounting for VPN, false otherwise + */ + public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { + Entry tunIfaceTotal = new Entry(); + Entry underlyingIfaceTotal = new Entry(); + + tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); + + // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. + // Negative stats should be avoided. + Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); + if (pool.isEmpty()) { + return true; + } + Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool); + deductTrafficFromVpnApp(tunUid, underlyingIface, moved); + + if (!moved.isEmpty()) { + Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" + + moved); + return false; + } + return true; + } + + /** + * Initializes the data used by the migrateTun() method. + * + * This is the first pass iteration which does the following work: + * (1) Adds up all the traffic through tun0. + * (2) Adds up all the traffic through the tunUid's underlyingIface + * (both foreground and background). + */ + private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry recycle = new Entry(); + for (int i = 0; i < size; i++) { + getValues(i, recycle); + if (recycle.uid == UID_ALL) { + throw new IllegalStateException( + "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); + } + + if (recycle.uid == tunUid && recycle.tag == TAG_NONE + && Objects.equals(underlyingIface, recycle.iface)) { + underlyingIfaceTotal.add(recycle); + } + + if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) { + // Add up all tunIface traffic. + tunIfaceTotal.add(recycle); + } + } + } + + private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry pool = new Entry(); + pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); + pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); + pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); + pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); + pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); + return pool; + } + + private Entry addTrafficToApplications(String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry pool) { + Entry moved = new Entry(); + Entry tmpEntry = new Entry(); + tmpEntry.iface = underlyingIface; + for (int i = 0; i < size; i++) { + if (Objects.equals(iface[i], tunIface)) { + if (tunIfaceTotal.rxBytes > 0) { + tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + } else { + tmpEntry.rxBytes = 0; + } + if (tunIfaceTotal.rxPackets > 0) { + tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + } else { + tmpEntry.rxPackets = 0; + } + if (tunIfaceTotal.txBytes > 0) { + tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + } else { + tmpEntry.txBytes = 0; + } + if (tunIfaceTotal.txPackets > 0) { + tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + } else { + tmpEntry.txPackets = 0; + } + if (tunIfaceTotal.operations > 0) { + tmpEntry.operations = + pool.operations * operations[i] / tunIfaceTotal.operations; + } else { + tmpEntry.operations = 0; + } + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.set = set[i]; + combineValues(tmpEntry); + if (tag[i] == TAG_NONE) { + moved.add(tmpEntry); + } + } + } + return moved; + } + + private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE); + if (idxVpnBackground != -1) { + tunSubtract(idxVpnBackground, this, moved); + } + + int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved); + } + } + + private static void tunSubtract(int i, NetworkStats left, Entry right) { + long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); + left.rxBytes[i] -= rxBytes; + right.rxBytes -= rxBytes; + + long rxPackets = Math.min(left.rxPackets[i], right.rxPackets); + left.rxPackets[i] -= rxPackets; + right.rxPackets -= rxPackets; + + long txBytes = Math.min(left.txBytes[i], right.txBytes); + left.txBytes[i] -= txBytes; + right.txBytes -= txBytes; + + long txPackets = Math.min(left.txPackets[i], right.txPackets); + left.txPackets[i] -= txPackets; + right.txPackets -= txPackets; + } } From fccef1da81ed92371e4fb6d486d6fbe6724975ef Mon Sep 17 00:00:00 2001 From: Wenchao Tong Date: Wed, 4 Mar 2015 13:26:38 -0800 Subject: [PATCH 0263/1150] NetworkStatsService to adjust VPN stats before recording. * Creates a new Parcelable class VpnInfo to hold required parameters for VPN stats adjustments. * ConnectivityService to collect infomation and provide a list of VpnInfo, one for each user. * NetworkStatsService passes the VpnInfo array to NetworkStatsRecorder. * NetworkStatsRecorder calls NetworkStats.migrateTun() to do the math. * Poll NetworkStats when the vpn application calls setUnderlyingNetworks(). Bug: 19536273 Change-Id: I7a4c7726b8243fead10416f7ec6eb5cf95f20183 --- .../com/android/internal/net/VpnInfo.aidl | 19 +++++++++ .../server/net/NetworkStatsRecorder.java | 10 ++++- .../server/net/NetworkStatsService.java | 39 ++++++++----------- 3 files changed, 45 insertions(+), 23 deletions(-) create mode 100644 core/java/com/android/internal/net/VpnInfo.aidl diff --git a/core/java/com/android/internal/net/VpnInfo.aidl b/core/java/com/android/internal/net/VpnInfo.aidl new file mode 100644 index 0000000000..6fc97be409 --- /dev/null +++ b/core/java/com/android/internal/net/VpnInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.net; + +parcelable VpnInfo; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index d5d7667630..649086575c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -31,6 +31,7 @@ import android.util.Log; import android.util.MathUtils; import android.util.Slog; +import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Sets; @@ -163,7 +164,8 @@ public class NetworkStatsRecorder { * snapshot is considered bootstrap, and is not counted as delta. */ public void recordSnapshotLocked(NetworkStats snapshot, - Map ifaceIdent, long currentTimeMillis) { + Map ifaceIdent, VpnInfo[] vpnArray, + long currentTimeMillis) { final HashSet unknownIfaces = Sets.newHashSet(); // skip recording when snapshot missing @@ -182,6 +184,12 @@ public class NetworkStatsRecorder { final long end = currentTimeMillis; final long start = end - delta.getElapsedRealtime(); + if (vpnArray != null) { + for (VpnInfo info : vpnArray) { + delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); + } + } + NetworkStats.Entry entry = null; for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 856a07667d..0b596aa119 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -111,6 +111,7 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -855,6 +856,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return ident; } + private void recordSnapshotLocked(long currentTime) throws RemoteException { + // snapshot and record current counters; read UID stats first to + // avoid overcounting dev stats. + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + + VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, null, currentTime); + mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + } + /** * Bootstrap initial stats snapshot, usually during {@link #systemReady()} * so we have baseline values without double-counting. @@ -864,17 +879,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { : System.currentTimeMillis(); try { - // snapshot and record current counters; read UID stats first to - // avoid overcounting dev stats. - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); - final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); - - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); - mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - + recordSnapshotLocked(currentTime); } catch (IllegalStateException e) { Slog.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { @@ -918,17 +923,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { : System.currentTimeMillis(); try { - // snapshot and record current counters; read UID stats first to - // avoid overcounting dev stats. - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); - final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); - - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); - mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); - + recordSnapshotLocked(currentTime); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); return; From b293e46f2cad5e43614acc82da43386e005bace6 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Mon, 23 Feb 2015 17:20:20 +0000 Subject: [PATCH 0264/1150] Data Usage public API Added new API consisting of android.app.usage.NetworkUsageManager and android.app.usage.NetworkUsageStats. Through them data usage on a network interface can be programmatically queried. Both summary and details are available. Bug: 19208876 Change-Id: I0e0c4b37ae23ad1e589d4b0c955b93f28ba4333e --- .../app/usage/NetworkStatsManager.java | 233 +++++++++ .../android/app/usage/NetworkUsageStats.java | 479 ++++++++++++++++++ .../android/net/INetworkStatsService.aidl | 8 + .../android/net/INetworkStatsSession.aidl | 6 + .../server/net/NetworkStatsCollection.java | 51 +- .../server/net/NetworkStatsService.java | 84 ++- 6 files changed, 855 insertions(+), 6 deletions(-) create mode 100644 core/java/android/app/usage/NetworkStatsManager.java create mode 100644 core/java/android/app/usage/NetworkUsageStats.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java new file mode 100644 index 0000000000..af7c053a41 --- /dev/null +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -0,0 +1,233 @@ +/** + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.app.usage; + +import android.app.usage.NetworkUsageStats.Bucket; +import android.content.Context; +import android.net.ConnectivityManager; +import android.net.NetworkIdentity; +import android.net.NetworkTemplate; +import android.os.RemoteException; +import android.os.UserHandle; +import android.util.Log; + +/** + * Provides access to network usage history and statistics. Usage data is collected in + * discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details. + *

+ * Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and + * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except + * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user + * as the client. In addition tethering usage, usage by removed users and apps, and usage by system + * is also included in the results. + *

+ * Summary queries + *

+ * These queries aggregate network usage across the whole interval. Therefore there will be only one + * bucket for a particular key and state combination. In case of the user-wide and device-wide + * summaries a single bucket containing the totalised network usage is returned. + *

+ * History queries + *

+ * These queries do not aggregate over time but do aggregate over state. Therefore there can be + * multiple buckets for a particular key but all Bucket's state is going to be + * {@link NetworkUsageStats.Bucket#STATE_ALL}. + *

+ * NOTE: This API requires the permission + * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and + * will not be granted to third-party apps. However, declaring the permission implies intention to + * use the API and the user of the device can grant permission through the Settings application. + * Profile owner apps are automatically granted permission to query data on the profile they manage + * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get + * access to usage data of the primary user. + */ +public class NetworkStatsManager { + private final static String TAG = "NetworkStatsManager"; + + private final Context mContext; + + /** + * {@hide} + */ + public NetworkStatsManager(Context context) { + mContext = context; + } + /** + * Query network usage statistics summaries. Result is summarised data usage for the whole + * device. Result is a single Bucket aggregated over time, state and uid. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return Bucket object or null if permissions are insufficient or error happened during + * statistics collection. + */ + public Bucket querySummaryForDevice(int networkType, String subscriberId, + long startTime, long endTime) throws SecurityException, RemoteException { + NetworkTemplate template = createTemplate(networkType, subscriberId); + if (template == null) { + return null; + } + + Bucket bucket = null; + NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime); + bucket = stats.getDeviceSummaryForNetwork(startTime, endTime); + + stats.close(); + return bucket; + } + + /** + * Query network usage statistics summaries. Result is summarised data usage for all uids + * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return Bucket object or null if permissions are insufficient or error happened during + * statistics collection. + */ + public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, + long endTime) throws SecurityException, RemoteException { + NetworkTemplate template = createTemplate(networkType, subscriberId); + if (template == null) { + return null; + } + + NetworkUsageStats stats; + stats = new NetworkUsageStats(mContext, template, startTime, endTime); + stats.startSummaryEnumeration(startTime, endTime); + + stats.close(); + return stats.getSummaryAggregate(); + } + + /** + * Query network usage statistics summaries. Result filtered to include only uids belonging to + * calling user. Result is aggregated over time, hence all buckets will have the same start and + * end timestamps. Not aggregated over state or uid. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return Statistics object or null if permissions are insufficient or error happened during + * statistics collection. + */ + public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime, + long endTime) throws SecurityException, RemoteException { + NetworkTemplate template = createTemplate(networkType, subscriberId); + if (template == null) { + return null; + } + + NetworkUsageStats result; + result = new NetworkUsageStats(mContext, template, startTime, endTime); + result.startSummaryEnumeration(startTime, endTime); + + return result; + } + + /** + * Query network usage statistics details. Only usable for uids belonging to calling user. + * Result is aggregated over state but not aggregated over time. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param uid UID of app + * @return Statistics object or null if permissions are insufficient or error happened during + * statistics collection. + */ + public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId, + long startTime, long endTime, int uid) throws SecurityException, RemoteException { + NetworkTemplate template = createTemplate(networkType, subscriberId); + if (template == null) { + return null; + } + + NetworkUsageStats result; + result = new NetworkUsageStats(mContext, template, startTime, endTime); + result.startHistoryEnumeration(uid); + + return result; + } + + /** + * Query network usage statistics details. Result filtered to include only uids belonging to + * calling user. Result is aggregated over state but not aggregated over time or uid. + * + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return Statistics object or null if permissions are insufficient or error happened during + * statistics collection. + */ + public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime, + long endTime) throws SecurityException, RemoteException { + NetworkTemplate template = createTemplate(networkType, subscriberId); + if (template == null) { + return null; + } + NetworkUsageStats result; + result = new NetworkUsageStats(mContext, template, startTime, endTime); + result.startUserUidEnumeration(); + return result; + } + + private static NetworkTemplate createTemplate(int networkType, String subscriberId) { + NetworkTemplate template = null; + switch (networkType) { + case ConnectivityManager.TYPE_MOBILE: { + template = NetworkTemplate.buildTemplateMobileAll(subscriberId); + } break; + case ConnectivityManager.TYPE_WIFI: { + template = NetworkTemplate.buildTemplateWifiWildcard(); + } break; + default: { + Log.w(TAG, "Cannot create template for network type " + networkType + + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) + + "'."); + } + } + return template; + } +} diff --git a/core/java/android/app/usage/NetworkUsageStats.java b/core/java/android/app/usage/NetworkUsageStats.java new file mode 100644 index 0000000000..990d231940 --- /dev/null +++ b/core/java/android/app/usage/NetworkUsageStats.java @@ -0,0 +1,479 @@ +/** + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.app.usage; + +import android.content.Context; +import android.net.INetworkStatsService; +import android.net.INetworkStatsSession; +import android.net.NetworkStats; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.net.TrafficStats; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +import dalvik.system.CloseGuard; + +/** + * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects + * are returned as results to various queries in {@link NetworkStatsManager}. + */ +public final class NetworkUsageStats implements AutoCloseable { + private final static String TAG = "NetworkUsageStats"; + + private final CloseGuard mCloseGuard = CloseGuard.get(); + + /** + * Start timestamp of stats collected + */ + private final long mStartTimeStamp; + + /** + * End timestamp of stats collected + */ + private final long mEndTimeStamp; + + + /** + * Non-null array indicates the query enumerates over uids. + */ + private int[] mUids; + + /** + * Index of the current uid in mUids when doing uid enumeration or a single uid value, + * depending on query type. + */ + private int mUidOrUidIndex; + + /** + * The session while the query requires it, null if all the stats have been collected or close() + * has been called. + */ + private INetworkStatsSession mSession; + private NetworkTemplate mTemplate; + + /** + * Results of a summary query. + */ + private NetworkStats mSummary = null; + + /** + * Results of detail queries. + */ + private NetworkStatsHistory mHistory = null; + + /** + * Where we are in enumerating over the current result. + */ + private int mEnumerationIndex = 0; + + /** + * Recycling entry objects to prevent heap fragmentation. + */ + private NetworkStats.Entry mRecycledSummaryEntry = null; + private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; + + /** @hide */ + NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp, + long endTimestamp) throws RemoteException, SecurityException { + final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + // Open network stats session + mSession = statsService.openSessionForUsageStats(context.getOpPackageName()); + mCloseGuard.open("close"); + mTemplate = template; + mStartTimeStamp = startTimestamp; + mEndTimeStamp = endTimestamp; + } + + @Override + protected void finalize() throws Throwable { + try { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } finally { + super.finalize(); + } + } + + // -------------------------BEGINNING OF PUBLIC API----------------------------------- + + /** + * Buckets are the smallest elements of a query result. As some dimensions of a result may be + * aggregated (e.g. time or state) some values may be equal across all buckets. + */ + public static class Bucket { + /** + * Combined usage across all other states. + */ + public static final int STATE_ALL = -1; + + /** + * Usage not accounted in any other states. + */ + public static final int STATE_DEFAULT = 0x1; + + /** + * Foreground usage. + */ + public static final int STATE_FOREGROUND = 0x2; + + /** + * Special UID value for removed apps. + */ + public static final int UID_REMOVED = -4; + + /** + * Special UID value for data usage by tethering. + */ + public static final int UID_TETHERING = -5; + + private int mUid; + private int mState; + private long mBeginTimeStamp; + private long mEndTimeStamp; + private long mRxBytes; + private long mRxPackets; + private long mTxBytes; + private long mTxPackets; + + private static int convertState(int networkStatsSet) { + switch (networkStatsSet) { + case NetworkStats.SET_ALL : return STATE_ALL; + case NetworkStats.SET_DEFAULT : return STATE_DEFAULT; + case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; + } + return 0; + } + + private static int convertUid(int uid) { + switch (uid) { + case TrafficStats.UID_REMOVED: return UID_REMOVED; + case TrafficStats.UID_TETHERING: return UID_TETHERING; + } + return uid; + } + + public Bucket() { + } + + /** + * Key of the bucket. Usually an app uid or one of the following special values:

+ *

    + *
  • {@link #UID_REMOVED}
  • + *
  • {@link #UID_TETHERING}
  • + *
  • {@link android.os.Process#SYSTEM_UID}
  • + *
+ * @return Bucket key. + */ + public int getUid() { + return mUid; + } + + /** + * Usage state. One of the following values:

+ *

    + *
  • {@link #STATE_ALL}
  • + *
  • {@link #STATE_DEFAULT}
  • + *
  • {@link #STATE_FOREGROUND}
  • + *
+ * @return Usage state. + */ + public int getState() { + return mState; + } + + /** + * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return Start of interval. + */ + public long getStartTimeStamp() { + return mBeginTimeStamp; + } + + /** + * End timestamp of the bucket's time interval. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @return End of interval. + */ + public long getEndTimeStamp() { + return mEndTimeStamp; + } + + /** + * Number of bytes received during the bucket's time interval. Statistics are measured at + * the network layer, so they include both TCP and UDP usage. + * @return Number of bytes. + */ + public long getRxBytes() { + return mRxBytes; + } + + /** + * Number of bytes transmitted during the bucket's time interval. Statistics are measured at + * the network layer, so they include both TCP and UDP usage. + * @return Number of bytes. + */ + public long getTxBytes() { + return mTxBytes; + } + + /** + * Number of packets received during the bucket's time interval. Statistics are measured at + * the network layer, so they include both TCP and UDP usage. + * @return Number of packets. + */ + public long getRxPackets() { + return mRxPackets; + } + + /** + * Number of packets transmitted during the bucket's time interval. Statistics are measured + * at the network layer, so they include both TCP and UDP usage. + * @return Number of packets. + */ + public long getTxPackets() { + return mTxPackets; + } + } + + /** + * Fills the recycled bucket with data of the next bin in the enumeration. + * @param bucketOut Bucket to be filled with data. + * @return true if successfully filled the bucket, false otherwise. + */ + public boolean getNextBucket(Bucket bucketOut) { + if (mSummary != null) { + return getNextSummaryBucket(bucketOut); + } else { + return getNextHistoryBucket(bucketOut); + } + } + + /** + * Check if it is possible to ask for a next bucket in the enumeration. + * @return true if there is at least one more bucket. + */ + public boolean hasNextBucket() { + if (mSummary != null) { + return mEnumerationIndex < mSummary.size(); + } else if (mHistory != null) { + return mEnumerationIndex < mHistory.size() + || hasNextUid(); + } + return false; + } + + /** + * Closes the enumeration. Call this method before this object gets out of scope. + */ + @Override + public void close() { + if (mSession != null) { + try { + mSession.close(); + } catch (RemoteException e) { + Log.w(TAG, e); + // Otherwise, meh + } + } + mSession = null; + if (mCloseGuard != null) { + mCloseGuard.close(); + } + } + + // -------------------------END OF PUBLIC API----------------------------------- + + /** + * Collects device summary results into a Bucket. + * @param startTime + * @param endTime + * @throws RemoteException + */ + Bucket getDeviceSummaryForNetwork(long startTime, long endTime) throws RemoteException { + mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, startTime, endTime); + + // Setting enumeration index beyond end to avoid accidental enumeration over data that does + // not belong to the calling user. + mEnumerationIndex = mSummary.size(); + + return getSummaryAggregate(); + } + + /** + * Collects summary results and sets summary enumeration mode. + * @param startTime + * @param endTime + * @throws RemoteException + */ + void startSummaryEnumeration(long startTime, long endTime) throws RemoteException { + mSummary = mSession.getSummaryForAllUid(mTemplate, startTime, endTime, false); + + mEnumerationIndex = 0; + } + + /** + * Collects history results for uid and resets history enumeration index. + */ + void startHistoryEnumeration(int uid) { + mHistory = null; + try { + mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL, + NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + setSingleUid(uid); + } catch (RemoteException e) { + Log.w(TAG, e); + // Leaving mHistory null + } + mEnumerationIndex = 0; + } + + /** + * Starts uid enumeration for current user. + * @throws RemoteException + */ + void startUserUidEnumeration() throws RemoteException { + setUidEnumeration(mSession.getRelevantUids()); + stepHistory(); + } + + /** + * Steps to next uid in enumeration and collects history for that. + */ + private void stepHistory(){ + if (hasNextUid()) { + stepUid(); + mHistory = null; + try { + mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL, + NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + } catch (RemoteException e) { + Log.w(TAG, e); + // Leaving mHistory null + } + mEnumerationIndex = 0; + } + } + + private void fillBucketFromSummaryEntry(Bucket bucketOut) { + bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); + bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + bucketOut.mBeginTimeStamp = mStartTimeStamp; + bucketOut.mEndTimeStamp = mEndTimeStamp; + bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; + bucketOut.mRxPackets = mRecycledSummaryEntry.rxPackets; + bucketOut.mTxBytes = mRecycledSummaryEntry.txBytes; + bucketOut.mTxPackets = mRecycledSummaryEntry.txPackets; + } + + /** + * Getting the next item in summary enumeration. + * @param bucketOut Next item will be set here. + * @return true if a next item could be set. + */ + private boolean getNextSummaryBucket(Bucket bucketOut) { + if (bucketOut != null && mEnumerationIndex < mSummary.size()) { + mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry); + fillBucketFromSummaryEntry(bucketOut); + return true; + } + return false; + } + + Bucket getSummaryAggregate() { + if (mSummary == null) { + return null; + } + Bucket bucket = new Bucket(); + if (mRecycledSummaryEntry == null) { + mRecycledSummaryEntry = new NetworkStats.Entry(); + } + mSummary.getTotal(mRecycledSummaryEntry); + fillBucketFromSummaryEntry(bucket); + return bucket; + } + /** + * Getting the next item in a history enumeration. + * @param bucketOut Next item will be set here. + * @return true if a next item could be set. + */ + private boolean getNextHistoryBucket(Bucket bucketOut) { + if (bucketOut != null && mHistory != null) { + if (mEnumerationIndex < mHistory.size()) { + mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, + mRecycledHistoryEntry); + bucketOut.mUid = Bucket.convertUid(getUid()); + bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; + bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + + mRecycledHistoryEntry.bucketDuration; + bucketOut.mRxBytes = mRecycledHistoryEntry.rxBytes; + bucketOut.mRxPackets = mRecycledHistoryEntry.rxPackets; + bucketOut.mTxBytes = mRecycledHistoryEntry.txBytes; + bucketOut.mTxPackets = mRecycledHistoryEntry.txPackets; + return true; + } else if (hasNextUid()) { + stepHistory(); + return getNextHistoryBucket(bucketOut); + } + } + return false; + } + + // ------------------ UID LOGIC------------------------ + + private boolean isUidEnumeration() { + return mUids != null; + } + + private boolean hasNextUid() { + return isUidEnumeration() && (mUidOrUidIndex + 1) < mUids.length; + } + + private int getUid() { + // Check if uid enumeration. + if (isUidEnumeration()) { + if (mUidOrUidIndex < 0 || mUidOrUidIndex >= mUids.length) { + throw new IndexOutOfBoundsException( + "Index=" + mUidOrUidIndex + " mUids.length=" + mUids.length); + } + return mUids[mUidOrUidIndex]; + } + // Single uid mode. + return mUidOrUidIndex; + } + + private void setSingleUid(int uid) { + mUidOrUidIndex = uid; + } + + private void setUidEnumeration(int[] uids) { + mUids = uids; + mUidOrUidIndex = -1; + } + + private void stepUid() { + if (mUids != null) { + ++mUidOrUidIndex; + } + } +} diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 2c3881c4f7..6436e42676 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -27,6 +27,14 @@ interface INetworkStatsService { /** Start a statistics query session. */ INetworkStatsSession openSession(); + /** Start a statistics query session. If calling package is profile or device owner then it is + * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If + * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then + * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted + * READ_NETWORK_USAGE_STATS is checked for. + */ + INetworkStatsSession openSessionForUsageStats(String callingPackage); + /** Return network layer usage total for traffic that matches template. */ long getNetworkTotalBytes(in NetworkTemplate template, long start, long end); diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl index 1596fa2b01..7bcb04328b 100644 --- a/core/java/android/net/INetworkStatsSession.aidl +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -23,6 +23,9 @@ import android.net.NetworkTemplate; /** {@hide} */ interface INetworkStatsSession { + /** Return device aggregated network layer usage summary for traffic that matches template. */ + NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end); + /** Return network layer usage summary for traffic that matches template. */ NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return historical network layer stats for traffic that matches template. */ @@ -33,6 +36,9 @@ interface INetworkStatsSession { /** Return historical network layer stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); + /** Return array of uids that have stats and are accessible to the calling user */ + int[] getRelevantUids(); + void close(); } diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 20f5f97c4b..01c66629b9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -22,21 +22,28 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; +import static android.net.TrafficStats.UID_TETHERING; +import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.Binder; +import android.os.UserHandle; import android.util.ArrayMap; import android.util.AtomicFile; +import android.util.IntArray; import libcore.io.IoUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; + import com.google.android.collect.Lists; import com.google.android.collect.Maps; @@ -129,6 +136,23 @@ public class NetworkStatsCollection implements FileRotator.Reader { return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; } + public int[] getRelevantUids() { + final int callerUid = Binder.getCallingUid(); + IntArray uids = new IntArray(); + for (int i = 0; i < mStats.size(); i++) { + final Key key = mStats.keyAt(i); + if (isAccessibleToUser(key.uid, callerUid)) { + int j = uids.binarySearch(key.uid); + + if (j < 0) { + j = ~j; + uids.add(j, key.uid); + } + } + } + return uids.toArray(); + } + /** * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. @@ -144,8 +168,18 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { + final int callerUid = Binder.getCallingUid(); + if (!isAccessibleToUser(uid, callerUid)) { + throw new SecurityException("Network stats history of uid " + uid + + " is forbidden for caller " + callerUid); + } + final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDuration, estimateBuckets(), fields); + mBucketDuration, start == end ? 1 : estimateBuckets(), fields); + + // shortcut when we know stats will be empty + if (start == end) return combined; + for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); final boolean setMatches = set == SET_ALL || key.set == set; @@ -166,15 +200,16 @@ public class NetworkStatsCollection implements FileRotator.Reader { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - NetworkStatsHistory.Entry historyEntry = null; - // shortcut when we know stats will be empty if (start == end) return stats; + final NetworkStats.Entry entry = new NetworkStats.Entry(); + NetworkStatsHistory.Entry historyEntry = null; + + final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident)) { + if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)) { final NetworkStatsHistory value = mStats.valueAt(i); historyEntry = value.getValues(start, end, now, historyEntry); @@ -534,6 +569,12 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + private static boolean isAccessibleToUser(int uid, int callerUid) { + return callerUid == android.os.Process.SYSTEM_UID || + uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING + || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); + } + /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0b596aa119..50e03a2b67 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -62,9 +62,13 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; +import android.Manifest; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.IAlarmManager; import android.app.PendingIntent; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -93,7 +97,9 @@ import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -116,6 +122,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.connectivity.Tethering; import java.io.File; @@ -429,7 +436,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + return openSessionForUsageStats(null); + } + + @Override + public INetworkStatsSession openSessionForUsageStats(final String callingPackage) { assertBandwidthControlEnabled(); // return an IBinder which holds strong references to any loaded stats @@ -438,6 +449,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new INetworkStatsSession.Stub() { private NetworkStatsCollection mUidComplete; private NetworkStatsCollection mUidTagComplete; + private String mCallingPackage = callingPackage; private NetworkStatsCollection getUidComplete() { synchronized (mStatsLock) { @@ -457,9 +469,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public int[] getRelevantUids() { + enforcePermissionForManagedAdmin(mCallingPackage); + return getUidComplete().getRelevantUids(); + } + + @Override + public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, + long end) { + enforcePermission(mCallingPackage); + NetworkStats result = new NetworkStats(end - start, 1); + final long ident = Binder.clearCallingIdentity(); + try { + result.combineAllValues(internalGetSummaryForNetwork(template, start, end)); + } finally { + Binder.restoreCallingIdentity(ident); + } + return result; + } + @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { + enforcePermission(mCallingPackage); return internalGetSummaryForNetwork(template, start, end); } @@ -471,6 +504,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { + enforcePermissionForManagedAdmin(mCallingPackage); final NetworkStats stats = getUidComplete().getSummary(template, start, end); if (includeTags) { final NetworkStats tagStats = getUidTagComplete() @@ -483,6 +517,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { + enforcePermissionForManagedAdmin(mCallingPackage); if (tag == TAG_NONE) { return getUidComplete().getHistory(template, uid, set, tag, fields); } else { @@ -498,6 +533,53 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; } + private boolean hasAppOpsPermission(String callingPackage) { + final int callingUid = Binder.getCallingUid(); + boolean appOpsAllow = false; + if (callingPackage != null) { + AppOpsManager appOps = (AppOpsManager) mContext.getSystemService( + Context.APP_OPS_SERVICE); + + final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + callingUid, callingPackage); + if (mode == AppOpsManager.MODE_DEFAULT) { + // The default behavior here is to check if PackageManager has given the app + // permission. + final int permissionCheck = mContext.checkCallingPermission( + Manifest.permission.PACKAGE_USAGE_STATS); + appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED; + } + appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED); + } + return appOpsAllow; + } + + private void enforcePermissionForManagedAdmin(String callingPackage) { + boolean hasPermission = hasAppOpsPermission(callingPackage); + if (!hasPermission) { + // Profile and device owners are exempt from permission checking. + final int callingUid = Binder.getCallingUid(); + final DevicePolicyManagerInternal dpmi = LocalServices.getService( + DevicePolicyManagerInternal.class); + if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) + || dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) { + return; + } + } + if (!hasPermission) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + } + } + + private void enforcePermission(String callingPackage) { + boolean appOpsAllow = hasAppOpsPermission(callingPackage); + if (!appOpsAllow) { + mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + } + } + + /** * Return network summary, splicing between DEV and XT stats when * appropriate. From efd57ecab8053d03d0c5103eade5dc1c0564e57c Mon Sep 17 00:00:00 2001 From: Wenchao Tong Date: Tue, 17 Mar 2015 16:14:23 -0700 Subject: [PATCH 0265/1150] Keep debug information in NetworkStats files Create two special SETs. SET_DBG_VPN_IN is used by individual applications to know how much traffic of the NetworkIdentity was actually moved from a VPN app. SET_DBG_VPN_OUT is used by the VPN app to know how much traffic of the NetworkIdentity was deducted. A debug application can restore the raw stats by these entries. raw_traffic = recorded_entry (TAG_NONE, SET_ALL) + recorded_entry (TAG_NONE, SET_DBF_VPN_OUT) - recorded_entry (TAG_NONE, SET_DBF_VPN_IN) The two debug SETs are not returned by NetworkStatsService.openSession(). These debug entries are retrieved by NetworkStatsCollection.dump(). Bug: 19536273 Change-Id: I03ef9f7667f5f2f48cbe3f6b11447fe7ead8ad3b --- core/java/android/net/NetworkStats.java | 41 ++++++++++++++++++- .../server/net/NetworkStatsCollection.java | 7 ++-- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0766253e63..77d7e0cd76 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -50,12 +50,19 @@ public class NetworkStats implements Parcelable { public static final int UID_ALL = -1; /** {@link #tag} value matching any tag. */ public static final int TAG_ALL = -1; - /** {@link #set} value when all sets combined. */ + /** {@link #set} value when all sets combined, not including debug sets. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; /** {@link #set} value where foreground data is accounted. */ public static final int SET_FOREGROUND = 1; + /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */ + public static final int SET_DEBUG_START = 1000; + /** Debug {@link #set} value when the VPN stats are moved in. */ + public static final int SET_DBG_VPN_IN = 1001; + /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ + public static final int SET_DBG_VPN_OUT = 1002; + /** {@link #tag} value for total data across all tags. */ public static final int TAG_NONE = 0; @@ -729,6 +736,10 @@ public class NetworkStats implements Parcelable { return "DEFAULT"; case SET_FOREGROUND: return "FOREGROUND"; + case SET_DBG_VPN_IN: + return "DBG_VPN_IN"; + case SET_DBG_VPN_OUT: + return "DBG_VPN_OUT"; default: return "UNKNOWN"; } @@ -745,11 +756,26 @@ public class NetworkStats implements Parcelable { return "def"; case SET_FOREGROUND: return "fg"; + case SET_DBG_VPN_IN: + return "vpnin"; + case SET_DBG_VPN_OUT: + return "vpnout"; default: return "unk"; } } + /** + * @return true if the querySet matches the dataSet. + */ + public static boolean setMatches(int querySet, int dataSet) { + if (querySet == dataSet) { + return true; + } + // SET_ALL matches all non-debugging sets. + return querySet == SET_ALL && dataSet < SET_DEBUG_START; + } + /** * Return text description of {@link #tag} value. */ @@ -843,6 +869,9 @@ public class NetworkStats implements Parcelable { if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); + } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + throw new IllegalStateException( + "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } if (recycle.uid == tunUid && recycle.tag == TAG_NONE @@ -906,6 +935,9 @@ public class NetworkStats implements Parcelable { combineValues(tmpEntry); if (tag[i] == TAG_NONE) { moved.add(tmpEntry); + // Add debug info + tmpEntry.set = SET_DBG_VPN_IN; + combineValues(tmpEntry); } } } @@ -913,6 +945,13 @@ public class NetworkStats implements Parcelable { } private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { + // Add debug info + moved.uid = tunUid; + moved.set = SET_DBG_VPN_OUT; + moved.tag = TAG_NONE; + moved.iface = underlyingIface; + combineValues(moved); + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 01c66629b9..a415a84b45 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -182,8 +182,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - final boolean setMatches = set == SET_ALL || key.set == set; - if (key.uid == uid && setMatches && key.tag == tag + if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag && templateMatches(template, key.ident)) { final NetworkStatsHistory value = mStats.valueAt(i); combined.recordHistory(value, start, end); @@ -209,7 +208,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid)) { + if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid) + && key.set < NetworkStats.SET_DEBUG_START) { final NetworkStatsHistory value = mStats.valueAt(i); historyEntry = value.getValues(start, end, now, historyEntry); @@ -542,6 +542,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStatsHistory value = mStats.valueAt(i); if (!templateMatches(groupTemplate, key.ident)) continue; + if (key.set >= NetworkStats.SET_DEBUG_START) continue; final Key groupKey = new Key(null, key.uid, key.set, key.tag); NetworkStatsHistory groupHistory = grouped.get(groupKey); From 6f2ba5ec4389e75aefc342d544963722b2762ee0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 18 Mar 2015 11:27:19 -0700 Subject: [PATCH 0266/1150] Progress towards dynamic storage support. Storage devices are no longer hard-coded, and instead bubble up from whatever Disk and VolumeBase that vold uncovered, turning into sibling Java objects in MountService. We now treat vold events as the source-of-truth for state, and synchronize our state by asking vold to "reset" whenever we reconnect. We've now moved to a model where all storage devices are mounted in the root mount namespace (user boundaries protected with GIDs), so we no longer need app-to-vold path translation. This also means that zygote only needs to bind mount the user-specific /mnt/user/n/ path onto /storage/self/ to make legacy paths like /sdcard work. This grealy simplifies a lot of system code. Many parts of the platform depend on a primary storage device always being present, so we hack together a stub StorageVolume when vold doesn't have a volume ready yet. StorageVolume isn't really a volume anymore; it's the user-specific view onto a volume, so MountService now filters and builds them based on the calling user. StorageVolume is now immutable, making it easier to reason about. Environment now builds all of its paths dynamically based on active volumes. Adds utility methods to turn int types and flags into user-readable strings for debugging purposes. Remove UMS sharing support for now, since no current devices support it; MTP is the recommended solution going forward because it offers better multi-user support. Simplify unmount logic, since vold will now gladly trigger EJECTING broadcast and kill stubborn processes. Bug: 19993667 Change-Id: I9842280e61974c91bae15d764e386969aedcd338 --- core/java/android/net/TrafficStats.java | 2 ++ .../com/android/server/NativeDaemonConnector.java | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 3f1851901f..ff3de2b6b4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -51,6 +51,8 @@ public class TrafficStats { public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; /** @hide */ public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; + /** @hide */ + public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; /** * Special UID value used when collecting {@link NetworkStatsHistory} for diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index d2dfc7bbdc..78c7f385a1 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -48,8 +48,6 @@ import java.util.LinkedList; * {@code libsysutils} FrameworkListener protocol. */ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { - private static final boolean LOGD = false; - private final static boolean VDBG = false; private final String TAG; @@ -58,6 +56,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private OutputStream mOutputStream; private LocalLog mLocalLog; + private volatile boolean mDebug = false; + private final ResponseQueue mResponseQueue; private final PowerManager.WakeLock mWakeLock; @@ -99,6 +99,14 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mLocalLog = new LocalLog(maxLogSize); } + /** + * Enable Set debugging mode, which causes messages to also be written to both + * {@link Slog} in addition to internal log. + */ + public void setDebug(boolean debug) { + mDebug = debug; + } + @Override public void run() { mCallbackHandler = new Handler(mLooper, this); @@ -513,7 +521,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } private void log(String logstring) { - if (LOGD) Slog.d(TAG, logstring); + if (mDebug) Slog.d(TAG, logstring); mLocalLog.log(logstring); } From fec3d1ff1ce71b80b9009e8c69ecd2c5b6db0300 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Tue, 31 Mar 2015 18:09:20 +0100 Subject: [PATCH 0267/1150] Data usage API: any uid is accessible to system apps running in any user This CL mostly affects Settings app as it can run in a user different than UserHandle.OWNER. Since it is a system app it should have access to all uid's data usage, regardless of which user it is currently running in. Bug: 19967498 Change-Id: I4a7787134d998457f7e2a1029183d44d9584083e --- .../java/com/android/server/net/NetworkStatsCollection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index a415a84b45..15b68c7399 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -571,7 +571,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { } private static boolean isAccessibleToUser(int uid, int callerUid) { - return callerUid == android.os.Process.SYSTEM_UID || + return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID || uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); } From 23b9a0d58d9878953fc03e80a6acf259642fd849 Mon Sep 17 00:00:00 2001 From: Jan Nordqvist Date: Thu, 23 Apr 2015 15:42:55 -0700 Subject: [PATCH 0268/1150] Added parameter to avoid having a stream opened, and with that, file truncated on no-op. Change-Id: I5813e4fd269c639a437e17f2554efa4db735a8ba --- .../com/android/server/net/DelayedDiskWrite.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/DelayedDiskWrite.java b/services/core/java/com/android/server/net/DelayedDiskWrite.java index 6ed277de1e..8f09eb7c19 100644 --- a/services/core/java/com/android/server/net/DelayedDiskWrite.java +++ b/services/core/java/com/android/server/net/DelayedDiskWrite.java @@ -38,6 +38,10 @@ public class DelayedDiskWrite { } public void write(final String filePath, final Writer w) { + write(filePath, w, true); + } + + public void write(final String filePath, final Writer w, final boolean open) { if (TextUtils.isEmpty(filePath)) { throw new IllegalArgumentException("empty file path"); } @@ -54,16 +58,18 @@ public class DelayedDiskWrite { mDiskWriteHandler.post(new Runnable() { @Override public void run() { - doWrite(filePath, w); + doWrite(filePath, w, open); } }); } - private void doWrite(String filePath, Writer w) { + private void doWrite(String filePath, Writer w, boolean open) { DataOutputStream out = null; try { - out = new DataOutputStream(new BufferedOutputStream( + if (open) { + out = new DataOutputStream(new BufferedOutputStream( new FileOutputStream(filePath))); + } w.onWriteCalled(out); } catch (IOException e) { loge("Error writing data file " + filePath); From 3a0699a15360073b839ac8bddae1296bd8ed8733 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Thu, 30 Apr 2015 10:38:24 +0100 Subject: [PATCH 0269/1150] Fix potential NPE on devices without DPMS Bug: 20563108 Change-Id: Ie2bda65c834ddad9db8753f7616c2754072551cd --- .../java/com/android/server/net/NetworkStatsService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 50e03a2b67..0035d01b66 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -561,9 +561,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int callingUid = Binder.getCallingUid(); final DevicePolicyManagerInternal dpmi = LocalServices.getService( DevicePolicyManagerInternal.class); - if (dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) - || dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_DEVICE_OWNER)) { + + // Device owners are also profile owners so it is enough to check for that. + if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) { return; } } From 43a69f7a67fcf2b778a6ab6d535128c58f0dbc3f Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Wed, 13 May 2015 17:53:17 +0100 Subject: [PATCH 0270/1150] Rename NetworkUsageStats -> NetworkStats Also making other changes to Data Usage API as requested by API review. Bug: 20823478 Change-Id: Id766c5a725c856da9d8883d73ae788fc1472440a --- ...tworkUsageStats.java => NetworkStats.java} | 35 +++++++----- .../app/usage/NetworkStatsManager.java | 56 ++++++++++++------- 2 files changed, 56 insertions(+), 35 deletions(-) rename core/java/android/app/usage/{NetworkUsageStats.java => NetworkStats.java} (92%) diff --git a/core/java/android/app/usage/NetworkUsageStats.java b/core/java/android/app/usage/NetworkStats.java similarity index 92% rename from core/java/android/app/usage/NetworkUsageStats.java rename to core/java/android/app/usage/NetworkStats.java index 990d231940..5193563413 100644 --- a/core/java/android/app/usage/NetworkUsageStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -19,7 +19,6 @@ package android.app.usage; import android.content.Context; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; -import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; @@ -33,7 +32,7 @@ import dalvik.system.CloseGuard; * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects * are returned as results to various queries in {@link NetworkStatsManager}. */ -public final class NetworkUsageStats implements AutoCloseable { +public final class NetworkStats implements AutoCloseable { private final static String TAG = "NetworkUsageStats"; private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -70,7 +69,7 @@ public final class NetworkUsageStats implements AutoCloseable { /** * Results of a summary query. */ - private NetworkStats mSummary = null; + private android.net.NetworkStats mSummary = null; /** * Results of detail queries. @@ -85,11 +84,11 @@ public final class NetworkUsageStats implements AutoCloseable { /** * Recycling entry objects to prevent heap fragmentation. */ - private NetworkStats.Entry mRecycledSummaryEntry = null; + private android.net.NetworkStats.Entry mRecycledSummaryEntry = null; private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; /** @hide */ - NetworkUsageStats(Context context, NetworkTemplate template, long startTimestamp, + NetworkStats(Context context, NetworkTemplate template, long startTimestamp, long endTimestamp) throws RemoteException, SecurityException { final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); @@ -135,15 +134,20 @@ public final class NetworkUsageStats implements AutoCloseable { */ public static final int STATE_FOREGROUND = 0x2; + /** + * Special UID value for aggregate/unspecified. + */ + public static final int UID_ALL = android.net.NetworkStats.UID_ALL; + /** * Special UID value for removed apps. */ - public static final int UID_REMOVED = -4; + public static final int UID_REMOVED = TrafficStats.UID_REMOVED; /** * Special UID value for data usage by tethering. */ - public static final int UID_TETHERING = -5; + public static final int UID_TETHERING = TrafficStats.UID_TETHERING; private int mUid; private int mState; @@ -156,9 +160,9 @@ public final class NetworkUsageStats implements AutoCloseable { private static int convertState(int networkStatsSet) { switch (networkStatsSet) { - case NetworkStats.SET_ALL : return STATE_ALL; - case NetworkStats.SET_DEFAULT : return STATE_DEFAULT; - case NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; + case android.net.NetworkStats.SET_ALL : return STATE_ALL; + case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; + case android.net.NetworkStats.SET_FOREGROUND : return STATE_FOREGROUND; } return 0; } @@ -337,8 +341,8 @@ public final class NetworkUsageStats implements AutoCloseable { void startHistoryEnumeration(int uid) { mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, uid, NetworkStats.SET_ALL, - NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + mHistory = mSession.getHistoryForUid(mTemplate, uid, android.net.NetworkStats.SET_ALL, + android.net.NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); setSingleUid(uid); } catch (RemoteException e) { Log.w(TAG, e); @@ -364,8 +368,9 @@ public final class NetworkUsageStats implements AutoCloseable { stepUid(); mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, getUid(), NetworkStats.SET_ALL, - NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + mHistory = mSession.getHistoryForUid(mTemplate, getUid(), + android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, + NetworkStatsHistory.FIELD_ALL); } catch (RemoteException e) { Log.w(TAG, e); // Leaving mHistory null @@ -405,7 +410,7 @@ public final class NetworkUsageStats implements AutoCloseable { } Bucket bucket = new Bucket(); if (mRecycledSummaryEntry == null) { - mRecycledSummaryEntry = new NetworkStats.Entry(); + mRecycledSummaryEntry = new android.net.NetworkStats.Entry(); } mSummary.getTotal(mRecycledSummaryEntry); fillBucketFromSummaryEntry(bucket); diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index af7c053a41..2ae018175e 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,18 +16,17 @@ package android.app.usage; -import android.app.usage.NetworkUsageStats.Bucket; +import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.os.RemoteException; -import android.os.UserHandle; import android.util.Log; /** * Provides access to network usage history and statistics. Usage data is collected in - * discrete bins of time called 'Buckets'. See {@link NetworkUsageStats.Bucket} for details. + * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. *

* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except @@ -37,15 +36,20 @@ import android.util.Log; *

* Summary queries *

+ * {@link #querySummaryForDevice}

+ * {@link #querySummaryForUser}

+ * {@link #querySummary}

* These queries aggregate network usage across the whole interval. Therefore there will be only one * bucket for a particular key and state combination. In case of the user-wide and device-wide * summaries a single bucket containing the totalised network usage is returned. *

* History queries *

+ * {@link #queryDetailsForUid}

+ * {@link #queryDetails}

* These queries do not aggregate over time but do aggregate over state. Therefore there can be * multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkUsageStats.Bucket#STATE_ALL}. + * {@link NetworkStats.Bucket#STATE_ALL}. *

* NOTE: This API requires the permission * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and @@ -68,7 +72,10 @@ public class NetworkStatsManager { } /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state and uid. + * device. Result is a single Bucket aggregated over time, state and uid. This means the + * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime' + * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -89,7 +96,7 @@ public class NetworkStatsManager { } Bucket bucket = null; - NetworkUsageStats stats = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime); bucket = stats.getDeviceSummaryForNetwork(startTime, endTime); stats.close(); @@ -99,6 +106,9 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. + * This means the bucket's start and end timestamp are going to be the same as the 'startTime' + * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -118,8 +128,8 @@ public class NetworkStatsManager { return null; } - NetworkUsageStats stats; - stats = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats stats; + stats = new NetworkStats(mContext, template, startTime, endTime); stats.startSummaryEnumeration(startTime, endTime); stats.close(); @@ -129,7 +139,9 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. + * end timestamps. Not aggregated over state or uid. This means buckets' start and end + * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and + * uid are going to vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -142,15 +154,15 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats querySummary(int networkType, String subscriberId, long startTime, + public NetworkStats querySummary(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startSummaryEnumeration(startTime, endTime); return result; @@ -158,7 +170,9 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Only usable for uids belonging to calling user. - * Result is aggregated over state but not aggregated over time. + * Result is aggregated over state but not aggregated over time. This means buckets' start and + * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going + * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -172,15 +186,15 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats queryDetailsForUid(int networkType, String subscriberId, + public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startHistoryEnumeration(uid); return result; @@ -188,7 +202,9 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. + * calling user. Result is aggregated over state but not aggregated over time or uid. This means + * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' + * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -201,14 +217,14 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkUsageStats queryDetails(int networkType, String subscriberId, long startTime, + public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; } - NetworkUsageStats result; - result = new NetworkUsageStats(mContext, template, startTime, endTime); + NetworkStats result; + result = new NetworkStats(mContext, template, startTime, endTime); result.startUserUidEnumeration(); return result; } From 567b6f86e7308b470ad89e2e1290a0ec53375b80 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Thu, 4 Jun 2015 14:07:55 +0100 Subject: [PATCH 0271/1150] Replace renamed reference to NetworkStats in javadoc Bug: 21572680 Change-Id: Iad43af4d8a6d178f3396f23a74f1568e6faed311 --- core/java/android/app/usage/NetworkStats.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 5193563413..1079f1ab8f 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -29,11 +29,11 @@ import android.util.Log; import dalvik.system.CloseGuard; /** - * Class providing enumeration over buckets of network usage statistics. NetworkUsageStats objects + * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects * are returned as results to various queries in {@link NetworkStatsManager}. */ public final class NetworkStats implements AutoCloseable { - private final static String TAG = "NetworkUsageStats"; + private final static String TAG = "NetworkStats"; private final CloseGuard mCloseGuard = CloseGuard.get(); From 8806907cc94132cf50e8383067b5735b7d354714 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 15 Jun 2015 21:09:10 -0700 Subject: [PATCH 0272/1150] Update file size formatting. Per UX, default strings should have space between value and units resulting in "12.3 GB". Add a formatting variant that returns the various components for callers who want to build their own strings. For now there is only one mounted emulated volume at a time, and it's always the primary storage, so give it the default rootId to keep old Uris working. Change-Id: Ifcc72a91a6b397ee65dc92642153286186eb64ac --- core/java/android/net/TrafficStats.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ff3de2b6b4..bb08be2e3b 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -53,6 +53,8 @@ public class TrafficStats { public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; /** @hide */ public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; + /** @hide */ + public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; /** * Special UID value used when collecting {@link NetworkStatsHistory} for From fd6ca6c8d4043855c6b066fea792c289c459971e Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Tue, 23 Jun 2015 13:35:28 -0700 Subject: [PATCH 0273/1150] Handle volume benchmark timeout If a volume benchmark operation times out, we don't want to show a cryptic toast message. Instead, we return a very large integer [eg Long.MAX_INT]. The storage wizard can then use this value to show an appropriate dialog if it chooses. Bug: 21376364 Change-Id: I3d97336e19c93511cfff2cbdb2f07ab033a1143d --- .../android/server/NativeDaemonConnector.java | 2 +- .../server/NativeDaemonTimeoutException.java | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 services/core/java/com/android/server/NativeDaemonTimeoutException.java diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 78c7f385a1..e7979e4310 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -421,7 +421,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo event = mResponseQueue.remove(sequenceNumber, timeout, logCmd); if (event == null) { loge("timed-out waiting for response to " + logCmd); - throw new NativeDaemonFailureException(logCmd, event); + throw new NativeDaemonTimeoutException(logCmd, event); } if (VDBG) log("RMV <- {" + event + "}"); events.add(event); diff --git a/services/core/java/com/android/server/NativeDaemonTimeoutException.java b/services/core/java/com/android/server/NativeDaemonTimeoutException.java new file mode 100644 index 0000000000..658f7d6264 --- /dev/null +++ b/services/core/java/com/android/server/NativeDaemonTimeoutException.java @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +/** + * An exception that indicates there was a timeout with a + * {@link NativeDaemonConnector} operation. + */ +public class NativeDaemonTimeoutException extends NativeDaemonConnectorException { + public NativeDaemonTimeoutException(String command, NativeDaemonEvent event) { + super(command, event); + } +} + From f34946fabb6c4fbc76c8a8d16685df31a8ecd0e9 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Tue, 16 Jun 2015 15:49:16 +0100 Subject: [PATCH 0274/1150] Expose time-interval detail query on INetworkStatsSession Also, force polling when a session is opened for NetworkStatsManager. Bug: 21864554 Bug: 21754685 Change-Id: I24ea822c2d5bc1421ec7ee65d0cfe27cf02dd69e --- core/java/android/app/usage/NetworkStats.java | 21 ++++++-------- .../app/usage/NetworkStatsManager.java | 16 +++++++---- .../android/net/INetworkStatsSession.aidl | 2 ++ .../server/net/NetworkStatsService.java | 28 ++++++++++++++++++- 4 files changed, 49 insertions(+), 18 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 1079f1ab8f..9d5eabbc07 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -309,12 +309,10 @@ public final class NetworkStats implements AutoCloseable { /** * Collects device summary results into a Bucket. - * @param startTime - * @param endTime * @throws RemoteException */ - Bucket getDeviceSummaryForNetwork(long startTime, long endTime) throws RemoteException { - mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, startTime, endTime); + Bucket getDeviceSummaryForNetwork() throws RemoteException { + mSummary = mSession.getDeviceSummaryForNetwork(mTemplate, mStartTimeStamp, mEndTimeStamp); // Setting enumeration index beyond end to avoid accidental enumeration over data that does // not belong to the calling user. @@ -325,12 +323,10 @@ public final class NetworkStats implements AutoCloseable { /** * Collects summary results and sets summary enumeration mode. - * @param startTime - * @param endTime * @throws RemoteException */ - void startSummaryEnumeration(long startTime, long endTime) throws RemoteException { - mSummary = mSession.getSummaryForAllUid(mTemplate, startTime, endTime, false); + void startSummaryEnumeration() throws RemoteException { + mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, false); mEnumerationIndex = 0; } @@ -341,8 +337,9 @@ public final class NetworkStats implements AutoCloseable { void startHistoryEnumeration(int uid) { mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, uid, android.net.NetworkStats.SET_ALL, - android.net.NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL); + mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, + android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, + NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); setSingleUid(uid); } catch (RemoteException e) { Log.w(TAG, e); @@ -368,9 +365,9 @@ public final class NetworkStats implements AutoCloseable { stepUid(); mHistory = null; try { - mHistory = mSession.getHistoryForUid(mTemplate, getUid(), + mHistory = mSession.getHistoryIntervalForUid(mTemplate, getUid(), android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, - NetworkStatsHistory.FIELD_ALL); + NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); } catch (RemoteException e) { Log.w(TAG, e); // Leaving mHistory null diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 2ae018175e..2886cda9d2 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -97,7 +97,7 @@ public class NetworkStatsManager { Bucket bucket = null; NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime); - bucket = stats.getDeviceSummaryForNetwork(startTime, endTime); + bucket = stats.getDeviceSummaryForNetwork(); stats.close(); return bucket; @@ -106,7 +106,7 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. - * This means the bucket's start and end timestamp are going to be the same as the 'startTime' + * This means the bucket's start and end timestamp are going to be the same as the 'startTime' * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid * {@link NetworkStats.Bucket#UID_ALL}. * @@ -130,7 +130,7 @@ public class NetworkStatsManager { NetworkStats stats; stats = new NetworkStats(mContext, template, startTime, endTime); - stats.startSummaryEnumeration(startTime, endTime); + stats.startSummaryEnumeration(); stats.close(); return stats.getSummaryAggregate(); @@ -140,7 +140,7 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and + * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and * uid are going to vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -163,7 +163,7 @@ public class NetworkStatsManager { NetworkStats result; result = new NetworkStats(mContext, template, startTime, endTime); - result.startSummaryEnumeration(startTime, endTime); + result.startSummaryEnumeration(); return result; } @@ -173,6 +173,9 @@ public class NetworkStatsManager { * Result is aggregated over state but not aggregated over time. This means buckets' start and * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. + *

Only includes buckets that atomically occur in the inclusive time range. Doesn't + * interpolate across partial buckets. Since bucket length is in the order of hours, this + * method cannot be used to measure data usage on a fine grained time scale. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -205,6 +208,9 @@ public class NetworkStatsManager { * calling user. Result is aggregated over state but not aggregated over time or uid. This means * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary. + *

Only includes buckets that atomically occur in the inclusive time range. Doesn't + * interpolate across partial buckets. Since bucket length is in the order of hours, this + * method cannot be used to measure data usage on a fine grained time scale. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl index 7bcb04328b..5229a3b3b9 100644 --- a/core/java/android/net/INetworkStatsSession.aidl +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -35,6 +35,8 @@ interface INetworkStatsSession { NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); /** Return historical network layer stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); + /** Return historical network layer stats for specific UID traffic that matches template. */ + NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end); /** Return array of uids that have stats and are accessible to the calling user */ int[] getRelevantUids(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0035d01b66..844934846f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -436,13 +436,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { - return openSessionForUsageStats(null); + return createSession(null, /* poll on create */ false); } @Override public INetworkStatsSession openSessionForUsageStats(final String callingPackage) { + return createSession(callingPackage, /* poll on create */ true); + } + + private INetworkStatsSession createSession(final String callingPackage, boolean pollOnCreate) { assertBandwidthControlEnabled(); + if (pollOnCreate) { + final long ident = Binder.clearCallingIdentity(); + try { + performPoll(FLAG_PERSIST_ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + // return an IBinder which holds strong references to any loaded stats // for its lifetime; when caller closes only weak references remain. @@ -525,6 +538,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public NetworkStatsHistory getHistoryIntervalForUid( + NetworkTemplate template, int uid, int set, int tag, int fields, + long start, long end) { + enforcePermissionForManagedAdmin(mCallingPackage); + if (tag == TAG_NONE) { + return getUidComplete().getHistory(template, uid, set, tag, fields, start, end); + } else { + return getUidTagComplete().getHistory(template, uid, set, tag, fields, + start, end); + } + } + @Override public void close() { mUidComplete = null; From 6928e332da27f7a6e8a33bb2969b54ffd88b8449 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 8 Jul 2015 14:06:37 -0700 Subject: [PATCH 0275/1150] Kill MediaProvider during drastic changes. Sadly MediaProvider makes a ton of assumptions about storage paths not changing. To ensure that it picks up radical storage changes, kill it and let it restart to pick up new paths. Also give ourselves a longer timeout when benchmarking. Bug: 20275423 Change-Id: I9971c4667dabdc685cb23528443f085f152c461d --- .../android/server/NativeDaemonConnector.java | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index e7979e4310..519a2a3f4f 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -69,7 +69,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private AtomicInteger mSequenceNumber; - private static final int DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ + private static final long DEFAULT_TIMEOUT = 1 * 60 * 1000; /* 1 minute */ private static final long WARN_EXECUTE_DELAY_MS = 500; /* .5 sec */ /** Lock held whenever communicating with native daemon. */ @@ -337,7 +337,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent execute(String cmd, Object... args) throws NativeDaemonConnectorException { - final NativeDaemonEvent[] events = executeForList(cmd, args); + return execute(DEFAULT_TIMEOUT, cmd, args); + } + + public NativeDaemonEvent execute(long timeoutMs, String cmd, Object... args) + throws NativeDaemonConnectorException { + final NativeDaemonEvent[] events = executeForList(timeoutMs, cmd, args); if (events.length != 1) { throw new NativeDaemonConnectorException( "Expected exactly one response, but received " + events.length); @@ -372,7 +377,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(String cmd, Object... args) throws NativeDaemonConnectorException { - return execute(DEFAULT_TIMEOUT, cmd, args); + return executeForList(DEFAULT_TIMEOUT, cmd, args); } /** @@ -387,7 +392,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * {@link NativeDaemonEvent#isClassClientError()} or * {@link NativeDaemonEvent#isClassServerError()}. */ - public NativeDaemonEvent[] execute(int timeout, String cmd, Object... args) + public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) throws NativeDaemonConnectorException { final long startTime = SystemClock.elapsedRealtime(); @@ -418,7 +423,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo NativeDaemonEvent event = null; do { - event = mResponseQueue.remove(sequenceNumber, timeout, logCmd); + event = mResponseQueue.remove(sequenceNumber, timeoutMs, logCmd); if (event == null) { loge("timed-out waiting for response to " + logCmd); throw new NativeDaemonTimeoutException(logCmd, event); @@ -606,7 +611,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // note that the timeout does not count time in deep sleep. If you don't want // the device to sleep, hold a wakelock - public NativeDaemonEvent remove(int cmdNum, int timeoutMs, String logCmd) { + public NativeDaemonEvent remove(int cmdNum, long timeoutMs, String logCmd) { PendingCmd found = null; synchronized (mPendingCmds) { for (PendingCmd pendingCmd : mPendingCmds) { From 06a45679aafe971d7ab8dbfc4cdd70376d9d7f83 Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Thu, 13 Aug 2015 16:53:10 +0100 Subject: [PATCH 0276/1150] Remove uids with empty history from NetworkStats uid enumeration Bug: 23018174 Change-Id: I1a482280599e0f5da18a208e727653d4bd4107ec --- core/java/android/app/usage/NetworkStats.java | 26 ++++++++++++++----- 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 9d5eabbc07..ef08eb9e89 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -24,6 +24,7 @@ import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.IntArray; import android.util.Log; import dalvik.system.CloseGuard; @@ -353,7 +354,25 @@ public final class NetworkStats implements AutoCloseable { * @throws RemoteException */ void startUserUidEnumeration() throws RemoteException { - setUidEnumeration(mSession.getRelevantUids()); + // TODO: getRelevantUids should be sensitive to time interval. When that's done, + // the filtering logic below can be removed. + int[] uids = mSession.getRelevantUids(); + // Filtering of uids with empty history. + IntArray filteredUids = new IntArray(uids.length); + for (int uid : uids) { + try { + NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid, + android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, + NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); + if (history != null && history.size() > 0) { + filteredUids.add(uid); + } + } catch (RemoteException e) { + Log.w(TAG, "Error while getting history of uid " + uid, e); + } + } + mUids = filteredUids.toArray(); + mUidOrUidIndex = -1; stepHistory(); } @@ -468,11 +487,6 @@ public final class NetworkStats implements AutoCloseable { mUidOrUidIndex = uid; } - private void setUidEnumeration(int[] uids) { - mUids = uids; - mUidOrUidIndex = -1; - } - private void stepUid() { if (mUids != null) { ++mUidOrUidIndex; From aa49801a929f21d6e6e305b875f4108ce4963f25 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Sat, 19 Sep 2015 17:31:01 -0400 Subject: [PATCH 0277/1150] constify JNINativeMethod function pointer tables Change-Id: I4036c924958221cbc644724f8eb01c5de3cd7954 --- core/jni/android_net_TrafficStats.cpp | 2 +- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 7354417435..7b7d0cf498 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -185,7 +185,7 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*) getUidStat}, diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 6c0b756591..70134ab04a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -284,7 +284,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, return 0; } -static JNINativeMethod gMethods[] = { +static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", (void*) readNetworkStatsDetail } From 32933d6da38d8fe82c930ba5d3d4fdc27d3882af Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 19 Oct 2015 16:52:08 -0700 Subject: [PATCH 0278/1150] Ignore network policies with missing IMSI. In rare cases, we might have created a network policy before an IMSI was available. Because this policy is persisted, and we incorrectly think that it always applies, we end up annoying the user when data usage goes over the 2GB default warning threshold. This patch fixes the network matching logic to ignore these empty network policies when present. Bug: 24972775 Change-Id: Id26499b6716121dddf0f2c05b848b0bed5995e72 --- core/java/android/net/NetworkTemplate.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 57eef83431..b7a411e4b6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -288,7 +288,8 @@ public class NetworkTemplate implements Parcelable { } else { final boolean matchesType = (sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); - return matchesType && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + return matchesType && !ArrayUtils.isEmpty(mMatchSubscriberIds) + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } From c109706f45e8b34c2c6a30b419a84c0df6eac362 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 3 Nov 2015 10:39:42 -0800 Subject: [PATCH 0279/1150] Yell if NDC callers are holding bad locks. The current MountService design heavily depends on down-callers not holding any locks, since the vast majority of events are unsolicited and bubble up to the framework. This simple API gives us an easy way to track down people calling while holding a lock they shouldn't be. Bug: 25443096 Change-Id: Ifcbda95f00d5be8c1b88d58ca67927e76c713c3e --- .../com/android/server/NativeDaemonConnector.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 519a2a3f4f..3a6fa0563d 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -25,6 +25,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; import android.util.LocalLog; +import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -57,6 +58,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private LocalLog mLocalLog; private volatile boolean mDebug = false; + private volatile Object mLockWarning; private final ResponseQueue mResponseQueue; @@ -107,6 +109,14 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mDebug = debug; } + /** + * Yell loudly if someone tries making future {@link #execute(Command)} calls while holding a + * lock on the given object. + */ + public void setLockWarning(Object lockWarning) { + mLockWarning = lockWarning; + } + @Override public void run() { mCallbackHandler = new Handler(mLooper, this); @@ -394,6 +404,10 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) throws NativeDaemonConnectorException { + if (mLockWarning != null && Thread.holdsLock(mLockWarning)) { + Log.wtf(TAG, "Calling thread is holding lock " + mLockWarning, new Throwable()); + } + final long startTime = SystemClock.elapsedRealtime(); final ArrayList events = Lists.newArrayList(); From 6d3c359289481f9ba5c0b34dac9cbd111ff248de Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 3 Nov 2015 12:33:54 -0800 Subject: [PATCH 0280/1150] Yell when calling installd with PM lock held. As a matter of policy, we should never be holding the mPackages lock while calling down into installd. This little bit of logic helps us catch accidental cases where this happens. Change-Id: I676c81df43ef936ffd36290d45a79429630c1b4b --- .../android/server/NativeDaemonConnector.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 3a6fa0563d..e6b6074abf 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -25,10 +25,10 @@ import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; import android.util.LocalLog; -import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import com.google.android.collect.Lists; import java.io.FileDescriptor; @@ -58,7 +58,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo private LocalLog mLocalLog; private volatile boolean mDebug = false; - private volatile Object mLockWarning; + private volatile Object mWarnIfHeld; private final ResponseQueue mResponseQueue; @@ -110,11 +110,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } /** - * Yell loudly if someone tries making future {@link #execute(Command)} calls while holding a - * lock on the given object. + * Yell loudly if someone tries making future {@link #execute(Command)} + * calls while holding a lock on the given object. */ - public void setLockWarning(Object lockWarning) { - mLockWarning = lockWarning; + public void setWarnIfHeld(Object warnIfHeld) { + Preconditions.checkState(mWarnIfHeld == null); + mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld); } @Override @@ -404,8 +405,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) throws NativeDaemonConnectorException { - if (mLockWarning != null && Thread.holdsLock(mLockWarning)) { - Log.wtf(TAG, "Calling thread is holding lock " + mLockWarning, new Throwable()); + if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { + Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" + + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); } final long startTime = SystemClock.elapsedRealtime(); From c1c71fdff5fe746a962ed64cda8a89984c6b8b67 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Tue, 10 Nov 2015 10:49:20 -0800 Subject: [PATCH 0281/1150] Introduce socket stats tag for restore traffic As well as system API for emplacing it. Change-Id: If33fbd23552261efe3b00d75c22ff823564f43e6 --- core/java/android/net/TrafficStats.java | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bb08be2e3b..2137c3a30a 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -87,12 +87,21 @@ public class TrafficStats { public static final int TAG_SYSTEM_MEDIA = 0xFFFFFF02; /** - * Default tag value for {@link BackupManager} traffic. + * Default tag value for {@link BackupManager} backup traffic; that is, + * traffic from the device to the storage backend. * * @hide */ public static final int TAG_SYSTEM_BACKUP = 0xFFFFFF03; + /** + * Default tag value for {@link BackupManager} restore traffic; that is, + * app data retrieved from the storage backend at install time. + * + * @hide + */ + public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { @@ -141,6 +150,16 @@ public class TrafficStats { setThreadStatsTag(TAG_SYSTEM_BACKUP); } + /** + * System API for restore-related support components to tag network traffic + * appropriately. + * @hide + */ + @SystemApi + public static void setThreadStatsTagRestore() { + setThreadStatsTag(TAG_SYSTEM_RESTORE); + } + /** * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. From dbccfac26f4e5de134045e5528d3c4b628dea16d Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Thu, 19 Nov 2015 16:58:57 +0900 Subject: [PATCH 0282/1150] Add capability to receive FD with NativeDaemonConnector. BUG=25755372 Change-Id: I2888219b77cf04f4bf749d5518ff62ba16258f2d --- .../com/android/server/NativeDaemonConnector.java | 6 ++++-- .../java/com/android/server/NativeDaemonEvent.java | 13 ++++++++++--- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index e6b6074abf..d6dbad87b0 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -177,6 +177,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbacks.onDaemonConnected(); + FileDescriptor[] fdList = null; byte[] buffer = new byte[BUFFER_SIZE]; int start = 0; @@ -186,6 +187,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo loge("got " + count + " reading with start = " + start); break; } + fdList = socket.getAncillaryFileDescriptors(); // Add our starting point to the count and reset the start. count += start; @@ -200,8 +202,8 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo boolean releaseWl = false; try { - final NativeDaemonEvent event = NativeDaemonEvent.parseRawEvent( - rawEvent); + final NativeDaemonEvent event = + NativeDaemonEvent.parseRawEvent(rawEvent, fdList); log("RCV <- {" + event + "}"); diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/services/core/java/com/android/server/NativeDaemonEvent.java index 4e61c0b09d..e6feda3dad 100644 --- a/services/core/java/com/android/server/NativeDaemonEvent.java +++ b/services/core/java/com/android/server/NativeDaemonEvent.java @@ -19,6 +19,7 @@ package com.android.server; import android.util.Slog; import com.google.android.collect.Lists; +import java.io.FileDescriptor; import java.util.ArrayList; /** @@ -35,15 +36,17 @@ public class NativeDaemonEvent { private final String mRawEvent; private final String mLogMessage; private String[] mParsed; + private FileDescriptor[] mFdList; private NativeDaemonEvent(int cmdNumber, int code, String message, - String rawEvent, String logMessage) { + String rawEvent, String logMessage, FileDescriptor[] fdList) { mCmdNumber = cmdNumber; mCode = code; mMessage = message; mRawEvent = rawEvent; mLogMessage = logMessage; mParsed = null; + mFdList = fdList; } static public final String SENSITIVE_MARKER = "{{sensitive}}"; @@ -60,6 +63,10 @@ public class NativeDaemonEvent { return mMessage; } + public FileDescriptor[] getFileDescriptors() { + return mFdList; + } + @Deprecated public String getRawEvent() { return mRawEvent; @@ -127,7 +134,7 @@ public class NativeDaemonEvent { * @throws IllegalArgumentException when line doesn't match format expected * from native side. */ - public static NativeDaemonEvent parseRawEvent(String rawEvent) { + public static NativeDaemonEvent parseRawEvent(String rawEvent, FileDescriptor[] fdList) { final String[] parsed = rawEvent.split(" "); if (parsed.length < 2) { throw new IllegalArgumentException("Insufficient arguments"); @@ -164,7 +171,7 @@ public class NativeDaemonEvent { final String message = rawEvent.substring(skiplength); - return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage); + return new NativeDaemonEvent(cmdNumber, code, message, rawEvent, logMessage, fdList); } /** From 7b124cb8e6f0ad6de77001f55b4da24b709caa2f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 4 Dec 2015 15:21:52 -0700 Subject: [PATCH 0283/1150] Add tagging variants for DatagramSocket. Oops, we missed these along the way. Bug: 25799174 Change-Id: I4ad368f9faee4b1996d605534dce4c2b23dbe200 --- core/java/android/net/TrafficStats.java | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 2137c3a30a..e82485da32 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -28,6 +28,7 @@ import com.android.server.NetworkManagementSocketTagger; import dalvik.system.SocketTagger; +import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -225,6 +226,27 @@ public class TrafficStats { SocketTagger.get().untag(socket); } + /** + * Tag the given {@link DatagramSocket} with any statistics parameters + * active for the current thread. Subsequent calls always replace any + * existing parameters. When finished, call + * {@link #untagDatagramSocket(DatagramSocket)} to remove statistics + * parameters. + * + * @see #setThreadStatsTag(int) + * @see #setThreadStatsUid(int) + */ + public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { + SocketTagger.get().tag(socket); + } + + /** + * Remove any statistics parameters from the given {@link DatagramSocket}. + */ + public static void untagDatagramSocket(DatagramSocket socket) throws SocketException { + SocketTagger.get().untag(socket); + } + /** * Start profiling data usage for current UID. Only one profiling session * can be active at a time. From 8dc22e3e902fe80db636529d0e18009d846419eb Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Wed, 9 Dec 2015 18:04:50 -0800 Subject: [PATCH 0284/1150] Relax permissions around NetworkStatsManager APIs. Currently, access to network usage history and statistics requires a signature|privileged permission, an AppOps bit (associated with the PACKAGE_USAGE_STATS permission), or device/profile ownership. Once access is granted via one of these mechanisms, it generally applies to any UID running in the same user as the caller. This CL expands access as follows: -Any app can access its own usage history with no extra requirements. -Carrier-privileged applications can access usage history for the entire device. -Device owners can access per-UID breakdowns for usage. Previously they could access the summary for the whole device, but not the individual breakdowns. We simplify the permission model by defining three access levels - DEFAULT (own app only), USER (all apps in the same user), and DEVICE (all apps on the device), and propagate these levels throughout. Finally, this CL fixes an apparent bug in NetworkStatsSerice#hasAppOpsPermissions - if the AppOp bit was in MODE_DEFAULT, hasAppOpsPermission would always return false instead of falling back to the PackageManager permission check. Bug: 25812859 Bug: 25813856 Change-Id: Ic96e0776e2a4215a400163872acea1ededfaced9 --- .../app/usage/NetworkStatsManager.java | 21 ++- .../server/net/NetworkStatsAccess.java | 166 ++++++++++++++++++ .../server/net/NetworkStatsCollection.java | 35 ++-- .../server/net/NetworkStatsRecorder.java | 3 +- .../server/net/NetworkStatsService.java | 112 ++++-------- 5 files changed, 235 insertions(+), 102 deletions(-) create mode 100644 services/core/java/com/android/server/net/NetworkStatsAccess.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 2886cda9d2..0fce7a90ea 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -21,6 +21,7 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkTemplate; +import android.os.Build; import android.os.RemoteException; import android.util.Log; @@ -29,10 +30,9 @@ import android.util.Log; * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. *

* Queries can define a time interval in the form of start and end timestamps (Long.MIN_VALUE and - * Long.MAX_VALUE can be used to simulate open ended intervals). All queries (except - * {@link #querySummaryForDevice}) collect only network usage of apps belonging to the same user - * as the client. In addition tethering usage, usage by removed users and apps, and usage by system - * is also included in the results. + * Long.MAX_VALUE can be used to simulate open ended intervals). By default, apps can only obtain + * data about themselves. See the below note for special cases in which apps can obtain data about + * other applications. *

* Summary queries *

@@ -51,13 +51,20 @@ import android.util.Log; * multiple buckets for a particular key but all Bucket's state is going to be * {@link NetworkStats.Bucket#STATE_ALL}. *

- * NOTE: This API requires the permission + * NOTE: Accessing stats for apps other than the calling app requires the permission * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and * will not be granted to third-party apps. However, declaring the permission implies intention to * use the API and the user of the device can grant permission through the Settings application. * Profile owner apps are automatically granted permission to query data on the profile they manage - * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps likewise get - * access to usage data of the primary user. + * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- + * privileged apps likewise get access to usage data for all users on the device. + *

+ * In addition to tethering usage, usage by removed users and apps, and usage by the system + * is also included in the results for callers with one of these higher levels of access. + *

+ * NOTE: Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required + * the above permission, even to access an app's own data usage, and carrier-privileged apps were + * not included. */ public class NetworkStatsManager { private final static String TAG = "NetworkStatsManager"; diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java new file mode 100644 index 0000000000..53ba7184e0 --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.server.net; + +import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; +import static android.net.TrafficStats.UID_REMOVED; +import static android.net.TrafficStats.UID_TETHERING; + +import android.Manifest; +import android.annotation.IntDef; +import android.app.AppOpsManager; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManagerInternal; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.UserHandle; +import android.telephony.TelephonyManager; + +import com.android.server.LocalServices; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** Utility methods for controlling access to network stats APIs. */ +public final class NetworkStatsAccess { + private NetworkStatsAccess() {} + + /** + * Represents an access level for the network usage history and statistics APIs. + * + *

Access levels are in increasing order; that is, it is reasonable to check access by + * verifying that the caller's access level is at least the minimum required level. + */ + @IntDef({ + Level.DEFAULT, + Level.USER, + Level.DEVICE, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Level { + /** + * Default, unprivileged access level. + * + *

Can only access usage for one's own UID. + * + *

Every app will have at least this access level. + */ + int DEFAULT = 0; + + /** + * Access level for apps which can access usage for any app running in the same user. + * + *

Granted to: + *

    + *
  • Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit + * so it is not necessarily sufficient to declare this in the manifest. + *
  • Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. + *
  • Profile owners. + *
+ */ + int USER = 1; + + /** + * Access level for apps which can access usage for any app on the device, including apps + * running on other users/profiles. + * + *

Granted to: + *

    + *
  • Device owners. + *
  • Carrier-privileged applications. + *
  • The system UID. + *
+ */ + int DEVICE = 2; + } + + /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ + public static @NetworkStatsAccess.Level int checkAccessLevel( + Context context, int callingUid, String callingPackage) { + final DevicePolicyManagerInternal dpmi = LocalServices.getService( + DevicePolicyManagerInternal.class); + final TelephonyManager tm = (TelephonyManager) + context.getSystemService(Context.TELEPHONY_SERVICE); + boolean hasCarrierPrivileges = tm != null && + tm.checkCarrierPrivilegesForPackage(callingPackage) == + TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + if (hasCarrierPrivileges || isDeviceOwner + || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { + // Carrier-privileged apps and device owners, and the system can access data usage for + // all apps on the device. + return NetworkStatsAccess.Level.DEVICE; + } + + boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner + || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) == + PackageManager.PERMISSION_GRANTED) { + // Apps with the AppOps permission, profile owners, and apps with the privileged + // permission can access data usage for all apps in this user/profile. + return NetworkStatsAccess.Level.USER; + } + + // Everyone else gets default access (only to their own UID). + return NetworkStatsAccess.Level.DEFAULT; + } + + /** + * Returns whether the given caller should be able to access the given UID when the caller has + * the given {@link NetworkStatsAccess.Level}. + */ + public static boolean isAccessibleToUser(int uid, int callerUid, + @NetworkStatsAccess.Level int accessLevel) { + switch (accessLevel) { + case NetworkStatsAccess.Level.DEVICE: + // Device-level access - can access usage for any uid. + return true; + case NetworkStatsAccess.Level.USER: + // User-level access - can access usage for any app running in the same user, along + // with some special uids (system, removed, or tethering). + return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED + || uid == UID_TETHERING + || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); + case NetworkStatsAccess.Level.DEFAULT: + default: + // Default access level - can only access one's own usage. + return uid == callerUid; + } + } + + private static boolean hasAppOpsPermission( + Context context, int callingUid, String callingPackage) { + if (callingPackage != null) { + AppOpsManager appOps = (AppOpsManager) context.getSystemService( + Context.APP_OPS_SERVICE); + + final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + callingUid, callingPackage); + if (mode == AppOpsManager.MODE_DEFAULT) { + // The default behavior here is to check if PackageManager has given the app + // permission. + final int permissionCheck = context.checkCallingPermission( + Manifest.permission.PACKAGE_USAGE_STATS); + return permissionCheck == PackageManager.PERMISSION_GRANTED; + } + return (mode == AppOpsManager.MODE_ALLOWED); + } + return false; + } +} diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 15b68c7399..102695e343 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -22,24 +22,18 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; -import static android.net.TrafficStats.UID_TETHERING; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; -import android.net.ConnectivityManager; import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.Binder; -import android.os.UserHandle; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; -import libcore.io.IoUtils; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -47,6 +41,8 @@ import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import libcore.io.IoUtils; + import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -136,12 +132,12 @@ public class NetworkStatsCollection implements FileRotator.Reader { return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; } - public int[] getRelevantUids() { + public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - if (isAccessibleToUser(key.uid, callerUid)) { + if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) { int j = uids.binarySearch(key.uid); if (j < 0) { @@ -158,8 +154,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { * the requested parameters. */ public NetworkStatsHistory getHistory( - NetworkTemplate template, int uid, int set, int tag, int fields) { - return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE); + NetworkTemplate template, int uid, int set, int tag, int fields, + @NetworkStatsAccess.Level int accessLevel) { + return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE, + accessLevel); } /** @@ -167,9 +165,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { * the requested parameters. */ public NetworkStatsHistory getHistory( - NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { + NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, + @NetworkStatsAccess.Level int accessLevel) { final int callerUid = Binder.getCallingUid(); - if (!isAccessibleToUser(uid, callerUid)) { + if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); } @@ -195,7 +194,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { * Summarize all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ - public NetworkStats getSummary(NetworkTemplate template, long start, long end) { + public NetworkStats getSummary(NetworkTemplate template, long start, long end, + @NetworkStatsAccess.Level int accessLevel) { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); @@ -208,7 +208,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); - if (templateMatches(template, key.ident) && isAccessibleToUser(key.uid, callerUid) + if (templateMatches(template, key.ident) + && NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel) && key.set < NetworkStats.SET_DEBUG_START) { final NetworkStatsHistory value = mStats.valueAt(i); historyEntry = value.getValues(start, end, now, historyEntry); @@ -570,12 +571,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } - private static boolean isAccessibleToUser(int uid, int callerUid) { - return UserHandle.getAppId(callerUid) == android.os.Process.SYSTEM_UID || - uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING - || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); - } - /** * Test if given {@link NetworkTemplate} matches any {@link NetworkIdentity} * in the given {@link NetworkIdentitySet}. diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 649086575c..c09196006b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -116,7 +116,8 @@ public class NetworkStatsRecorder { } public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { - return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null); + return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE, + NetworkStatsAccess.Level.DEVICE).getTotal(null); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 844934846f..b1d6f896dd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -62,13 +62,9 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; -import android.Manifest; import android.app.AlarmManager; -import android.app.AppOpsManager; import android.app.IAlarmManager; import android.app.PendingIntent; -import android.app.admin.DeviceAdminInfo; -import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -97,9 +93,7 @@ import android.os.HandlerThread; import android.os.INetworkManagementService; import android.os.Message; import android.os.PowerManager; -import android.os.Process; import android.os.RemoteException; -import android.os.ServiceManager; import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; @@ -122,7 +116,6 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; -import com.android.server.LocalServices; import com.android.server.connectivity.Tethering; import java.io.File; @@ -484,18 +477,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public int[] getRelevantUids() { - enforcePermissionForManagedAdmin(mCallingPackage); - return getUidComplete().getRelevantUids(); + return getUidComplete().getRelevantUids(checkAccessLevel(mCallingPackage)); } @Override public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, long end) { - enforcePermission(mCallingPackage); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + if (accessLevel < NetworkStatsAccess.Level.DEVICE) { + throw new SecurityException("Calling package " + mCallingPackage + + " cannot access device-level network stats"); + } NetworkStats result = new NetworkStats(end - start, 1); final long ident = Binder.clearCallingIdentity(); try { - result.combineAllValues(internalGetSummaryForNetwork(template, start, end)); + result.combineAllValues( + internalGetSummaryForNetwork(template, start, end, accessLevel)); } finally { Binder.restoreCallingIdentity(ident); } @@ -505,23 +502,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { - enforcePermission(mCallingPackage); - return internalGetSummaryForNetwork(template, start, end); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + return internalGetSummaryForNetwork(template, start, end, accessLevel); } @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return internalGetHistoryForNetwork(template, fields); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + return internalGetHistoryForNetwork(template, fields, accessLevel); } @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { - enforcePermissionForManagedAdmin(mCallingPackage); - final NetworkStats stats = getUidComplete().getSummary(template, start, end); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + final NetworkStats stats = + getUidComplete().getSummary(template, start, end, accessLevel); if (includeTags) { final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end); + .getSummary(template, start, end, accessLevel); stats.combineAllValues(tagStats); } return stats; @@ -530,11 +529,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { - enforcePermissionForManagedAdmin(mCallingPackage); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, uid, set, tag, fields); + return getUidComplete().getHistory(template, uid, set, tag, fields, + accessLevel); } else { - return getUidTagComplete().getHistory(template, uid, set, tag, fields); + return getUidTagComplete().getHistory(template, uid, set, tag, fields, + accessLevel); } } @@ -542,12 +543,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsHistory getHistoryIntervalForUid( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { - enforcePermissionForManagedAdmin(mCallingPackage); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, uid, set, tag, fields, start, end); + return getUidComplete().getHistory(template, uid, set, tag, fields, start, end, + accessLevel); } else { return getUidTagComplete().getHistory(template, uid, set, tag, fields, - start, end); + start, end, accessLevel); } } @@ -559,80 +561,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; } - private boolean hasAppOpsPermission(String callingPackage) { - final int callingUid = Binder.getCallingUid(); - boolean appOpsAllow = false; - if (callingPackage != null) { - AppOpsManager appOps = (AppOpsManager) mContext.getSystemService( - Context.APP_OPS_SERVICE); - - final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, - callingUid, callingPackage); - if (mode == AppOpsManager.MODE_DEFAULT) { - // The default behavior here is to check if PackageManager has given the app - // permission. - final int permissionCheck = mContext.checkCallingPermission( - Manifest.permission.PACKAGE_USAGE_STATS); - appOpsAllow = permissionCheck == PackageManager.PERMISSION_GRANTED; - } - appOpsAllow = (mode == AppOpsManager.MODE_ALLOWED); - } - return appOpsAllow; + private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) { + return NetworkStatsAccess.checkAccessLevel( + mContext, Binder.getCallingUid(), callingPackage); } - private void enforcePermissionForManagedAdmin(String callingPackage) { - boolean hasPermission = hasAppOpsPermission(callingPackage); - if (!hasPermission) { - // Profile and device owners are exempt from permission checking. - final int callingUid = Binder.getCallingUid(); - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); - - // Device owners are also profile owners so it is enough to check for that. - if (dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) { - return; - } - } - if (!hasPermission) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - } - } - - private void enforcePermission(String callingPackage) { - boolean appOpsAllow = hasAppOpsPermission(callingPackage); - if (!appOpsAllow) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - } - } - - /** * Return network summary, splicing between DEV and XT stats when * appropriate. */ private NetworkStats internalGetSummaryForNetwork( - NetworkTemplate template, long start, long end) { + NetworkTemplate template, long start, long end, + @NetworkStatsAccess.Level int accessLevel) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. - return mXtStatsCached.getSummary(template, start, end); + return mXtStatsCached.getSummary(template, start, end, accessLevel); } /** * Return network history, splicing between DEV and XT stats when * appropriate. */ - private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) { + private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields, + @NetworkStatsAccess.Level int accessLevel) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. - return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); + return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields, accessLevel); } @Override public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { + // Special case - since this is for internal use only, don't worry about a full access level + // check and just require the signature/privileged permission. mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); - return internalGetSummaryForNetwork(template, start, end).getTotalBytes(); + return internalGetSummaryForNetwork(template, start, end, NetworkStatsAccess.Level.DEVICE) + .getTotalBytes(); } @Override From b7ab1f9da6de43a09ef88d9036613859400baecc Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Wed, 6 Jan 2016 13:53:36 -0800 Subject: [PATCH 0285/1150] Define new APIs for metering and roaming network stats buckets. These are analagous to the state buckets for tracking whether usage is incurred while the app is in the foreground or background. We will additionally track whether data usage is incurred over a metered or unmetered network, and whether it is incurred over a roaming or native network. The APIs are not implemented in this CL; the existing buckets are still returned with METERING_ALL and ROAMING_ALL to indicate that this is not yet being tracked. Bug: 25813438 Bug: 25813958 Change-Id: I76dd3dd063ed28ef5579ca3a978570532e7836bc --- core/java/android/app/usage/NetworkStats.java | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index ef08eb9e89..5f97c9e1d4 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -121,12 +121,12 @@ public final class NetworkStats implements AutoCloseable { */ public static class Bucket { /** - * Combined usage across all other states. + * Combined usage across all states. */ public static final int STATE_ALL = -1; /** - * Usage not accounted in any other states. + * Usage not accounted for in any other state. */ public static final int STATE_DEFAULT = 0x1; @@ -150,8 +150,40 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** + * Combined usage across all metering states. + */ + public static final int METERING_ALL = -1; + + /** + * Usage not accounted for in any other metering state. + */ + public static final int METERING_DEFAULT = 0x1; + + /** + * Metered usage. + */ + public static final int METERING_METERED = 0x2; + + /** + * Combined usage across all roaming states. + */ + public static final int ROAMING_ALL = -1; + + /** + * Usage not accounted for in any other roaming state. + */ + public static final int ROAMING_DEFAULT = 0x1; + + /** + * Roaming usage. + */ + public static final int ROAMING_ROAMING = 0x2; + private int mUid; private int mState; + private int mMetering; + private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; private long mRxBytes; @@ -205,6 +237,30 @@ public final class NetworkStats implements AutoCloseable { return mState; } + /** + * Metering state. One of the following values:

+ *

    + *
  • {@link #METERING_ALL}
  • + *
  • {@link #METERING_DEFAULT}
  • + *
  • {@link #METERING_METERED}
  • + *
+ */ + public int getMetering() { + return mMetering; + } + + /** + * Roaming state. One of the following values:

+ *

    + *
  • {@link #ROAMING_ALL}
  • + *
  • {@link #ROAMING_DEFAULT}
  • + *
  • {@link #ROAMING_ROAMING}
  • + *
+ */ + public int getRoaming() { + return mRoaming; + } + /** * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. @@ -398,6 +454,9 @@ public final class NetworkStats implements AutoCloseable { private void fillBucketFromSummaryEntry(Bucket bucketOut) { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metering/roaming tracking. + bucketOut.mMetering = Bucket.METERING_ALL; + bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; @@ -444,6 +503,8 @@ public final class NetworkStats implements AutoCloseable { mRecycledHistoryEntry); bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetering = Bucket.METERING_ALL; + bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + mRecycledHistoryEntry.bucketDuration; From 131806f111786d5887be150494e25b1f5257398e Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Mon, 11 Jan 2016 16:02:17 -0800 Subject: [PATCH 0286/1150] Implement roaming tracking in NetworkStats summary queries. Whether a network is deemed roaming or not was already being tracked as part of the NetworkIdentitySet, so the underlying data store already tracks roaming and native data separately. However, this data was being aggregated together in NetworkStatsCollection#getSummary, since the NetworkIdentitySet is converted to an iface name for the purposes of matching, and the iface name will be identical whether or not the iface is considered roaming. Now it is separated. Also fixes a long-standing bug in NetworkIdentitySet where an identity read from a saved file would always be considered roaming == false, even if it wasn't at the time it was written. Bug: 25813438 Change-Id: I11ab5b51182ed8da7af8fde468df065f9fdc3dad --- core/java/android/app/usage/NetworkStats.java | 13 ++- .../app/usage/NetworkStatsManager.java | 25 +++-- core/java/android/net/NetworkStats.java | 101 +++++++++++++++--- ...droid_internal_net_NetworkStatsFactory.cpp | 7 ++ .../server/net/NetworkIdentitySet.java | 15 ++- .../server/net/NetworkStatsCollection.java | 3 + 6 files changed, 134 insertions(+), 30 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 5f97c9e1d4..d2636467ca 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -208,6 +208,15 @@ public final class NetworkStats implements AutoCloseable { return uid; } + private static int convertRoaming(int roaming) { + switch (roaming) { + case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; + case android.net.NetworkStats.ROAMING_DEFAULT : return ROAMING_DEFAULT; + case android.net.NetworkStats.ROAMING_ROAMING : return ROAMING_ROAMING; + } + return 0; + } + public Bucket() { } @@ -454,9 +463,9 @@ public final class NetworkStats implements AutoCloseable { private void fillBucketFromSummaryEntry(Bucket bucketOut) { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metering/roaming tracking. + // TODO: Implement metering tracking. bucketOut.mMetering = Bucket.METERING_ALL; - bucketOut.mRoaming = Bucket.ROAMING_ALL; + bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; bucketOut.mRxBytes = mRecycledSummaryEntry.rxBytes; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 0fce7a90ea..e8373a175e 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -40,16 +40,17 @@ import android.util.Log; * {@link #querySummaryForUser}

* {@link #querySummary}

* These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state combination. In case of the user-wide and device-wide - * summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key and state and roaming combination. In case of the user-wide and + * device-wide summaries a single bucket containing the totalised network usage is returned. *

* History queries *

* {@link #queryDetailsForUid}

* {@link #queryDetails}

- * These queries do not aggregate over time but do aggregate over state. Therefore there can be - * multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL}. + * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there + * can be multiple buckets for a particular key but all Bucket's state is going to be + * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * {@link NetworkStats.Bucket#ROAMING_ALL}. *

* NOTE: Accessing stats for apps other than the calling app requires the permission * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and @@ -81,8 +82,8 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state and uid. This means the * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime' - * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid + * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -114,8 +115,8 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid + * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -146,7 +147,7 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end + * end timestamps. Not aggregated over state, uid, or roaming. This means buckets' start and end * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and * uid are going to vary. * @@ -179,7 +180,8 @@ public class NetworkStatsManager { * Query network usage statistics details. Only usable for uids belonging to calling user. * Result is aggregated over state but not aggregated over time. This means buckets' start and * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going - * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. + * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. roaming + * is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. @@ -215,6 +217,7 @@ public class NetworkStatsManager { * calling user. Result is aggregated over state but not aggregated over time or uid. This means * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary. + * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 77d7e0cd76..8919d516d5 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -50,7 +50,7 @@ public class NetworkStats implements Parcelable { public static final int UID_ALL = -1; /** {@link #tag} value matching any tag. */ public static final int TAG_ALL = -1; - /** {@link #set} value when all sets combined, not including debug sets. */ + /** {@link #set} value for all sets combined, not including debug sets. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; @@ -66,6 +66,13 @@ public class NetworkStats implements Parcelable { /** {@link #tag} value for total data across all tags. */ public static final int TAG_NONE = 0; + /** {@link #set} value for all roaming values. */ + public static final int ROAMING_ALL = -1; + /** {@link #set} value where native, non-roaming data is accounted. */ + public static final int ROAMING_DEFAULT = 0; + /** {@link #set} value where roaming data is accounted. */ + public static final int ROAMING_ROAMING = 1; + // TODO: move fields to "mVariable" notation /** @@ -79,6 +86,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] roaming; private long[] rxBytes; private long[] rxPackets; private long[] txBytes; @@ -90,6 +98,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int roaming; public long rxBytes; public long rxPackets; public long txBytes; @@ -107,10 +121,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + this(iface, uid, set, tag, ROAMING_DEFAULT, rxBytes, rxPackets, txBytes, txPackets, + operations); + } + + public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, + long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; this.txBytes = txBytes; @@ -142,6 +163,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); builder.append(" txBytes=").append(txBytes); @@ -154,8 +176,8 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && rxBytes == e.rxBytes - && rxPackets == e.rxPackets && txBytes == e.txBytes + return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming + && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes && txPackets == e.txPackets && operations == e.operations && iface.equals(e.iface); } @@ -172,6 +194,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; this.txBytes = new long[initialSize]; @@ -184,6 +207,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; this.txBytes = EmptyArray.LONG; @@ -200,6 +224,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); txBytes = parcel.createLongArray(); @@ -216,6 +241,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); dest.writeLongArray(txBytes); @@ -248,6 +274,13 @@ public class NetworkStats implements Parcelable { iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } + @VisibleForTesting + public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + return addValues(new Entry( + iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + } + /** * Add new stats entry, copying from given {@link Entry}. The {@link Entry} * object can be recycled across multiple calls. @@ -259,6 +292,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); txBytes = Arrays.copyOf(txBytes, newLength); @@ -271,6 +305,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; txBytes[size] = entry.txBytes; @@ -290,6 +325,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; entry.txBytes = txBytes[i]; @@ -327,22 +363,23 @@ public class NetworkStats implements Parcelable { public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return combineValues( - iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, txPackets, operations); + iface, uid, SET_DEFAULT, tag, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public NetworkStats combineValues(String iface, int uid, int set, int tag, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public NetworkStats combineValues(String iface, int uid, int set, int tag, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return combineValues(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** * Combine given values with an existing row, or create a new row if - * {@link #findIndex(String, int, int, int)} is unable to find match. Can + * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -370,10 +407,10 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag) { + public int findIndex(String iface, int uid, int set, int tag, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && Objects.equals(iface, this.iface[i])) { + && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { return i; } } @@ -385,7 +422,8 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int hintIndex) { + public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -398,7 +436,7 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && Objects.equals(iface, this.iface[i])) { + && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { return i; } } @@ -412,7 +450,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -502,6 +540,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; entry.txBytes = 0; @@ -596,9 +635,11 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.roaming = left.roaming[i]; // find remote row that matches, and subtract - final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, i); + final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, + entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -644,6 +685,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.roaming = ROAMING_ALL; entry.operations = 0L; for (int i = 0; i < size; i++) { @@ -672,6 +714,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { // skip specific tags, since already counted in TAG_NONE @@ -717,6 +760,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); pw.print(" txBytes="); pw.print(txBytes[i]); @@ -783,6 +827,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #roaming} value. + */ + public static String roamingToString(int roaming) { + switch (roaming) { + case ROAMING_ALL: + return "ALL"; + case ROAMING_DEFAULT: + return "DEFAULT"; + case ROAMING_ROAMING: + return "ROAMING"; + default: + return "UNKNOWN"; + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); @@ -932,6 +992,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { moved.add(tmpEntry); @@ -950,16 +1011,24 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. - int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE); + // + // Relies on the fact that the underlying traffic only has state ROAMING_DEFAULT, which + // should be the case as it comes directly from the /proc file. We only blend in the + // roaming data after applying these adjustments, by checking the NetworkIdentity of the + // underlying iface. + int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, + ROAMING_DEFAULT); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } - int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE); + int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, + ROAMING_DEFAULT); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 70134ab04a..9fa90acc02 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; jfieldID txBytes; @@ -238,6 +239,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW roaming(env, get_int_array(env, stats, + gNetworkStatsClassInfo.roaming, size, grow)); + if (roaming.get() == NULL) return -1; ScopedLongArrayRW rxBytes(env, get_long_array(env, stats, gNetworkStatsClassInfo.rxBytes, size, grow)); if (rxBytes.get() == NULL) return -1; @@ -261,6 +265,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; + // Roaming is populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -274,6 +279,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); @@ -305,6 +311,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index f230bb39be..68dc715b08 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -61,7 +61,7 @@ public class NetworkIdentitySet extends HashSet implements roaming = false; } - add(new NetworkIdentity(type, subType, subscriberId, networkId, false)); + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming)); } } @@ -77,6 +77,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ + public boolean isAnyMemberRoaming() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getRoaming()) { + return true; + } + } + return false; + } + private static void writeOptionalString(DataOutputStream out, String value) throws IOException { if (value != null) { out.writeByte(1); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 102695e343..eec7d931d4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.ROAMING_DEFAULT; +import static android.net.NetworkStats.ROAMING_ROAMING; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; @@ -218,6 +220,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_ROAMING : ROAMING_DEFAULT; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; entry.txBytes = historyEntry.txBytes; From 4ff8b948b0f155d4079a5d365a4648aca0bd71df Mon Sep 17 00:00:00 2001 From: Zoltan Szatmary-Ban Date: Thu, 21 Jan 2016 10:44:37 +0000 Subject: [PATCH 0287/1150] Introduce DEVICESUMMARY access level to NetworkStatsAccess. Apps with PACKAGE_USAGE_STATS app op or READ_NETWORK_USAGE_HISTORY granted can query the summarized device data usage (but not individual uids running in other users or profiles). Bug:26677052 Change-Id: Id51631638f338a8cf48172c9b41746228a335084 --- .../app/usage/NetworkStatsManager.java | 10 ++++--- .../server/net/NetworkStatsAccess.java | 30 ++++++++++++++----- .../server/net/NetworkStatsService.java | 10 +++++-- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index e8373a175e..1a9bf4e25b 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -52,10 +52,12 @@ import android.util.Log; * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

- * NOTE: Accessing stats for apps other than the calling app requires the permission - * {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, which is a system-level permission and - * will not be granted to third-party apps. However, declaring the permission implies intention to - * use the API and the user of the device can grant permission through the Settings application. + * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the + * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, + * which is a system-level permission and will not be granted to third-party apps. However, + * declaring the permission implies intention to use the API and the user of the device can grant + * permission through the Settings application. + *

* Profile owner apps are automatically granted permission to query data on the profile they manage * (that is, for any query except {@link #querySummaryForDevice}). Device owner apps and carrier- * privileged apps likewise get access to usage data for all users on the device. diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 53ba7184e0..479b065f5c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -66,14 +66,25 @@ public final class NetworkStatsAccess { * *

Granted to: *

    - *
  • Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit - * so it is not necessarily sufficient to declare this in the manifest. - *
  • Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. *
  • Profile owners. *
*/ int USER = 1; + /** + * Access level for apps which can access usage summary of device. Device summary includes + * usage by apps running in any profiles/users, however this access level does not + * allow querying usage of individual apps running in other profiles/users. + * + *

Granted to: + *

    + *
  • Apps with the PACKAGE_USAGE_STATS permission granted. Note that this is an AppOps bit + * so it is not necessarily sufficient to declare this in the manifest. + *
  • Apps with the (signature/privileged) READ_NETWORK_USAGE_HISTORY permission. + *
+ */ + int DEVICESUMMARY = 2; + /** * Access level for apps which can access usage for any app on the device, including apps * running on other users/profiles. @@ -85,7 +96,7 @@ public final class NetworkStatsAccess { *
  • The system UID. * */ - int DEVICE = 2; + int DEVICE = 3; } /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ @@ -107,11 +118,15 @@ public final class NetworkStatsAccess { return NetworkStatsAccess.Level.DEVICE; } + boolean hasAppOpsPermission = hasAppOpsPermission(context, callingUid, callingPackage); + if (hasAppOpsPermission || context.checkCallingOrSelfPermission( + READ_NETWORK_USAGE_HISTORY) == PackageManager.PERMISSION_GRANTED) { + return NetworkStatsAccess.Level.DEVICESUMMARY; + } + boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - if (hasAppOpsPermission(context, callingUid, callingPackage) || isProfileOwner - || context.checkCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY) == - PackageManager.PERMISSION_GRANTED) { + if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile. return NetworkStatsAccess.Level.USER; @@ -131,6 +146,7 @@ public final class NetworkStatsAccess { case NetworkStatsAccess.Level.DEVICE: // Device-level access - can access usage for any uid. return true; + case NetworkStatsAccess.Level.DEVICESUMMARY: case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b1d6f896dd..3aeceef51d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -484,15 +484,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, long end) { @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - if (accessLevel < NetworkStatsAccess.Level.DEVICE) { + if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { throw new SecurityException("Calling package " + mCallingPackage - + " cannot access device-level network stats"); + + " cannot access device summary network stats"); } NetworkStats result = new NetworkStats(end - start, 1); final long ident = Binder.clearCallingIdentity(); try { + // Using access level higher than the one we checked for above. + // Reason is that we are combining usage data in a way that is not PII + // anymore. result.combineAllValues( - internalGetSummaryForNetwork(template, start, end, accessLevel)); + internalGetSummaryForNetwork(template, start, end, + NetworkStatsAccess.Level.DEVICE)); } finally { Binder.restoreCallingIdentity(ident); } From 3bbf8f320d1fa1903d19b08d6bd27dbc6968c144 Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Fri, 29 Jan 2016 10:36:52 -0800 Subject: [PATCH 0288/1150] Revert Network Stats API stub for tracking of metered networks. Bug: 25813958 Change-Id: I9d2835b7bacfffef05b1588f1301afc70f5f582f --- core/java/android/app/usage/NetworkStats.java | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index d2636467ca..5622207941 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -150,21 +150,6 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; - /** - * Combined usage across all metering states. - */ - public static final int METERING_ALL = -1; - - /** - * Usage not accounted for in any other metering state. - */ - public static final int METERING_DEFAULT = 0x1; - - /** - * Metered usage. - */ - public static final int METERING_METERED = 0x2; - /** * Combined usage across all roaming states. */ @@ -182,7 +167,6 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mState; - private int mMetering; private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; @@ -246,18 +230,6 @@ public final class NetworkStats implements AutoCloseable { return mState; } - /** - * Metering state. One of the following values:

    - *

      - *
    • {@link #METERING_ALL}
    • - *
    • {@link #METERING_DEFAULT}
    • - *
    • {@link #METERING_METERED}
    • - *
    - */ - public int getMetering() { - return mMetering; - } - /** * Roaming state. One of the following values:

    *

      @@ -463,8 +435,6 @@ public final class NetworkStats implements AutoCloseable { private void fillBucketFromSummaryEntry(Bucket bucketOut) { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metering tracking. - bucketOut.mMetering = Bucket.METERING_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; @@ -512,7 +482,6 @@ public final class NetworkStats implements AutoCloseable { mRecycledHistoryEntry); bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mState = Bucket.STATE_ALL; - bucketOut.mMetering = Bucket.METERING_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + From 2bb66f5d4824f152d4a3b1884c942f7014893e34 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Thu, 10 Dec 2015 15:57:56 -0800 Subject: [PATCH 0289/1150] Retuning tag information through NetworkStatsManager. Network tags could be set since ICS but was not exposed through the SDK. This CL extends existing functionality of NetworkStatsManager to return network tags. Bug: 25813338 Change-Id: I414b98193249ba88a3f2d64cb2e0d2633f64fa3f --- core/java/android/app/usage/NetworkStats.java | 44 ++++++++-- .../app/usage/NetworkStatsManager.java | 87 ++++++++++++++----- core/java/android/net/NetworkStats.java | 2 + 3 files changed, 105 insertions(+), 28 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 5622207941..9f1a9cf01e 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -48,7 +48,6 @@ public final class NetworkStats implements AutoCloseable { */ private final long mEndTimeStamp; - /** * Non-null array indicates the query enumerates over uids. */ @@ -165,7 +164,18 @@ public final class NetworkStats implements AutoCloseable { */ public static final int ROAMING_ROAMING = 0x2; + /** + * Special TAG value matching any tag. + */ + public static final int TAG_ANY = android.net.NetworkStats.TAG_ALL; + + /** + * Special TAG value for total data across all tags + */ + public static final int TAG_ALL = android.net.NetworkStats.TAG_NONE; + private int mUid; + private int mTag; private int mState; private int mRoaming; private long mBeginTimeStamp; @@ -192,6 +202,14 @@ public final class NetworkStats implements AutoCloseable { return uid; } + private static int convertTag(int tag) { + switch (tag) { + case android.net.NetworkStats.TAG_ALL: return TAG_ANY; + case android.net.NetworkStats.TAG_NONE: return TAG_ALL; + } + return tag; + } + private static int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -217,6 +235,14 @@ public final class NetworkStats implements AutoCloseable { return mUid; } + /** + * Tag of the bucket.

      + * @return Bucket tag. + */ + public int getTag() { + return mTag; + } + /** * Usage state. One of the following values:

      *

        @@ -363,9 +389,9 @@ public final class NetworkStats implements AutoCloseable { * Collects summary results and sets summary enumeration mode. * @throws RemoteException */ - void startSummaryEnumeration() throws RemoteException { - mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, false); - + void startSummaryEnumeration(boolean includeTags) throws RemoteException { + mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, + includeTags); mEnumerationIndex = 0; } @@ -373,10 +399,17 @@ public final class NetworkStats implements AutoCloseable { * Collects history results for uid and resets history enumeration index. */ void startHistoryEnumeration(int uid) { + startHistoryEnumeration(uid, android.net.NetworkStats.TAG_NONE); + } + + /** + * Collects history results for uid and resets history enumeration index. + */ + void startHistoryEnumeration(int uid, int tag) { mHistory = null; try { mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, - android.net.NetworkStats.SET_ALL, android.net.NetworkStats.TAG_NONE, + android.net.NetworkStats.SET_ALL, tag, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); setSingleUid(uid); } catch (RemoteException e) { @@ -434,6 +467,7 @@ public final class NetworkStats implements AutoCloseable { private void fillBucketFromSummaryEntry(Bucket bucketOut) { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); + bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1a9bf4e25b..4dc636b078 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -82,10 +82,11 @@ public class NetworkStatsManager { } /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state and uid. This means the - * bucket's start and end timestamp are going to be the same as the 'startTime' and 'endTime' - * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. + * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This + * means the bucket's start and end timestamp are going to be the same as the 'startTime' and + * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid + * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_ALL} + * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -113,12 +114,23 @@ public class NetworkStatsManager { return bucket; } + /** + * Query network usage statistics summaries aggregated across tags. + * + * #see querySummaryForUser(int, String, long, long, boolean) + */ + public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, + long endTime) throws SecurityException, RemoteException { + return querySummaryForUser(networkType, subscriberId, startTime, endTime, + false /* includeTags */); + } + /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -128,11 +140,13 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. + * @param includeTags whether to include network tags. If {@code true}, tags will be returned + * and history retention may be shorter. * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { + long endTime, boolean includeTags) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; @@ -140,18 +154,28 @@ public class NetworkStatsManager { NetworkStats stats; stats = new NetworkStats(mContext, template, startTime, endTime); - stats.startSummaryEnumeration(); + stats.startSummaryEnumeration(includeTags); stats.close(); return stats.getSummaryAggregate(); } + /** + * Query network usage statistics summaries aggregated across tags. + * + * #see querySummary(int, String, long, long, boolean) + */ + public NetworkStats querySummary(int networkType, String subscriberId, long startTime, + long endTime) throws SecurityException, RemoteException { + return querySummary(networkType, subscriberId, startTime, endTime, false /* includeTags */); + } + /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state, uid, or roaming. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters, state and - * uid are going to vary. + * end timestamps. Not aggregated over state or uid or tag. This means buckets' start and end + * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. State, + * uid and tag are going to vary. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -161,11 +185,13 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. + * @param includeTags whether to include network tags. If {@code true}, tags will be returned + * and history retention may be shorter. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ public NetworkStats querySummary(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { + long endTime, boolean includeTags) throws SecurityException, RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; @@ -173,17 +199,28 @@ public class NetworkStatsManager { NetworkStats result; result = new NetworkStats(mContext, template, startTime, endTime); - result.startSummaryEnumeration(); + result.startSummaryEnumeration(includeTags); return result; } /** - * Query network usage statistics details. Only usable for uids belonging to calling user. - * Result is aggregated over state but not aggregated over time. This means buckets' start and - * end timestamps are going to be between 'startTime' and 'endTime' parameters, state is going - * to be {@link NetworkStats.Bucket#STATE_ALL} and uid the same as the 'uid' parameter. roaming - * is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. + * Query network usage statistics details for a given uid. + * + * #see queryDetailsForUidTag(int, String, long, long, int, int) + */ + public NetworkStats queryDetailsForUid(int networkType, String subscriberId, + long startTime, long endTime, int uid) throws SecurityException, RemoteException { + return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid, + NetworkStats.Bucket.TAG_ALL); + } + + /** + * Query network usage statistics details for a given uid and tag. Only usable for uids + * belonging to calling user. Result is aggregated over state but not aggregated over time. + * This means buckets' start and end timestamps are going to be between 'startTime' and + * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the + * same as the 'uid' parameter and tag the same as 'tag' parameter. *

        Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. @@ -197,11 +234,14 @@ public class NetworkStatsManager { * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app + * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_ANY} for any tags, use + * {@link NetworkStats.Bucket#TAG_ALL} to aggregate over tags. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ - public NetworkStats queryDetailsForUid(int networkType, String subscriberId, - long startTime, long endTime, int uid) throws SecurityException, RemoteException { + public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, + long startTime, long endTime, int uid, int tag) throws SecurityException, + RemoteException { NetworkTemplate template = createTemplate(networkType, subscriberId); if (template == null) { return null; @@ -209,7 +249,7 @@ public class NetworkStatsManager { NetworkStats result; result = new NetworkStats(mContext, template, startTime, endTime); - result.startHistoryEnumeration(uid); + result.startHistoryEnumeration(uid, tag); return result; } @@ -218,8 +258,9 @@ public class NetworkStatsManager { * Query network usage statistics details. Result filtered to include only uids belonging to * calling user. Result is aggregated over state but not aggregated over time or uid. This means * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid will vary. - * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. + * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_ALL} and roaming is going to be + * {@link NetworkStats.Bucket#ROAMING_ALL}. *

        Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 8919d516d5..3d8b0917a3 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -49,6 +49,7 @@ public class NetworkStats implements Parcelable { /** {@link #uid} value when UID details unavailable. */ public static final int UID_ALL = -1; /** {@link #tag} value matching any tag. */ + // TODO: Rename TAG_ALL to TAG_ANY. public static final int TAG_ALL = -1; /** {@link #set} value for all sets combined, not including debug sets. */ public static final int SET_ALL = -1; @@ -64,6 +65,7 @@ public class NetworkStats implements Parcelable { public static final int SET_DBG_VPN_OUT = 1002; /** {@link #tag} value for total data across all tags. */ + // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; /** {@link #set} value for all roaming values. */ From fb502108b497c008b46c3160e1d2d708f1e7fc4c Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Wed, 2 Dec 2015 08:42:54 -0800 Subject: [PATCH 0290/1150] Adding a callback to notify data usage. Allow holders of android.Manifest.permission#PACKAGE_USAGE_STATS to be notified when data usage has exceeded a given threshold. This allows an app to update its data usage metrics without polling. Bug: 25812785 Change-Id: I3a4904a97f3c7fbaf8071b460f9ee6ca9c1ba4ed --- .../app/usage/NetworkStatsManager.java | 61 ++++++++ core/java/android/net/DataUsageRequest.aidl | 19 +++ core/java/android/net/DataUsageRequest.java | 143 ++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 core/java/android/net/DataUsageRequest.aidl create mode 100644 core/java/android/net/DataUsageRequest.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 4dc636b078..13aeef0058 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,12 +16,17 @@ package android.app.usage; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; +import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkTemplate; import android.os.Build; +import android.os.Handler; import android.os.RemoteException; import android.util.Log; @@ -288,6 +293,62 @@ public class NetworkStatsManager { return result; } + /** + * Registers to receive notifications about data usage on specified networks and uids. + * The callbacks will continue to be called as long as the process is live or + * {@link #unregisterDataUsageCallback} is called. + * + * @param policy {@link DataUsagePolicy} describing this request. + * @param callback The {@link DataUsageCallback} that the system will call when data usage + * has exceeded the specified threshold. + */ + public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback) { + registerDataUsageCallback(policy, callback, null /* handler */); + } + + /** + * Registers to receive notifications about data usage on specified networks and uids. + * The callbacks will continue to be called as long as the process is live or + * {@link #unregisterDataUsageCallback} is called. + * + * @param policy {@link DataUsagePolicy} describing this request. + * @param callback The {@link DataUsageCallback} that the system will call when data usage + * has exceeded the specified threshold. + * @param handler to dispatch callback events through, otherwise if {@code null} it uses + * the calling thread. + */ + public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback, + @Nullable Handler handler) { + checkNotNull(policy, "DataUsagePolicy cannot be null"); + checkNotNull(callback, "DataUsageCallback cannot be null"); + + // TODO: Implement stub. + } + + /** + * Unregisters callbacks on data usage. + * + * @param callback The {@link DataUsageCallback} used when registering. + */ + public void unregisterDataUsageCallback(DataUsageCallback callback) { + checkNotNull(callback, "DataUsageCallback cannot be null"); + + // TODO: Implement stub. + } + + /** + * Base class for data usage callbacks. Should be extended by applications wanting + * notifications. + */ + public static class DataUsageCallback { + /** + * Called when data usage has reached the given policy threshold. + */ + public void onLimitReached() {} + + private DataUsageRequest request; + } + private static NetworkTemplate createTemplate(int networkType, String subscriberId) { NetworkTemplate template = null; switch (networkType) { diff --git a/core/java/android/net/DataUsageRequest.aidl b/core/java/android/net/DataUsageRequest.aidl new file mode 100644 index 0000000000..d1937c7b8c --- /dev/null +++ b/core/java/android/net/DataUsageRequest.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2016, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +parcelable DataUsageRequest; diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java new file mode 100644 index 0000000000..0e46f4c0cb --- /dev/null +++ b/core/java/android/net/DataUsageRequest.java @@ -0,0 +1,143 @@ +/** + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy + * of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ + +package android.net; + +import android.net.NetworkTemplate; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Defines a request to register a callbacks. Used to be notified on data usage via + * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}. + * If no {@code uid}s are set, callbacks are restricted to device-owners, + * carrier-privileged apps, or system apps. + */ +public class DataUsageRequest implements Parcelable { + + /** + * @hide + */ + public static final int REQUEST_ID_UNSET = 0; + + /** + * Identifies the request. {@link DataUsageRequest}s should only be constructed by + * the Framework and it is used internally to identify the request. + * @hide + */ + public final int requestId; + + /** + * Set of {@link NetworkTemplate}s describing the networks to monitor. + * @hide + */ + public final NetworkTemplate[] templates; + + /** + * Set of UIDs of which to monitor data usage. + * + *

        If not {@code null}, the caller will be notified when any of the uids exceed + * the given threshold. If {@code null} all uids for which the calling process has access + * to stats will be monitored. + * @hide + */ + public final int[] uids; + + /** + * Threshold in bytes to be notified on. + * @hide + */ + public final long thresholdInBytes; + + /** + * @hide + */ + public DataUsageRequest(int requestId, NetworkTemplate[] templates, int[] uids, + long thresholdInBytes) { + this.requestId = requestId; + this.templates = templates; + this.uids = uids; + this.thresholdInBytes = thresholdInBytes; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(requestId); + dest.writeTypedArray(templates, flags); + dest.writeIntArray(uids); + dest.writeLong(thresholdInBytes); + } + + public static final Creator CREATOR = + new Creator() { + @Override + public DataUsageRequest createFromParcel(Parcel in) { + int requestId = in.readInt(); + NetworkTemplate[] templates = in.createTypedArray(NetworkTemplate.CREATOR); + int[] uids = in.createIntArray(); + long thresholdInBytes = in.readLong(); + DataUsageRequest result = new DataUsageRequest(requestId, + templates, uids, thresholdInBytes); + return result; + } + + @Override + public DataUsageRequest[] newArray(int size) { + return new DataUsageRequest[size]; + } + }; + + @Override + public String toString() { + return "DataUsageRequest [ requestId=" + requestId + + ", networkTemplates=" + Arrays.toString(templates) + + ", uids=" + Arrays.toString(uids) + + ", thresholdInBytes=" + thresholdInBytes + " ]"; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DataUsageRequest == false) return false; + DataUsageRequest that = (DataUsageRequest) obj; + return that.requestId == this.requestId + && Arrays.deepEquals(that.templates, this.templates) + && Arrays.equals(that.uids, this.uids) + && that.thresholdInBytes == this.thresholdInBytes; + } + + @Override + public int hashCode() { + // Start with a non-zero constant. + int result = 17; + + // Include a hash for each field. + result = 31 * result + requestId; + result = 31 * result + Arrays.deepHashCode(templates); + result = 31 * result + Arrays.hashCode(uids); + result = 31 * result + (int) (thresholdInBytes ^ (thresholdInBytes >>> 32)); + + return result; + } + +} From ca9d62d08d350b796fd6040d26bd34254cc7430b Mon Sep 17 00:00:00 2001 From: Ritesh Reddy Date: Thu, 4 Feb 2016 18:33:30 +0000 Subject: [PATCH 0291/1150] Enabled Network Policy Backup/Restore. Added Backup Restore specific NetworkPolicySerializer to NetworkPolicy Class and related classes. Change-Id: I2a11e2afae8dd9e0ee0c3356e669a73f6a1361af --- core/java/android/net/NetworkTemplate.java | 37 ++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b7a411e4b6..5761d66dde 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -28,15 +28,21 @@ import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; import static android.telephony.TelephonyManager.getNetworkClass; + import static com.android.internal.util.ArrayUtils.contains; import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; +import android.util.BackupUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; import java.util.Arrays; import java.util.Objects; @@ -47,6 +53,10 @@ import java.util.Objects; * @hide */ public class NetworkTemplate implements Parcelable { + /** + * Current Version of the Backup Serializer. + */ + private static final int BACKUP_VERSION = 1; public static final int MATCH_MOBILE_ALL = 1; @Deprecated @@ -443,4 +453,31 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate[size]; } }; + + public byte[] getBytesForBackup() throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(baos); + + out.writeInt(BACKUP_VERSION); + + out.writeInt(mMatchRule); + BackupUtils.writeString(out, mSubscriberId); + BackupUtils.writeString(out, mNetworkId); + + return baos.toByteArray(); + } + + public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in) + throws IOException, BackupUtils.BadVersionException { + int version = in.readInt(); + if (version < 1 || version > BACKUP_VERSION) { + throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); + } + + int matchRule = in.readInt(); + String subscriberId = BackupUtils.readString(in); + String networkId = BackupUtils.readString(in); + + return new NetworkTemplate(matchRule, subscriberId, networkId); + } } From 7a6536383df6d3d40dbc4f96465d5b9532311791 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Wed, 17 Feb 2016 13:03:38 -0800 Subject: [PATCH 0292/1150] Implementation of data usage callbacks. NetworkStatsService will register data usage requests and keep data usage stats scoped to the request. There are different types of data usage requests - scoped to a set of NetworkTemplate; these are restrictred to device owners and carrier apps and allow the caller to monitor all activity on the specified interfaces. - scoped to all uids visible to the user, if the user has android.Manifest.permission#PACKAGE_USAGE_STATS permission. The set of uids may change over time, so we keep track of that. - scoped to a set of uids given by the caller, granted that the caller has access to those uids. - scoped to the caller's own data usage. This doesn't require PACKAGE_USAGE_STATS. Bug: 25812785 Change-Id: Ie11f35fc1f29d0dbe82f7fc924b169bb55c76708 --- .../app/usage/NetworkStatsManager.java | 99 +++- core/java/android/net/DataUsageRequest.java | 5 + .../android/net/INetworkStatsService.aidl | 10 + .../server/net/NetworkStatsAccess.java | 8 + .../server/net/NetworkStatsCollection.java | 28 +- .../server/net/NetworkStatsObservers.java | 493 ++++++++++++++++++ .../server/net/NetworkStatsRecorder.java | 86 ++- .../server/net/NetworkStatsService.java | 135 ++++- 8 files changed, 811 insertions(+), 53 deletions(-) create mode 100644 services/core/java/com/android/server/net/NetworkStatsObservers.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 13aeef0058..2e3aca46f9 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -25,9 +25,15 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.NetworkIdentity; import android.net.NetworkTemplate; +import android.net.INetworkStatsService; +import android.os.Binder; import android.os.Build; +import android.os.Message; +import android.os.Messenger; import android.os.Handler; +import android.os.Looper; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; /** @@ -75,16 +81,26 @@ import android.util.Log; * not included. */ public class NetworkStatsManager { - private final static String TAG = "NetworkStatsManager"; + private static final String TAG = "NetworkStatsManager"; + private static final boolean DBG = false; + + /** @hide */ + public static final int CALLBACK_LIMIT_REACHED = 0; + /** @hide */ + public static final int CALLBACK_RELEASED = 1; private final Context mContext; + private final INetworkStatsService mService; /** * {@hide} */ public NetworkStatsManager(Context context) { mContext = context; + mService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); } + /** * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This @@ -322,7 +338,40 @@ public class NetworkStatsManager { checkNotNull(policy, "DataUsagePolicy cannot be null"); checkNotNull(callback, "DataUsageCallback cannot be null"); - // TODO: Implement stub. + final Looper looper; + if (handler == null) { + looper = Looper.myLooper(); + } else { + looper = handler.getLooper(); + } + + if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy); + + NetworkTemplate[] templates; + if (policy.subscriberIds == null || policy.subscriberIds.length == 0) { + templates = new NetworkTemplate[1]; + templates[0] = createTemplate(policy.networkType, null /* subscriberId */); + } else { + templates = new NetworkTemplate[policy.subscriberIds.length]; + for (int i = 0; i < policy.subscriberIds.length; i++) { + templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]); + } + } + DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, + templates, policy.uids, policy.thresholdInBytes); + try { + CallbackHandler callbackHandler = new CallbackHandler(looper, callback); + callback.request = mService.registerDataUsageCallback( + mContext.getOpPackageName(), request, new Messenger(callbackHandler), + new Binder()); + if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request); + + if (callback.request == null) { + Log.e(TAG, "Request from callback is null; should not happen"); + } + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when registering callback"); + } } /** @@ -331,9 +380,15 @@ public class NetworkStatsManager { * @param callback The {@link DataUsageCallback} used when registering. */ public void unregisterDataUsageCallback(DataUsageCallback callback) { - checkNotNull(callback, "DataUsageCallback cannot be null"); - - // TODO: Implement stub. + if (callback == null || callback.request == null + || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { + throw new IllegalArgumentException("Invalid DataUsageCallback"); + } + try { + mService.unregisterDataUsageRequest(callback.request); + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); + } } /** @@ -366,4 +421,38 @@ public class NetworkStatsManager { } return template; } + + private static class CallbackHandler extends Handler { + private DataUsageCallback mCallback; + CallbackHandler(Looper looper, DataUsageCallback callback) { + super(looper); + mCallback = callback; + } + + @Override + public void handleMessage(Message message) { + DataUsageRequest request = + (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); + + switch (message.what) { + case CALLBACK_LIMIT_REACHED: { + if (mCallback != null) { + mCallback.onLimitReached(); + } else { + Log.e(TAG, "limit reached with released callback for " + request); + } + break; + } + case CALLBACK_RELEASED: { + if (DBG) Log.d(TAG, "callback released for " + request); + mCallback = null; + break; + } + } + } + + private static Object getObject(Message msg, String key) { + return msg.getData().getParcelable(key); + } + } } diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index 0e46f4c0cb..5e96cc1fe0 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -31,6 +31,11 @@ import java.util.Objects; */ public class DataUsageRequest implements Parcelable { + /** + * @hide + */ + public static final String PARCELABLE_KEY = "DataUsageRequest"; + /** * @hide */ diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 6436e42676..2eea9408f9 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -16,10 +16,13 @@ package android.net; +import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.os.IBinder; +import android.os.Messenger; /** {@hide} */ interface INetworkStatsService { @@ -57,4 +60,11 @@ interface INetworkStatsService { /** Advise persistance threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); + /** Registers a callback on data usage. */ + DataUsageRequest registerDataUsageCallback(String callingPackage, + in DataUsageRequest request, in Messenger messenger, in IBinder binder); + + /** Unregisters a callback on data usage. */ + void unregisterDataUsageRequest(in DataUsageRequest request); + } diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 479b065f5c..98fe770774 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; +import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; @@ -48,6 +49,7 @@ public final class NetworkStatsAccess { @IntDef({ Level.DEFAULT, Level.USER, + Level.DEVICESUMMARY, Level.DEVICE, }) @Retention(RetentionPolicy.SOURCE) @@ -147,6 +149,12 @@ public final class NetworkStatsAccess { // Device-level access - can access usage for any uid. return true; case NetworkStatsAccess.Level.DEVICESUMMARY: + // Can access usage for any app running in the same user, along + // with some special uids (system, removed, or tethering) and + // anonymized uids + return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED + || uid == UID_TETHERING || uid == UID_ALL + || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index eec7d931d4..d986e94b02 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -135,7 +135,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { } public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { - final int callerUid = Binder.getCallingUid(); + return getRelevantUids(accessLevel, Binder.getCallingUid()); + } + + public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, + final int callerUid) { IntArray uids = new IntArray(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); @@ -169,7 +173,17 @@ public class NetworkStatsCollection implements FileRotator.Reader { public NetworkStatsHistory getHistory( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel) { - final int callerUid = Binder.getCallingUid(); + return getHistory(template, uid, set, tag, fields, start, end, accessLevel, + Binder.getCallingUid()); + } + + /** + * Combine all {@link NetworkStatsHistory} in this collection which match + * the requested parameters. + */ + public NetworkStatsHistory getHistory( + NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, + @NetworkStatsAccess.Level int accessLevel, int callerUid) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); @@ -198,6 +212,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel) { + return getSummary(template, start, end, accessLevel, Binder.getCallingUid()); + } + + /** + * Summarize all {@link NetworkStatsHistory} in this collection which match + * the requested parameters. + */ + public NetworkStats getSummary(NetworkTemplate template, long start, long end, + @NetworkStatsAccess.Level int accessLevel, int callerUid) { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); @@ -207,7 +230,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { final NetworkStats.Entry entry = new NetworkStats.Entry(); NetworkStatsHistory.Entry historyEntry = null; - final int callerUid = Binder.getCallingUid(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); if (templateMatches(template, key.ident) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java new file mode 100644 index 0000000000..2f55562bc0 --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.TrafficStats.MB_IN_BYTES; +import static com.android.internal.util.Preconditions.checkArgument; + +import android.app.usage.NetworkStatsManager; +import android.net.DataUsageRequest; +import android.net.NetworkStats; +import android.net.NetworkStats.NonMonotonicObserver; +import android.net.NetworkStatsHistory; +import android.net.NetworkTemplate; +import android.os.Binder; +import android.os.Bundle; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Process; +import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.IntArray; +import android.util.SparseArray; +import android.util.Slog; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.VpnInfo; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Manages observers of {@link NetworkStats}. Allows observers to be notified when + * data usage has been reported in {@link NetworkStatsService}. An observer can set + * a threshold of how much data it cares about to be notified. + */ +class NetworkStatsObservers { + private static final String TAG = "NetworkStatsObservers"; + private static final boolean LOGV = true; + + private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES; + + private static final int MSG_REGISTER = 1; + private static final int MSG_UNREGISTER = 2; + private static final int MSG_UPDATE_STATS = 3; + + // All access to this map must be done from the handler thread. + // indexed by DataUsageRequest#requestId + private final SparseArray mDataUsageRequests = new SparseArray<>(); + + // Sequence number of DataUsageRequests + private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger(); + + // Lazily instantiated when an observer is registered. + private Handler mHandler; + + /** + * Creates a wrapper that contains the caller context and a normalized request. + * The request should be returned to the caller app, and the wrapper should be sent to this + * object through #addObserver by the service handler. + * + *

        It will register the observer asynchronously, so it is safe to call from any thread. + * + * @return the normalized request wrapped within {@link RequestInfo}. + */ + public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger, + IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) { + checkVisibilityUids(callingUid, accessLevel, inputRequest.uids); + + DataUsageRequest request = buildRequest(inputRequest); + RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid, + accessLevel); + + if (LOGV) Slog.v(TAG, "Registering observer for " + request); + getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo)); + return request; + } + + /** + * Unregister a data usage observer. + * + *

        It will unregister the observer asynchronously, so it is safe to call from any thread. + */ + public void unregister(DataUsageRequest request, int callingUid) { + getHandler().sendMessage(mHandler.obtainMessage(MSG_UNREGISTER, callingUid, 0 /* ignore */, + request)); + } + + /** + * Updates data usage statistics of registered observers and notifies if limits are reached. + * + *

        It will update stats asynchronously, so it is safe to call from any thread. + */ + public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot, + ArrayMap activeIfaces, + ArrayMap activeUidIfaces, + VpnInfo[] vpnArray, long currentTime) { + StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces, + activeUidIfaces, vpnArray, currentTime); + getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext)); + } + + private Handler getHandler() { + if (mHandler == null) { + synchronized (this) { + if (mHandler == null) { + if (LOGV) Slog.v(TAG, "Creating handler"); + mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback); + } + } + } + return mHandler; + } + + @VisibleForTesting + protected Looper getHandlerLooperLocked() { + HandlerThread handlerThread = new HandlerThread(TAG); + handlerThread.start(); + return handlerThread.getLooper(); + } + + private Handler.Callback mHandlerCallback = new Handler.Callback() { + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_REGISTER: { + handleRegister((RequestInfo) msg.obj); + return true; + } + case MSG_UNREGISTER: { + handleUnregister((DataUsageRequest) msg.obj, msg.arg1 /* callingUid */); + return true; + } + case MSG_UPDATE_STATS: { + handleUpdateStats((StatsContext) msg.obj); + return true; + } + default: { + return false; + } + } + } + }; + + /** + * Adds a {@link RequestInfo} as an observer. + * Should only be called from the handler thread otherwise there will be a race condition + * on mDataUsageRequests. + */ + private void handleRegister(RequestInfo requestInfo) { + mDataUsageRequests.put(requestInfo.mRequest.requestId, requestInfo); + } + + /** + * Removes a {@link DataUsageRequest} if the calling uid is authorized. + * Should only be called from the handler thread otherwise there will be a race condition + * on mDataUsageRequests. + */ + private void handleUnregister(DataUsageRequest request, int callingUid) { + RequestInfo requestInfo; + requestInfo = mDataUsageRequests.get(request.requestId); + if (requestInfo == null) { + if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request); + return; + } + if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) { + Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request); + return; + } + + if (LOGV) Slog.v(TAG, "Unregistering " + request); + mDataUsageRequests.remove(request.requestId); + requestInfo.unlinkDeathRecipient(); + requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED); + } + + private void handleUpdateStats(StatsContext statsContext) { + if (mDataUsageRequests.size() == 0) { + if (LOGV) Slog.v(TAG, "No registered listeners of data usage"); + return; + } + + if (LOGV) Slog.v(TAG, "Checking if any registered observer needs to be notified"); + for (int i = 0; i < mDataUsageRequests.size(); i++) { + RequestInfo requestInfo = mDataUsageRequests.valueAt(i); + requestInfo.updateStats(statsContext); + } + } + + private DataUsageRequest buildRequest(DataUsageRequest request) { + // Cap the minimum threshold to a safe default to avoid too many callbacks + long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes); + if (thresholdInBytes < request.thresholdInBytes) { + Slog.w(TAG, "Threshold was too low for " + request + + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); + } + return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(), + request.templates, request.uids, thresholdInBytes); + } + + private RequestInfo buildRequestInfo(DataUsageRequest request, + Messenger messenger, IBinder binder, int callingUid, + @NetworkStatsAccess.Level int accessLevel) { + if (accessLevel <= NetworkStatsAccess.Level.USER + || request.uids != null && request.uids.length > 0) { + return new UserUsageRequestInfo(this, request, messenger, binder, callingUid, + accessLevel); + } else { + // Safety check in case a new access level is added and we forgot to update this + checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY); + return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid, + accessLevel); + } + } + + private void checkVisibilityUids(int callingUid, @NetworkStatsAccess.Level int accessLevel, + int[] uids) { + if (uids == null) { + return; + } + for (int i = 0; i < uids.length; i++) { + if (!NetworkStatsAccess.isAccessibleToUser(uids[i], callingUid, accessLevel)) { + throw new SecurityException("Caller " + callingUid + " cannot monitor network stats" + + " for uid " + uids[i] + " with accessLevel " + accessLevel); + } + } + } + + /** + * Tracks information relevant to a data usage observer. + * It will notice when the calling process dies so we can self-expire. + */ + private abstract static class RequestInfo implements IBinder.DeathRecipient { + private final NetworkStatsObservers mStatsObserver; + protected final DataUsageRequest mRequest; + private final Messenger mMessenger; + private final IBinder mBinder; + protected final int mCallingUid; + protected final @NetworkStatsAccess.Level int mAccessLevel; + protected NetworkStatsRecorder mRecorder; + protected NetworkStatsCollection mCollection; + + RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, + Messenger messenger, IBinder binder, int callingUid, + @NetworkStatsAccess.Level int accessLevel) { + mStatsObserver = statsObserver; + mRequest = request; + mMessenger = messenger; + mBinder = binder; + mCallingUid = callingUid; + mAccessLevel = accessLevel; + + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + + @Override + public void binderDied() { + if (LOGV) Slog.v(TAG, "RequestInfo binderDied(" + + mRequest + ", " + mBinder + ")"); + mStatsObserver.unregister(mRequest, Process.SYSTEM_UID); + callCallback(NetworkStatsManager.CALLBACK_RELEASED); + } + + @Override + public String toString() { + return "RequestInfo from uid:" + mCallingUid + + " for " + mRequest + " accessLevel:" + mAccessLevel; + } + + private void unlinkDeathRecipient() { + if (mBinder != null) { + mBinder.unlinkToDeath(this, 0); + } + } + + /** + * Update stats given the samples and interface to identity mappings. + */ + private void updateStats(StatsContext statsContext) { + if (mRecorder == null) { + // First run; establish baseline stats + resetRecorder(); + recordSample(statsContext); + return; + } + recordSample(statsContext); + + if (checkStats()) { + resetRecorder(); + callCallback(NetworkStatsManager.CALLBACK_LIMIT_REACHED); + } + } + + private void callCallback(int callbackType) { + Bundle bundle = new Bundle(); + bundle.putParcelable(DataUsageRequest.PARCELABLE_KEY, mRequest); + Message msg = Message.obtain(); + msg.what = callbackType; + msg.setData(bundle); + try { + if (LOGV) { + Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType) + + " for " + mRequest); + } + mMessenger.send(msg); + } catch (RemoteException e) { + // May occur naturally in the race of binder death. + Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); + } + } + + private void resetRecorder() { + mRecorder = new NetworkStatsRecorder(); + mCollection = mRecorder.getSinceBoot(); + } + + protected abstract boolean checkStats(); + + protected abstract void recordSample(StatsContext statsContext); + + private String callbackTypeToName(int callbackType) { + switch (callbackType) { + case NetworkStatsManager.CALLBACK_LIMIT_REACHED: + return "LIMIT_REACHED"; + case NetworkStatsManager.CALLBACK_RELEASED: + return "RELEASED"; + default: + return "UNKNOWN"; + } + } + } + + private static class NetworkUsageRequestInfo extends RequestInfo { + NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, + Messenger messenger, IBinder binder, int callingUid, + @NetworkStatsAccess.Level int accessLevel) { + super(statsObserver, request, messenger, binder, callingUid, accessLevel); + } + + @Override + protected boolean checkStats() { + for (int i = 0; i < mRequest.templates.length; i++) { + long bytesSoFar = getTotalBytesForNetwork(mRequest.templates[i]); + if (LOGV) { + Slog.v(TAG, bytesSoFar + " bytes so far since notification for " + + mRequest.templates[i]); + } + if (bytesSoFar > mRequest.thresholdInBytes) { + return true; + } + } + return false; + } + + @Override + protected void recordSample(StatsContext statsContext) { + // Recorder does not need to be locked in this context since only the handler + // thread will update it + mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, + statsContext.mVpnArray, statsContext.mCurrentTime); + } + + /** + * Reads stats matching the given template. {@link NetworkStatsCollection} will aggregate + * over all buckets, which in this case should be only one since we built it big enough + * that it will outlive the caller. If it doesn't, then there will be multiple buckets. + */ + private long getTotalBytesForNetwork(NetworkTemplate template) { + NetworkStats stats = mCollection.getSummary(template, + Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, + mAccessLevel, mCallingUid); + if (LOGV) { + Slog.v(TAG, "Netstats for " + template + ": " + stats); + } + return stats.getTotalBytes(); + } + } + + private static class UserUsageRequestInfo extends RequestInfo { + UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, + Messenger messenger, IBinder binder, int callingUid, + @NetworkStatsAccess.Level int accessLevel) { + super(statsObserver, request, messenger, binder, callingUid, accessLevel); + } + + @Override + protected boolean checkStats() { + int[] uidsToMonitor = getUidsToMonitor(); + + for (int i = 0; i < mRequest.templates.length; i++) { + for (int j = 0; j < uidsToMonitor.length; j++) { + long bytesSoFar = getTotalBytesForNetworkUid(mRequest.templates[i], + uidsToMonitor[j]); + + if (LOGV) { + Slog.v(TAG, bytesSoFar + " bytes so far since notification for " + + mRequest.templates[i] + " for uid=" + uidsToMonitor[j]); + } + if (bytesSoFar > mRequest.thresholdInBytes) { + return true; + } + } + } + return false; + } + + @Override + protected void recordSample(StatsContext statsContext) { + // Recorder does not need to be locked in this context since only the handler + // thread will update it + mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, + statsContext.mVpnArray, statsContext.mCurrentTime); + } + + /** + * Reads all stats matching the given template and uid. Ther history will likely only + * contain one bucket per ident since we build it big enough that it will outlive the + * caller lifetime. + */ + private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) { + try { + NetworkStatsHistory history = mCollection.getHistory(template, uid, + NetworkStats.SET_ALL, NetworkStats.TAG_NONE, + NetworkStatsHistory.FIELD_ALL, + Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, + mAccessLevel, mCallingUid); + return history.getTotalBytes(); + } catch (SecurityException e) { + if (LOGV) { + Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid " + + uid); + } + return 0; + } + } + + private int[] getUidsToMonitor() { + if (mRequest.uids == null || mRequest.uids.length == 0) { + return mCollection.getRelevantUids(mAccessLevel, mCallingUid); + } + // Pick only uids from the request that are currently accessible to the user + IntArray accessibleUids = new IntArray(mRequest.uids.length); + for (int i = 0; i < mRequest.uids.length; i++) { + int uid = mRequest.uids[i]; + if (NetworkStatsAccess.isAccessibleToUser(uid, mCallingUid, mAccessLevel)) { + accessibleUids.add(uid); + } + } + return accessibleUids.toArray(); + } + } + + private static class StatsContext { + NetworkStats mXtSnapshot; + NetworkStats mUidSnapshot; + ArrayMap mActiveIfaces; + ArrayMap mActiveUidIfaces; + VpnInfo[] mVpnArray; + long mCurrentTime; + + StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot, + ArrayMap activeIfaces, + ArrayMap activeUidIfaces, + VpnInfo[] vpnArray, long currentTime) { + mXtSnapshot = xtSnapshot; + mUidSnapshot = uidSnapshot; + mActiveIfaces = activeIfaces; + mActiveUidIfaces = activeUidIfaces; + mVpnArray = vpnArray; + mCurrentTime = currentTime; + } + } +} diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index c09196006b..04dc917ec3 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -19,6 +19,7 @@ package com.android.server.net; import static android.net.NetworkStats.TAG_NONE; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.text.format.DateUtils.YEAR_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; import android.net.NetworkStats; @@ -54,7 +55,7 @@ import libcore.io.IoUtils; * Logic to record deltas between periodic {@link NetworkStats} snapshots into * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. * Keeps pending changes in memory until they pass a specific threshold, in - * bytes. Uses {@link FileRotator} for persistence logic. + * bytes. Uses {@link FileRotator} for persistence logic if present. *

        * Not inherently thread safe. */ @@ -86,6 +87,29 @@ public class NetworkStatsRecorder { private WeakReference mComplete; + /** + * Non-persisted recorder, with only one bucket. Used by {@link NetworkStatsObservers}. + */ + public NetworkStatsRecorder() { + mRotator = null; + mObserver = null; + mDropBox = null; + mCookie = null; + + // set the bucket big enough to have all data in one bucket, but allow some + // slack to avoid overflow + mBucketDuration = YEAR_IN_MILLIS; + mOnlyTags = false; + + mPending = null; + mSinceBoot = new NetworkStatsCollection(mBucketDuration); + + mPendingRewriter = null; + } + + /** + * Persisted recorder. + */ public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer, DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) { mRotator = checkNotNull(rotator, "missing FileRotator"); @@ -110,9 +134,15 @@ public class NetworkStatsRecorder { public void resetLocked() { mLastSnapshot = null; - mPending.reset(); - mSinceBoot.reset(); - mComplete.clear(); + if (mPending != null) { + mPending.reset(); + } + if (mSinceBoot != null) { + mSinceBoot.reset(); + } + if (mComplete != null) { + mComplete.clear(); + } } public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { @@ -120,6 +150,10 @@ public class NetworkStatsRecorder { NetworkStatsAccess.Level.DEVICE).getTotal(null); } + public NetworkStatsCollection getSinceBoot() { + return mSinceBoot; + } + /** * Load complete history represented by {@link FileRotator}. Caches * internally as a {@link WeakReference}, and updated with future @@ -127,6 +161,7 @@ public class NetworkStatsRecorder { * as reference is valid. */ public NetworkStatsCollection getOrLoadCompleteLocked() { + checkNotNull(mRotator, "missing FileRotator"); NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; if (res == null) { res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE); @@ -136,6 +171,7 @@ public class NetworkStatsRecorder { } public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) { + checkNotNull(mRotator, "missing FileRotator"); NetworkStatsCollection res = mComplete != null ? mComplete.get() : null; if (res == null) { res = loadLocked(start, end); @@ -205,7 +241,9 @@ public class NetworkStatsRecorder { // only record tag data when requested if ((entry.tag == TAG_NONE) != mOnlyTags) { - mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); + if (mPending != null) { + mPending.recordData(ident, entry.uid, entry.set, entry.tag, start, end, entry); + } // also record against boot stats when present if (mSinceBoot != null) { @@ -231,6 +269,7 @@ public class NetworkStatsRecorder { * {@link #mPersistThresholdBytes}. */ public void maybePersistLocked(long currentTimeMillis) { + checkNotNull(mRotator, "missing FileRotator"); final long pendingBytes = mPending.getTotalBytes(); if (pendingBytes >= mPersistThresholdBytes) { forcePersistLocked(currentTimeMillis); @@ -243,6 +282,7 @@ public class NetworkStatsRecorder { * Force persisting any pending deltas. */ public void forcePersistLocked(long currentTimeMillis) { + checkNotNull(mRotator, "missing FileRotator"); if (mPending.isDirty()) { if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie); try { @@ -264,20 +304,26 @@ public class NetworkStatsRecorder { * to {@link TrafficStats#UID_REMOVED}. */ public void removeUidsLocked(int[] uids) { - try { - // Rewrite all persisted data to migrate UID stats - mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); - } catch (IOException e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); - } catch (OutOfMemoryError e) { - Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); - recoverFromWtf(); + if (mRotator != null) { + try { + // Rewrite all persisted data to migrate UID stats + mRotator.rewriteAll(new RemoveUidRewriter(mBucketDuration, uids)); + } catch (IOException e) { + Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); + recoverFromWtf(); + } catch (OutOfMemoryError e) { + Log.wtf(TAG, "problem removing UIDs " + Arrays.toString(uids), e); + recoverFromWtf(); + } } // Remove any pending stats - mPending.removeUids(uids); - mSinceBoot.removeUids(uids); + if (mPending != null) { + mPending.removeUids(uids); + } + if (mSinceBoot != null) { + mSinceBoot.removeUids(uids); + } // Clear UID from current stats snapshot if (mLastSnapshot != null) { @@ -361,6 +407,8 @@ public class NetworkStatsRecorder { } public void importLegacyNetworkLocked(File file) throws IOException { + checkNotNull(mRotator, "missing FileRotator"); + // legacy file still exists; start empty to avoid double importing mRotator.deleteAll(); @@ -379,6 +427,8 @@ public class NetworkStatsRecorder { } public void importLegacyUidLocked(File file) throws IOException { + checkNotNull(mRotator, "missing FileRotator"); + // legacy file still exists; start empty to avoid double importing mRotator.deleteAll(); @@ -397,7 +447,9 @@ public class NetworkStatsRecorder { } public void dumpLocked(IndentingPrintWriter pw, boolean fullHistory) { - pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); + if (mPending != null) { + pw.print("Pending bytes: "); pw.println(mPending.getTotalBytes()); + } if (fullHistory) { pw.println("Complete history:"); getOrLoadCompleteLocked().dump(pw); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3aeceef51d..2c2e9b91b5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -57,6 +57,7 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.internal.util.Preconditions.checkArgument; import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; @@ -72,6 +73,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.net.DataUsageRequest; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; @@ -90,8 +92,10 @@ import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Message; +import android.os.Messenger; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; @@ -152,6 +156,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final TrustedTime mTime; private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; + private final NetworkStatsObservers mStatsObservers; private final File mSystemDir; private final File mBaseDir; @@ -233,43 +238,65 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - private final Handler mHandler; + /** Must be set in factory by calling #setHandler. */ + private Handler mHandler; + private Handler.Callback mHandlerCallback; private boolean mSystemReady; private long mPersistThreshold = 2 * MB_IN_BYTES; private long mGlobalAlertBytes; - public NetworkStatsService( - Context context, INetworkManagementService networkManager, IAlarmManager alarmManager) { - this(context, networkManager, alarmManager, NtpTrustedTime.getInstance(context), - getDefaultSystemDir(), new DefaultNetworkStatsSettings(context)); - } - private static File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } - public NetworkStatsService(Context context, INetworkManagementService networkManager, - IAlarmManager alarmManager, TrustedTime time, File systemDir, - NetworkStatsSettings settings) { + private static File getDefaultBaseDir() { + File baseDir = new File(getDefaultSystemDir(), "netstats"); + baseDir.mkdirs(); + return baseDir; + } + + public static NetworkStatsService create(Context context, + INetworkManagementService networkManager) { + AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + PowerManager.WakeLock wakeLock = + powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + + NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, + wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(), + new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), + getDefaultSystemDir(), getDefaultBaseDir()); + + HandlerThread handlerThread = new HandlerThread(TAG); + Handler.Callback callback = new HandlerCallback(service); + handlerThread.start(); + Handler handler = new Handler(handlerThread.getLooper(), callback); + service.setHandler(handler, callback); + return service; + } + + @VisibleForTesting + NetworkStatsService(Context context, INetworkManagementService networkManager, + AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time, + TelephonyManager teleManager, NetworkStatsSettings settings, + NetworkStatsObservers statsObservers, File systemDir, File baseDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); + mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager"); mTime = checkNotNull(time, "missing TrustedTime"); - mTeleManager = checkNotNull(TelephonyManager.getDefault(), "missing TelephonyManager"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); - mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + mTeleManager = checkNotNull(teleManager, "missing TelephonyManager"); + mWakeLock = checkNotNull(wakeLock, "missing WakeLock"); + mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); + mSystemDir = checkNotNull(systemDir, "missing systemDir"); + mBaseDir = checkNotNull(baseDir, "missing baseDir"); + } - final PowerManager powerManager = (PowerManager) context.getSystemService( - Context.POWER_SERVICE); - mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - - HandlerThread thread = new HandlerThread(TAG); - thread.start(); - mHandler = new Handler(thread.getLooper(), mHandlerCallback); - - mSystemDir = checkNotNull(systemDir); - mBaseDir = new File(systemDir, "netstats"); - mBaseDir.mkdirs(); + @VisibleForTesting + void setHandler(Handler handler, Handler.Callback callback) { + mHandler = handler; + mHandlerCallback = callback; } public void bindConnectivityManager(IConnectivityManager connManager) { @@ -733,6 +760,46 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerGlobalAlert(); } + @Override + public DataUsageRequest registerDataUsageCallback(String callingPackage, + DataUsageRequest request, Messenger messenger, IBinder binder) { + checkNotNull(callingPackage, "calling package is null"); + checkNotNull(request, "DataUsageRequest is null"); + checkNotNull(request.templates, "NetworkTemplate is null"); + checkArgument(request.templates.length > 0); + checkNotNull(messenger, "messenger is null"); + checkNotNull(binder, "binder is null"); + + int callingUid = Binder.getCallingUid(); + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage); + DataUsageRequest normalizedRequest; + final long token = Binder.clearCallingIdentity(); + try { + normalizedRequest = mStatsObservers.register(request, messenger, binder, + callingUid, accessLevel); + } finally { + Binder.restoreCallingIdentity(token); + } + + // Create baseline stats + mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL)); + + return normalizedRequest; + } + + @Override + public void unregisterDataUsageRequest(DataUsageRequest request) { + checkNotNull(request, "DataUsageRequest is null"); + + int callingUid = Binder.getCallingUid(); + final long token = Binder.clearCallingIdentity(); + try { + mStatsObservers.unregister(request, callingUid); + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to * reflect current {@link #mPersistThreshold} value. Always defers to @@ -945,6 +1012,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + + // We need to make copies of member fields that are sent to the observer to avoid + // a race condition between the service handler thread and the observer's + mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), + new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); } /** @@ -1243,21 +1315,28 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private Handler.Callback mHandlerCallback = new Handler.Callback() { + @VisibleForTesting + static class HandlerCallback implements Handler.Callback { + private final NetworkStatsService mService; + + HandlerCallback(NetworkStatsService service) { + this.mService = service; + } + @Override public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { final int flags = msg.arg1; - performPoll(flags); + mService.performPoll(flags); return true; } case MSG_UPDATE_IFACES: { - updateIfaces(); + mService.updateIfaces(); return true; } case MSG_REGISTER_GLOBAL_ALERT: { - registerGlobalAlert(); + mService.registerGlobalAlert(); return true; } default: { @@ -1265,7 +1344,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } } - }; + } private void assertBandwidthControlEnabled() { if (!isBandwidthControlEnabled()) { From 6df1731743c92d61451c4c1b10f27a89b1b0b973 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Mon, 22 Feb 2016 17:06:47 -0800 Subject: [PATCH 0293/1150] IpConfigStore: New constructor to accept writer Add a new constructor to accept a DelayeDiskWrite object from the caller. BUG: 27293150 Change-Id: I13fb86c76ee5a0d05b45fec0c42b7e1b2233ee76 TEST: `runtest frameworks-wifi` --- .../core/java/com/android/server/net/IpConfigStore.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 90e26d8488..9f1435acd4 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -59,8 +59,12 @@ public class IpConfigStore { protected static final int IPCONFIG_FILE_VERSION = 2; + public IpConfigStore(DelayedDiskWrite writer) { + mWriter = writer; + } + public IpConfigStore() { - mWriter = new DelayedDiskWrite(); + this(new DelayedDiskWrite()); } private boolean writeConfig(DataOutputStream out, int configKey, From bc08d071ba55d98b1ad2523b3acf9dabaa188d95 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 26 Feb 2016 13:03:01 -0700 Subject: [PATCH 0294/1150] When system server goes down, crash apps more. Similar to first patch, but now using new "rethrowFromSystemServer()" method which internally translates DeadObjectException into DeadSystemException. New logic over in Log.printlns() now suppresses the DeadSystemException stack traces, since they're misleading and just added pressure to the precious log buffer space. Add some extra RuntimeInit checks to suppress logging-about-logging when the system server is dead. Bug: 27364859 Change-Id: I05316b3e8e42416b30a56a76c09cd3113a018123 --- core/java/android/net/TrafficStats.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e82485da32..ba8bd34bfc 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -310,7 +310,7 @@ public class TrafficStats { try { getStatsService().incrementOperationCount(uid, tag, operationCount); } catch (RemoteException e) { - throw new RuntimeException(e); + throw e.rethrowFromSystemServer(); } } @@ -653,7 +653,7 @@ public class TrafficStats { try { return getStatsService().getDataLayerSnapshotForUid(uid); } catch (RemoteException e) { - throw new RuntimeException(e); + throw e.rethrowFromSystemServer(); } } @@ -666,7 +666,7 @@ public class TrafficStats { try { return getStatsService().getMobileIfaces(); } catch (RemoteException e) { - throw new RuntimeException(e); + throw e.rethrowFromSystemServer(); } } From 89a344fe602d43b0a65b7c706ee3a0d022dc12b8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 29 Feb 2016 16:34:46 -0700 Subject: [PATCH 0295/1150] Parcelable classes should always be final. Also hide ConnectivityMetricsEvent which isn't being used yet. Bug: 27415331 Change-Id: Iacdccddda504f3f669185f807b4f35b8dc2b0212 --- core/java/android/net/DataUsageRequest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index 5e96cc1fe0..8526584d64 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -29,7 +29,7 @@ import java.util.Objects; * If no {@code uid}s are set, callbacks are restricted to device-owners, * carrier-privileged apps, or system apps. */ -public class DataUsageRequest implements Parcelable { +public final class DataUsageRequest implements Parcelable { /** * @hide From f713828f74b08b6ab70adefe7342a418b1d489ae Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 1 Mar 2016 19:27:23 -0700 Subject: [PATCH 0296/1150] When system server goes down, crash apps more. Apps making calls into the system server may end up persisting internal state or making security decisions based on the perceived success or failure of a call, or the default values returned. The reality is that if the system process just died, init will be along shortly to kill all running apps, so we should have no problem rethrowing the RemoteException as a RuntimeException. Bug: 27364859 Change-Id: Ife0bcb079636c88d54c44d17eb580409fd79028b --- core/java/android/net/EthernetManager.java | 17 ++++++++++------- core/java/android/net/nsd/NsdManager.java | 6 ++++-- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index f45737a66e..664b7b4089 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -87,8 +87,8 @@ public class EthernetManager { public IpConfiguration getConfiguration() { try { return mService.getConfiguration(); - } catch (NullPointerException | RemoteException e) { - return new IpConfiguration(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -98,7 +98,8 @@ public class EthernetManager { public void setConfiguration(IpConfiguration config) { try { mService.setConfiguration(config); - } catch (NullPointerException | RemoteException e) { + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -109,8 +110,8 @@ public class EthernetManager { public boolean isAvailable() { try { return mService.isAvailable(); - } catch (NullPointerException | RemoteException e) { - return false; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -127,7 +128,8 @@ public class EthernetManager { if (mListeners.size() == 1) { try { mService.addListener(mServiceListener); - } catch (NullPointerException | RemoteException e) { + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } } @@ -145,7 +147,8 @@ public class EthernetManager { if (mListeners.isEmpty()) { try { mService.removeListener(mServiceListener); - } catch (NullPointerException | RemoteException e) { + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 377ed88997..86bd502826 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -619,7 +619,9 @@ public final class NsdManager { public void setEnabled(boolean enabled) { try { mService.setEnabled(enabled); - } catch (RemoteException e) { } + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -632,7 +634,7 @@ public final class NsdManager { try { return mService.getMessenger(); } catch (RemoteException e) { - return null; + throw e.rethrowFromSystemServer(); } } } From 9f5c3b8c682a0672328151572e6ec3c0c6f01fef Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Mon, 1 Feb 2016 17:49:31 -0800 Subject: [PATCH 0297/1150] Turn down the logging a little bit. Change-Id: Ib6e0e6f3577afac3b9bfe9a9b1cce70fb16d9d04 --- services/core/java/com/android/server/NsdService.java | 2 +- services/core/java/com/android/server/net/IpConfigStore.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index f4c62259e1..11aef178a2 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -58,7 +58,7 @@ public class NsdService extends INsdManager.Stub { private static final String TAG = "NsdService"; private static final String MDNS_TAG = "mDnsConnector"; - private static final boolean DBG = true; + private static final boolean DBG = false; private Context mContext; private ContentResolver mContentResolver; diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 9f1435acd4..2807ec822b 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -40,7 +40,7 @@ import java.net.Inet4Address; public class IpConfigStore { private static final String TAG = "IpConfigStore"; - private static final boolean DBG = true; + private static final boolean DBG = false; protected final DelayedDiskWrite mWriter; From 27c8a07be62321f2c724c6b5a01e82bdf2e76bfd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 9 Mar 2016 16:40:15 -0700 Subject: [PATCH 0298/1150] Restrict TrafficStats due to privacy concerns. Granular per-UID network statistics can be used to infer user behavior over time, so they fall under the umbrella of the PACKAGE_USAGE_STATS permission. Since we can't check app-ops based permissions in the kernel, the best we can do is redirect users to the NetworkStatsManager class, which offers a much more robust historical data set. Bug: 27577101 Change-Id: I696bdc5e0b3d7e24acf35f388d0ab13617ed8af3 --- core/java/android/net/TrafficStats.java | 75 ++++++++++++++++++++++--- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index ba8bd34bfc..95ffb44d22 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.media.MediaPlayer; import android.os.RemoteException; @@ -33,12 +34,16 @@ import java.net.Socket; import java.net.SocketException; /** - * Class that provides network traffic statistics. These statistics include + * Class that provides network traffic statistics. These statistics include * bytes transmitted and received and network packets transmitted and received, * over all interfaces, over the mobile interface, and on a per-UID basis. *

        - * These statistics may not be available on all platforms. If the statistics - * are not supported by this device, {@link #UNSUPPORTED} will be returned. + * These statistics may not be available on all platforms. If the statistics are + * not supported by this device, {@link #UNSUPPORTED} will be returned. + *

        + * Note that the statistics returned by this class reset and start from zero + * after every reboot. To access more robust historical network statistics data, + * use {@link NetworkStatsManager} instead. */ public class TrafficStats { /** @@ -497,14 +502,27 @@ public class TrafficStats { * monotonically since device boot. Statistics are measured at the network * layer, so they include both TCP and UDP usage. *

        - * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return - * {@link #UNSUPPORTED} on devices where statistics aren't available. + * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may + * return {@link #UNSUPPORTED} on devices where statistics aren't available. + *

        + * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxBytes(int uid) { - return nativeGetUidStat(uid, TYPE_TX_BYTES); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_TX_BYTES); + } else { + return UNSUPPORTED; + } } /** @@ -515,12 +533,25 @@ public class TrafficStats { *

        * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

        + * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxBytes(int uid) { - return nativeGetUidStat(uid, TYPE_RX_BYTES); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_RX_BYTES); + } else { + return UNSUPPORTED; + } } /** @@ -531,12 +562,25 @@ public class TrafficStats { *

        * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

        + * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxPackets(int uid) { - return nativeGetUidStat(uid, TYPE_TX_PACKETS); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_TX_PACKETS); + } else { + return UNSUPPORTED; + } } /** @@ -547,12 +591,25 @@ public class TrafficStats { *

        * Before {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR2}, this may return * {@link #UNSUPPORTED} on devices where statistics aren't available. + *

        + * Starting in {@link android.os.Build.VERSION_CODES#N} this will only + * report traffic statistics for the calling UID. It will return + * {@link #UNSUPPORTED} for all other UIDs for privacy reasons. To access + * historical network statistics belonging to other UIDs, use + * {@link NetworkStatsManager}. * * @see android.os.Process#myUid() * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxPackets(int uid) { - return nativeGetUidStat(uid, TYPE_RX_PACKETS); + // This isn't actually enforcing any security; it just returns the + // unsupported value. The real filtering is done at the kernel level. + final int callingUid = android.os.Process.myUid(); + if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { + return nativeGetUidStat(uid, TYPE_RX_PACKETS); + } else { + return UNSUPPORTED; + } } /** From 082ceb16795c5f6cb17137d892968d52d993f9ee Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Thu, 10 Mar 2016 13:21:38 -0800 Subject: [PATCH 0299/1150] NetworkStats.Bucket API polish. -Add @IntDef constants for STATE_ and ROAMING_. -Expand docs for ROAMING_ constants. -Use ROAMING_NO/YES instead of ROAMING_DEFAULT/ROAMING. Bug: 27531260 Change-Id: I54ecfb4148caa549214df0bee9983036ffa4cb55 --- core/java/android/app/usage/NetworkStats.java | 49 ++++++++++++++----- core/java/android/net/NetworkStats.java | 20 ++++---- .../server/net/NetworkStatsCollection.java | 6 +-- 3 files changed, 49 insertions(+), 26 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 9f1a9cf01e..6d5c81b142 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -16,6 +16,7 @@ package android.app.usage; +import android.annotation.IntDef; import android.content.Context; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -29,6 +30,9 @@ import android.util.Log; import dalvik.system.CloseGuard; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects * are returned as results to various queries in {@link NetworkStatsManager}. @@ -119,6 +123,11 @@ public final class NetworkStats implements AutoCloseable { * aggregated (e.g. time or state) some values may be equal across all buckets. */ public static class Bucket { + /** @hide */ + @IntDef({STATE_ALL, STATE_DEFAULT, STATE_FOREGROUND}) + @Retention(RetentionPolicy.SOURCE) + public @interface State {} + /** * Combined usage across all states. */ @@ -149,20 +158,34 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** @hide */ + @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) + @Retention(RetentionPolicy.SOURCE) + public @interface Roaming {} + /** - * Combined usage across all roaming states. + * Combined usage across all roaming states. Covers both roaming and non-roaming usage. */ public static final int ROAMING_ALL = -1; /** - * Usage not accounted for in any other roaming state. + * Usage that occurs on a home, non-roaming network. + * + *

        Any cellular usage in this bucket was incurred while the device was connected to a + * tower owned or operated by the user's wireless carrier, or a tower that the user's + * wireless carrier has indicated should be treated as a home network regardless. + * + *

        This is also the default value for network types that do not support roaming. */ - public static final int ROAMING_DEFAULT = 0x1; + public static final int ROAMING_NO = 0x1; /** - * Roaming usage. + * Usage that occurs on a roaming network. + * + *

        Any cellular usage in this bucket as incurred while the device was roaming on another + * carrier's network, for which additional charges may apply. */ - public static final int ROAMING_ROAMING = 0x2; + public static final int ROAMING_YES = 0x2; /** * Special TAG value matching any tag. @@ -185,7 +208,7 @@ public final class NetworkStats implements AutoCloseable { private long mTxBytes; private long mTxPackets; - private static int convertState(int networkStatsSet) { + private static @State int convertState(int networkStatsSet) { switch (networkStatsSet) { case android.net.NetworkStats.SET_ALL : return STATE_ALL; case android.net.NetworkStats.SET_DEFAULT : return STATE_DEFAULT; @@ -210,11 +233,11 @@ public final class NetworkStats implements AutoCloseable { return tag; } - private static int convertRoaming(int roaming) { + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; - case android.net.NetworkStats.ROAMING_DEFAULT : return ROAMING_DEFAULT; - case android.net.NetworkStats.ROAMING_ROAMING : return ROAMING_ROAMING; + case android.net.NetworkStats.ROAMING_NO: return ROAMING_NO; + case android.net.NetworkStats.ROAMING_YES: return ROAMING_YES; } return 0; } @@ -252,7 +275,7 @@ public final class NetworkStats implements AutoCloseable { *

      * @return Usage state. */ - public int getState() { + public @State int getState() { return mState; } @@ -260,11 +283,11 @@ public final class NetworkStats implements AutoCloseable { * Roaming state. One of the following values:

      *

        *
      • {@link #ROAMING_ALL}
      • - *
      • {@link #ROAMING_DEFAULT}
      • - *
      • {@link #ROAMING_ROAMING}
      • + *
      • {@link #ROAMING_NO}
      • + *
      • {@link #ROAMING_YES}
      • *
      */ - public int getRoaming() { + public @Roaming int getRoaming() { return mRoaming; } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 3d8b0917a3..25806fa776 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -71,9 +71,9 @@ public class NetworkStats implements Parcelable { /** {@link #set} value for all roaming values. */ public static final int ROAMING_ALL = -1; /** {@link #set} value where native, non-roaming data is accounted. */ - public static final int ROAMING_DEFAULT = 0; + public static final int ROAMING_NO = 0; /** {@link #set} value where roaming data is accounted. */ - public static final int ROAMING_ROAMING = 1; + public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -123,7 +123,7 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_DEFAULT, rxBytes, rxPackets, txBytes, txPackets, + this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, operations); } @@ -836,10 +836,10 @@ public class NetworkStats implements Parcelable { switch (roaming) { case ROAMING_ALL: return "ALL"; - case ROAMING_DEFAULT: - return "DEFAULT"; - case ROAMING_ROAMING: - return "ROAMING"; + case ROAMING_NO: + return "NO"; + case ROAMING_YES: + return "YES"; default: return "UNKNOWN"; } @@ -1019,18 +1019,18 @@ public class NetworkStats implements Parcelable { // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_DEFAULT, which + // Relies on the fact that the underlying traffic only has state ROAMING_NO, which // should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_DEFAULT); + ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_DEFAULT); + ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index d986e94b02..673dd8fbbd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,8 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.ROAMING_DEFAULT; -import static android.net.NetworkStats.ROAMING_ROAMING; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; @@ -242,7 +242,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; - entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_ROAMING : ROAMING_DEFAULT; + entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; entry.txBytes = historyEntry.txBytes; From f28f2820ab0a1eff3d747de5cc3a43b4acd88f53 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 21 Mar 2016 13:12:59 -0600 Subject: [PATCH 0300/1150] Ignore wildcard network policies. They never should have been persisted to disk in the first place. Bug: 24972775 Change-Id: If9254f74455823f9fda9545fdf543fc7250a4016 --- core/java/android/net/NetworkTemplate.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5761d66dde..d847cd0e7c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -250,6 +250,16 @@ public class NetworkTemplate implements Parcelable { } } + public boolean isPersistable() { + switch (mMatchRule) { + case MATCH_MOBILE_WILDCARD: + case MATCH_WIFI_WILDCARD: + return false; + default: + return true; + } + } + public int getMatchRule() { return mMatchRule; } From f759159b62088ec951e71875106497e2511864f8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 22 Mar 2016 10:20:12 -0600 Subject: [PATCH 0301/1150] Update TrafficStats SystemApi docs. Bug: 25726690 Change-Id: I221d62eaaf1e0fca8c26e4f19cb25d306710a849 --- core/java/android/net/TrafficStats.java | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 95ffb44d22..cfd0468a6e 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -147,8 +147,10 @@ public class TrafficStats { } /** - * System API for backup-related support components to tag network traffic - * appropriately. + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. The tag used internally is well-defined to + * distinguish all backup-related traffic. + * * @hide */ @SystemApi @@ -157,8 +159,10 @@ public class TrafficStats { } /** - * System API for restore-related support components to tag network traffic - * appropriately. + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. The tag used internally is well-defined to + * distinguish all restore-related traffic. + * * @hide */ @SystemApi @@ -205,7 +209,13 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } - /** {@hide} */ + /** + * Clear any active UID set to account {@link Socket} traffic originating + * from the current thread. + * + * @see #setThreadStatsUid(int) + * @hide + */ @SystemApi public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); From 74895614daa2f4f4598f929dd91f96399024483a Mon Sep 17 00:00:00 2001 From: Sharvil Nanavati Date: Mon, 21 Mar 2016 14:19:37 -0700 Subject: [PATCH 0302/1150] Add a NetworkTemplate matcher for ConnectivityManager#TYPE_PROXY. Change-Id: I48c0a7bc39e2efcc5b4120a4fa2ecf6dfd54ac27 --- core/java/android/net/NetworkTemplate.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d847cd0e7c..b32b2ccd76 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -68,6 +69,7 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_WILDCARD = 6; public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; + public static final int MATCH_PROXY = 9; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -157,6 +159,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_BLUETOOTH, null, null); } + /** + * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style + * networks together. + */ + public static NetworkTemplate buildTemplateProxy() { + return new NetworkTemplate(MATCH_PROXY, null, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -293,6 +303,8 @@ public class NetworkTemplate implements Parcelable { return matchesWifiWildcard(ident); case MATCH_BLUETOOTH: return matchesBluetooth(ident); + case MATCH_PROXY: + return matchesProxy(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -401,6 +413,13 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches Proxy network template. + */ + private boolean matchesProxy(NetworkIdentity ident) { + return ident.mType == TYPE_PROXY; + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -419,6 +438,8 @@ public class NetworkTemplate implements Parcelable { return "WIFI_WILDCARD"; case MATCH_BLUETOOTH: return "BLUETOOTH"; + case MATCH_PROXY: + return "PROXY"; default: return "UNKNOWN"; } From 70ee7efa312e8857b3eff76bae55a151977c3aa0 Mon Sep 17 00:00:00 2001 From: Sharvil Nanavati Date: Mon, 21 Mar 2016 14:19:37 -0700 Subject: [PATCH 0303/1150] DO NOT MERGE ANYWHERE Add a NetworkTemplate matcher for ConnectivityManager#TYPE_PROXY. Change-Id: I48c0a7bc39e2efcc5b4120a4fa2ecf6dfd54ac27 --- core/java/android/net/NetworkTemplate.java | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b7a411e4b6..c7339c13c6 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; +import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -58,6 +59,7 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_MOBILE_WILDCARD = 6; public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; + public static final int MATCH_PROXY = 9; /** * Set of {@link NetworkInfo#getType()} that reflect data usage. @@ -147,6 +149,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_BLUETOOTH, null, null); } + /** + * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style + * networks together. + */ + public static NetworkTemplate buildTemplateProxy() { + return new NetworkTemplate(MATCH_PROXY, null, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -273,6 +283,8 @@ public class NetworkTemplate implements Parcelable { return matchesWifiWildcard(ident); case MATCH_BLUETOOTH: return matchesBluetooth(ident); + case MATCH_PROXY: + return matchesProxy(ident); default: throw new IllegalArgumentException("unknown network template"); } @@ -381,6 +393,13 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches Proxy network template. + */ + private boolean matchesProxy(NetworkIdentity ident) { + return ident.mType == TYPE_PROXY; + } + private static String getMatchRuleName(int matchRule) { switch (matchRule) { case MATCH_MOBILE_3G_LOWER: @@ -399,6 +418,8 @@ public class NetworkTemplate implements Parcelable { return "WIFI_WILDCARD"; case MATCH_BLUETOOTH: return "BLUETOOTH"; + case MATCH_PROXY: + return "PROXY"; default: return "UNKNOWN"; } From e80e75eda4d7c1f221df10de543fc8d12ed31622 Mon Sep 17 00:00:00 2001 From: Joe Onorato Date: Fri, 18 Mar 2016 13:34:13 -0700 Subject: [PATCH 0304/1150] Turn off verbose logs and remove log that is covered by verbose logs. Bug: 27744135 Change-Id: I436cfd325f87b3b9205d50e92e2a70a50dd33344 --- .../core/java/com/android/server/net/NetworkStatsObservers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index 2f55562bc0..6f781b3ebb 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -52,7 +52,7 @@ import java.util.concurrent.atomic.AtomicInteger; */ class NetworkStatsObservers { private static final String TAG = "NetworkStatsObservers"; - private static final boolean LOGV = true; + private static final boolean LOGV = false; private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES; From bbb41dd3bdf35a65e61f9154b1695f5d0623dcb4 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Wed, 16 Mar 2016 10:15:39 -0700 Subject: [PATCH 0305/1150] Parse and validate txt records. Bug: 27696905 Change-Id: I9affcf02a51c92a2be1c2bfc5efbd09065e100bc --- core/java/android/net/nsd/NsdServiceInfo.java | 98 ++++++++++++++++++- .../java/com/android/server/NsdService.java | 22 +---- 2 files changed, 101 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 6fdb0d0f84..4a06fb1220 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -16,8 +16,11 @@ package android.net.nsd; +import android.annotation.NonNull; import android.os.Parcelable; import android.os.Parcel; +import android.text.TextUtils; +import android.util.Base64; import android.util.Log; import android.util.ArrayMap; @@ -95,8 +98,99 @@ public final class NsdServiceInfo implements Parcelable { mPort = p; } + /** + * Unpack txt information from a base-64 encoded byte array. + * + * @param rawRecords The raw base64 encoded records string read from netd. + * + * @hide + */ + public void setTxtRecords(@NonNull String rawRecords) { + byte[] txtRecordsRawBytes = Base64.decode(rawRecords, Base64.DEFAULT); + + // There can be multiple TXT records after each other. Each record has to following format: + // + // byte type required meaning + // ------------------- ------------------- -------- ---------------------------------- + // 0 unsigned 8 bit yes size of record excluding this byte + // 1 - n ASCII but not '=' yes key + // n + 1 '=' optional separator of key and value + // n + 2 - record size uninterpreted bytes optional value + // + // Example legal records: + // [11, 'm', 'y', 'k', 'e', 'y', '=', 0x0, 0x4, 0x65, 0x7, 0xff] + // [17, 'm', 'y', 'K', 'e', 'y', 'W', 'i', 't', 'h', 'N', 'o', 'V', 'a', 'l', 'u', 'e', '='] + // [12, 'm', 'y', 'B', 'o', 'o', 'l', 'e', 'a', 'n', 'K', 'e', 'y'] + // + // Example corrupted records + // [3, =, 1, 2] <- key is empty + // [3, 0, =, 2] <- key contains non-ASCII character. We handle this by replacing the + // invalid characters instead of skipping the record. + // [30, 'a', =, 2] <- length exceeds total left over bytes in the TXT records array, we + // handle this by reducing the length of the record as needed. + int pos = 0; + while (pos < txtRecordsRawBytes.length) { + // recordLen is an unsigned 8 bit value + int recordLen = txtRecordsRawBytes[pos] & 0xff; + pos += 1; + + try { + if (recordLen == 0) { + throw new IllegalArgumentException("Zero sized txt record"); + } else if (pos + recordLen > txtRecordsRawBytes.length) { + Log.w(TAG, "Corrupt record length (pos = " + pos + "): " + recordLen); + recordLen = txtRecordsRawBytes.length - pos; + } + + // Decode key-value records + String key = null; + byte[] value = null; + int valueLen = 0; + for (int i = pos; i < pos + recordLen; i++) { + if (key == null) { + if (txtRecordsRawBytes[i] == '=') { + key = new String(txtRecordsRawBytes, pos, i - pos, + StandardCharsets.US_ASCII); + } + } else { + if (value == null) { + value = new byte[recordLen - key.length() - 1]; + } + value[valueLen] = txtRecordsRawBytes[i]; + valueLen++; + } + } + + // If '=' was not found we have a boolean record + if (key == null) { + key = new String(txtRecordsRawBytes, pos, recordLen, StandardCharsets.US_ASCII); + } + + if (TextUtils.isEmpty(key)) { + // Empty keys are not allowed (RFC6763 6.4) + throw new IllegalArgumentException("Invalid txt record (key is empty)"); + } + + if (getAttributes().containsKey(key)) { + // When we have a duplicate record, the later ones are ignored (RFC6763 6.4) + throw new IllegalArgumentException("Invalid txt record (duplicate key \"" + key + "\")"); + } + + setAttribute(key, value); + } catch (IllegalArgumentException e) { + Log.e(TAG, "While parsing txt records (pos = " + pos + "): " + e.getMessage()); + } + + pos += recordLen; + } + } + /** @hide */ public void setAttribute(String key, byte[] value) { + if (TextUtils.isEmpty(key)) { + throw new IllegalArgumentException("Key cannot be empty"); + } + // Key must be printable US-ASCII, excluding =. for (int i = 0; i < key.length(); ++i) { char character = key.charAt(i); @@ -177,10 +271,10 @@ public final class NsdServiceInfo implements Parcelable { } /** @hide */ - public byte[] getTxtRecord() { + public @NonNull byte[] getTxtRecord() { int txtRecordSize = getTxtRecordSize(); if (txtRecordSize == 0) { - return null; + return new byte[]{}; } byte[] txtRecord = new byte[txtRecordSize]; diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 11aef178a2..a44b065d42 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -30,16 +30,14 @@ import android.os.Message; import android.os.Messenger; import android.os.UserHandle; import android.provider.Settings; +import android.util.Base64; import android.util.Slog; import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; import java.net.InetAddress; import java.util.HashMap; -import java.util.Locale; -import java.util.Map; import java.util.concurrent.CountDownLatch; import com.android.internal.util.AsyncChannel; @@ -492,6 +490,7 @@ public class NsdService extends INsdManager.Stub { clientInfo.mResolvedService.setServiceName(name); clientInfo.mResolvedService.setServiceType(type); clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); + clientInfo.mResolvedService.setTxtRecords(cooked[6]); stopResolveService(id); removeRequestMap(clientId, id, clientInfo); @@ -708,20 +707,9 @@ public class NsdService extends INsdManager.Stub { if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); try { Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(), - service.getServiceType(), service.getPort()); - - // Add TXT records as additional arguments. - Map txtRecords = service.getAttributes(); - for (String key : txtRecords.keySet()) { - try { - // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data. - byte[] recordValue = txtRecords.get(key); - cmd.appendArg(String.format(Locale.US, "%s=%s", key, - recordValue != null ? new String(recordValue, "UTF_8") : "")); - } catch (UnsupportedEncodingException e) { - Slog.e(TAG, "Failed to encode txtRecord " + e); - } - } + service.getServiceType(), service.getPort(), + Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT) + .replace("\n", "")); mNativeConnector.execute(cmd); } catch(NativeDaemonConnectorException e) { From 7e3859251fca8d16b00af49dc5bec7a575936ea6 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 30 Mar 2016 11:14:39 -0700 Subject: [PATCH 0306/1150] Excluded certain APNs (e.g. IMS) from mobile data usage. Added not_metered capability to a mobile network if none of its associated APN types are metered. Also used not_metered capability to determine if a network should be accounted for data usage or not instead of using network type, which is always MOBILE after refactoring. Will add VT usage support in next phase. bug: 20888836 Change-Id: Id692cb856be9a47d0e918371112630128965b1bb --- core/java/android/net/NetworkIdentity.java | 24 +++++++++++++++---- core/java/android/net/NetworkTemplate.java | 21 ++++------------ .../server/net/NetworkIdentitySet.java | 18 ++++++++++++-- 3 files changed, 40 insertions(+), 23 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index a9de23ef1b..9cd563e87c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -55,19 +55,22 @@ public class NetworkIdentity implements Comparable { final String mSubscriberId; final String mNetworkId; final boolean mRoaming; + final boolean mMetered; public NetworkIdentity( - int type, int subType, String subscriberId, String networkId, boolean roaming) { + int type, int subType, String subscriberId, String networkId, boolean roaming, + boolean metered) { mType = type; mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; + mMetered = metered; } @Override public int hashCode() { - return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming); + return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered); } @Override @@ -76,7 +79,8 @@ public class NetworkIdentity implements Comparable { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming && Objects.equals(mSubscriberId, ident.mSubscriberId) - && Objects.equals(mNetworkId, ident.mNetworkId); + && Objects.equals(mNetworkId, ident.mNetworkId) + && mMetered == ident.mMetered; } return false; } @@ -102,6 +106,7 @@ public class NetworkIdentity implements Comparable { if (mRoaming) { builder.append(", ROAMING"); } + builder.append(", metered=").append(mMetered); return builder.append("}").toString(); } @@ -125,6 +130,10 @@ public class NetworkIdentity implements Comparable { return mRoaming; } + public boolean getMetered() { + return mMetered; + } + /** * Scrub given IMSI on production builds. */ @@ -162,6 +171,7 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; + boolean metered = false; if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -171,6 +181,9 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); + metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; @@ -182,7 +195,7 @@ public class NetworkIdentity implements Comparable { } } - return new NetworkIdentity(type, subType, subscriberId, networkId, roaming); + return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered); } @Override @@ -200,6 +213,9 @@ public class NetworkIdentity implements Comparable { if (res == 0) { res = Boolean.compare(mRoaming, another.mRoaming); } + if (res == 0) { + res = Boolean.compare(mMetered, another.mMetered); + } return res; } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b32b2ccd76..caf79829db 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -19,6 +19,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_PROXY; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -30,9 +31,6 @@ import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; import static android.telephony.TelephonyManager.getNetworkClass; -import static com.android.internal.util.ArrayUtils.contains; - -import android.content.res.Resources; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; @@ -71,16 +69,6 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; - /** - * Set of {@link NetworkInfo#getType()} that reflect data usage. - */ - private static final int[] DATA_USAGE_NETWORK_TYPES; - - static { - DATA_USAGE_NETWORK_TYPES = Resources.getSystem().getIntArray( - com.android.internal.R.array.config_data_usage_network_types); - } - private static boolean sForceAllNetworkTypes = false; @VisibleForTesting @@ -318,9 +306,8 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - final boolean matchesType = (sForceAllNetworkTypes - || contains(DATA_USAGE_NETWORK_TYPES, ident.mType)); - return matchesType && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } } @@ -389,7 +376,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || contains(DATA_USAGE_NETWORK_TYPES, ident.mType); + return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); } } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 68dc715b08..959a823290 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -23,6 +23,8 @@ import java.io.DataOutputStream; import java.io.IOException; import java.util.HashSet; +import static android.net.ConnectivityManager.TYPE_MOBILE; + /** * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} * active on that interface. @@ -34,6 +36,7 @@ public class NetworkIdentitySet extends HashSet implements private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; private static final int VERSION_ADD_NETWORK_ID = 3; + private static final int VERSION_ADD_METERED = 4; public NetworkIdentitySet() { } @@ -61,12 +64,22 @@ public class NetworkIdentitySet extends HashSet implements roaming = false; } - add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming)); + final boolean metered; + if (version >= VERSION_ADD_METERED) { + metered = in.readBoolean(); + } else { + // If this is the old data and the type is mobile, treat it as metered. (Note that + // if this is a mobile network, TYPE_MOBILE is the only possible type that could be + // used.) + metered = (type == TYPE_MOBILE); + } + + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered)); } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_NETWORK_ID); + out.writeInt(VERSION_ADD_METERED); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -74,6 +87,7 @@ public class NetworkIdentitySet extends HashSet implements writeOptionalString(out, ident.getSubscriberId()); writeOptionalString(out, ident.getNetworkId()); out.writeBoolean(ident.getRoaming()); + out.writeBoolean(ident.getMetered()); } } From 1ba4d36e2c80d4fad53b7fa4a77ea767b5a581e8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 10 Apr 2016 15:39:53 +0900 Subject: [PATCH 0307/1150] Improve Tethering and NativeDaemonConnector logging. 1. Deduplicate the Tethering message numbers, and use MessageUtils to convert them to strings. 2. Add a warning to NativeDaemonConnector when an unsolicited event is more than 500ms late or takes more than 500ms to process. Bug: 27857665 Change-Id: I379aef9257027d1ccf30906e79c6389ef1f95420 --- .../android/server/NativeDaemonConnector.java | 24 ++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index d6dbad87b0..7db9be20e9 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -109,6 +109,14 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mDebug = debug; } + /** + * Like SystemClock.uptimeMillis, except truncated to an int so it will fit in a message arg. + * Inaccurate across 49.7 days of uptime, but only used for debugging. + */ + private int uptimeMillisInt() { + return (int) SystemClock.uptimeMillis() & Integer.MAX_VALUE; + } + /** * Yell loudly if someone tries making future {@link #execute(Command)} * calls while holding a lock on the given object. @@ -134,7 +142,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo @Override public boolean handleMessage(Message msg) { - String event = (String) msg.obj; + final String event = (String) msg.obj; + final int start = uptimeMillisInt(); + final int sent = msg.arg1; try { if (!mCallbacks.onEvent(msg.what, event, NativeDaemonEvent.unescapeArgs(event))) { log(String.format("Unhandled event '%s'", event)); @@ -145,6 +155,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (mCallbacks.onCheckHoldWakeLock(msg.what) && mWakeLock != null) { mWakeLock.release(); } + final int end = uptimeMillisInt(); + if (start > sent && start - sent > WARN_EXECUTE_DELAY_MS) { + loge(String.format("NDC event {%s} processed too late: %dms", event, start - sent)); + } + if (end > start && end - start > WARN_EXECUTE_DELAY_MS) { + loge(String.format("NDC event {%s} took too long: %dms", event, end - start)); + } } return true; } @@ -214,8 +231,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mWakeLock.acquire(); releaseWl = true; } - if (mCallbackHandler.sendMessage(mCallbackHandler.obtainMessage( - event.getCode(), event.getRawEvent()))) { + Message msg = mCallbackHandler.obtainMessage( + event.getCode(), uptimeMillisInt(), 0, event.getRawEvent()); + if (mCallbackHandler.sendMessage(msg)) { releaseWl = false; } } else { From 8b3ff56d28abde42bb438eede67651042ca9a805 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 11 Apr 2016 17:08:10 +0900 Subject: [PATCH 0308/1150] If we want to release the lock, release instead of acquiring it. The intent of this code seems pretty clearly to release the lock, not acquire it. This is bad since it's a refcounted wakelock. Change-Id: I0f7590ab697133bd82db8a1a515453316c6a80dc --- .../core/java/com/android/server/NativeDaemonConnector.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 7db9be20e9..6009984842 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -243,7 +243,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo log("Problem parsing message " + e); } finally { if (releaseWl) { - mWakeLock.acquire(); + mWakeLock.release(); } } From 3616d5e826b858d1b50ae8576125de0dbdd917a7 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 12 Apr 2016 15:19:10 -0600 Subject: [PATCH 0309/1150] Fix broken javadoc. Change-Id: I9f2050fd6040234bb1d759ab346f79fc41247aa9 --- core/java/android/net/TrafficStats.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index cfd0468a6e..1ac9fca51b 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -228,7 +228,6 @@ public class TrafficStats { * statistics parameters. * * @see #setThreadStatsTag(int) - * @see #setThreadStatsUid(int) */ public static void tagSocket(Socket socket) throws SocketException { SocketTagger.get().tag(socket); @@ -249,7 +248,6 @@ public class TrafficStats { * parameters. * * @see #setThreadStatsTag(int) - * @see #setThreadStatsUid(int) */ public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { SocketTagger.get().tag(socket); From 8bad0f4646f5928b554fe6f1e2470083ca2e9bad Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Wed, 30 Mar 2016 18:52:40 +0100 Subject: [PATCH 0310/1150] Move UidRange aidl declaration to system/netd Which owns the native UidRange.cpp, so it makes more sense for the declaration to live there since frameworks/base depends on netd but not vice versa. Bug: 26694104 Change-Id: I0efda77713ee6f0ec8070fb0e09a694b95f6cd25 --- core/java/android/net/UidRange.aidl | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl deleted file mode 100644 index f9be628c16..0000000000 --- a/core/java/android/net/UidRange.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * An inclusive range of UIDs. - * - * {@hide} - */ -parcelable UidRange; From 576ec01271cd517c39a0656aba734d4bba061d4c Mon Sep 17 00:00:00 2001 From: Rebecca Silberstein Date: Thu, 21 Apr 2016 12:14:41 -0700 Subject: [PATCH 0311/1150] NativeDaemonConnector: add waitForCallbacks method Add a method that allows callers to wait until all unsolicited responses received from the native daemon during a command are processed. When commands are issued to a native daemon (such as netd) through the NativeDaemonConnector we block until the command response is received. Any responses or events that are a side-effect (considered "unsolicited") of the command are placed in a Message and handled as callbacks. The order of their processing is not guaranteed and, as we have seen from bugreports, can be handled several seconds later - causing the SoftAP that was just set up to be torn down because a late interface down/removed is indistinguishable from a new interface down/removed. This CL adds a method that first checks to make sure callback thread is not the same thread as used for the blocking call. The new waitForCallbacks method uses a CountDownLatch to force the calling thread to wait until all unsolicited responses received from the native daemon during the execution of the command are handled. The wifiFirmwareReload method is also updated to use the new waitForCallbacks method. BUG: 27857665 Change-Id: I3e22978f720b1cbf57fbb64ad4fea73f8c2d408a --- .../android/server/NativeDaemonConnector.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index 6009984842..f5f7732141 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -41,6 +41,7 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.LinkedList; @@ -343,6 +344,30 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo rawBuilder.append('\0'); } + /** + * Method that waits until all asychronous notifications sent by the native daemon have + * been processed. This method must not be called on the notification thread or an + * exception will be thrown. + */ + public void waitForCallbacks() { + if (Thread.currentThread() == mLooper.getThread()) { + throw new IllegalStateException("Must not call this method on callback thread"); + } + + final CountDownLatch latch = new CountDownLatch(1); + mCallbackHandler.post(new Runnable() { + @Override + public void run() { + latch.countDown(); + } + }); + try { + latch.await(); + } catch (InterruptedException e) { + Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); + } + } + /** * Issue the given command to the native daemon and return a single expected * response. From 84a92fd256311b4a3ca9985fa87d0efa1c360ac3 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Fri, 22 Apr 2016 11:23:27 -0700 Subject: [PATCH 0312/1150] Fixing network tags. - History was not populating the tag, so all of them appeared as tag 0x0. Bug: 28345240 Change-Id: I9c898695bbe8d18531f7ea432ebb8f02d72e5d27 --- core/java/android/app/usage/NetworkStats.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 6d5c81b142..9963eab9b9 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -63,6 +63,11 @@ public final class NetworkStats implements AutoCloseable { */ private int mUidOrUidIndex; + /** + * Tag id in case if was specified in the query. + */ + private int mTag = android.net.NetworkStats.TAG_NONE; + /** * The session while the query requires it, null if all the stats have been collected or close() * has been called. @@ -434,7 +439,7 @@ public final class NetworkStats implements AutoCloseable { mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, android.net.NetworkStats.SET_ALL, tag, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - setSingleUid(uid); + setSingleUidTag(uid, tag); } catch (RemoteException e) { Log.w(TAG, e); // Leaving mHistory null @@ -538,6 +543,7 @@ public final class NetworkStats implements AutoCloseable { mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, mRecycledHistoryEntry); bucketOut.mUid = Bucket.convertUid(getUid()); + bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; @@ -579,8 +585,9 @@ public final class NetworkStats implements AutoCloseable { return mUidOrUidIndex; } - private void setSingleUid(int uid) { + private void setSingleUidTag(int uid, int tag) { mUidOrUidIndex = uid; + mTag = tag; } private void stepUid() { From 79a3c031a09ff02e1f22c87024ae220c32e04c6c Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 18 Apr 2016 16:23:06 -0700 Subject: [PATCH 0313/1150] Indicate the NsdServiceInfo attributes are only filled in for a resolved service. Fixes: 28530428 Change-Id: Ic90bcf4eec10c7db0fd4a4acc8436dda6bab4ba8 --- core/java/android/net/nsd/NsdManager.java | 10 +++++----- core/java/android/net/nsd/NsdServiceInfo.java | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 86bd502826..33d12a3a3f 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -103,11 +103,11 @@ import com.android.internal.util.Protocol; * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on * {@link DiscoveryListener#onServiceLost}. * - *

      Once the peer application discovers the "Example" http srevice, and needs to receive data - * from the "Example" application, it can initiate a resolve with {@link #resolveService} to - * resolve the host and port details for the purpose of establishing a connection. A successful - * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified - * on {@link ResolveListener#onResolveFailed}. + *

      Once the peer application discovers the "Example" http service, and either needs to read the + * attributes of the service or wants to receive data from the "Example" application, it can + * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port + * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a + * failure is notified on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 4a06fb1220..7b845be749 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -250,7 +250,8 @@ public final class NsdServiceInfo implements Parcelable { } /** - * Retrive attributes as a map of String keys to byte[] values. + * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only + * valid for a resolved service. * *

      The returned map is unmodifiable; changes must be made through {@link #setAttribute} and * {@link #removeAttribute}. From fe78ecbb2caa3a647a0bddb4c3bea65d7e2cd736 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Wed, 30 Mar 2016 11:37:18 -0700 Subject: [PATCH 0314/1150] Addressing API council comments on NetworkStatsManager. Callbacks - DataUsageCallback renamed to UsageCallback - DataUsagePolicy removed; passing in params directly to register method - making it an abstract class - passing in (networkType, subscriberId) that reached its threshold - renaming onLimitReached to onThresholdReached to match existing naming - only monitor single network,subscriberId - no monitoring of specific uids; using device or user wide instead Tags - only owner uid can read its tags - exposing only TAG_NONE to match service side BUG: 27530098 Change-Id: I2b2664da71806868a1e937d2bf4d1f234637509b --- core/java/android/app/usage/NetworkStats.java | 14 +- .../app/usage/NetworkStatsManager.java | 225 ++++++++++-------- core/java/android/net/DataUsageRequest.java | 63 +---- .../android/net/INetworkStatsService.aidl | 4 +- .../server/net/NetworkStatsObservers.java | 72 ++---- .../server/net/NetworkStatsService.java | 12 +- 6 files changed, 167 insertions(+), 223 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 9963eab9b9..226aa8f270 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -192,15 +192,10 @@ public final class NetworkStats implements AutoCloseable { */ public static final int ROAMING_YES = 0x2; - /** - * Special TAG value matching any tag. - */ - public static final int TAG_ANY = android.net.NetworkStats.TAG_ALL; - /** * Special TAG value for total data across all tags */ - public static final int TAG_ALL = android.net.NetworkStats.TAG_NONE; + public static final int TAG_NONE = android.net.NetworkStats.TAG_NONE; private int mUid; private int mTag; @@ -232,8 +227,7 @@ public final class NetworkStats implements AutoCloseable { private static int convertTag(int tag) { switch (tag) { - case android.net.NetworkStats.TAG_ALL: return TAG_ANY; - case android.net.NetworkStats.TAG_NONE: return TAG_ALL; + case android.net.NetworkStats.TAG_NONE: return TAG_NONE; } return tag; } @@ -417,9 +411,9 @@ public final class NetworkStats implements AutoCloseable { * Collects summary results and sets summary enumeration mode. * @throws RemoteException */ - void startSummaryEnumeration(boolean includeTags) throws RemoteException { + void startSummaryEnumeration() throws RemoteException { mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp, - includeTags); + false /* includeTags */); mEnumerationIndex = 0; } diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 2e3aca46f9..4a2811778a 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -106,7 +106,7 @@ public class NetworkStatsManager { * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This * means the bucket's start and end timestamp are going to be the same as the 'startTime' and * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_ALL} + * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -122,8 +122,11 @@ public class NetworkStatsManager { */ public Bucket querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (template == null) { + NetworkTemplate template; + try { + template = createTemplate(networkType, subscriberId); + } catch (IllegalArgumentException e) { + if (DBG) Log.e(TAG, "Cannot create template", e); return null; } @@ -135,22 +138,11 @@ public class NetworkStatsManager { return bucket; } - /** - * Query network usage statistics summaries aggregated across tags. - * - * #see querySummaryForUser(int, String, long, long, boolean) - */ - public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - return querySummaryForUser(networkType, subscriberId, startTime, endTime, - false /* includeTags */); - } - /** * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid + * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid * {@link NetworkStats.Bucket#UID_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -161,42 +153,33 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. - * @param includeTags whether to include network tags. If {@code true}, tags will be returned - * and history retention may be shorter. * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, - long endTime, boolean includeTags) throws SecurityException, RemoteException { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (template == null) { + long endTime) throws SecurityException, RemoteException { + NetworkTemplate template; + try { + template = createTemplate(networkType, subscriberId); + } catch (IllegalArgumentException e) { + if (DBG) Log.e(TAG, "Cannot create template", e); return null; } NetworkStats stats; stats = new NetworkStats(mContext, template, startTime, endTime); - stats.startSummaryEnumeration(includeTags); + stats.startSummaryEnumeration(); stats.close(); return stats.getSummaryAggregate(); } - /** - * Query network usage statistics summaries aggregated across tags. - * - * #see querySummary(int, String, long, long, boolean) - */ - public NetworkStats querySummary(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { - return querySummary(networkType, subscriberId, startTime, endTime, false /* includeTags */); - } - /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid or tag. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. State, - * uid and tag are going to vary. + * end timestamps. Not aggregated over state or uid. This means buckets' start and end + * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. + * State and uid are going to vary, and tag is going to be the same. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -206,21 +189,22 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. - * @param includeTags whether to include network tags. If {@code true}, tags will be returned - * and history retention may be shorter. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ public NetworkStats querySummary(int networkType, String subscriberId, long startTime, - long endTime, boolean includeTags) throws SecurityException, RemoteException { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (template == null) { + long endTime) throws SecurityException, RemoteException { + NetworkTemplate template; + try { + template = createTemplate(networkType, subscriberId); + } catch (IllegalArgumentException e) { + if (DBG) Log.e(TAG, "Cannot create template", e); return null; } NetworkStats result; result = new NetworkStats(mContext, template, startTime, endTime); - result.startSummaryEnumeration(includeTags); + result.startSummaryEnumeration(); return result; } @@ -233,7 +217,7 @@ public class NetworkStatsManager { public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException, RemoteException { return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid, - NetworkStats.Bucket.TAG_ALL); + NetworkStats.Bucket.TAG_NONE); } /** @@ -255,22 +239,28 @@ public class NetworkStatsManager { * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_ANY} for any tags, use - * {@link NetworkStats.Bucket#TAG_ALL} to aggregate over tags. + * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, - long startTime, long endTime, int uid, int tag) throws SecurityException, - RemoteException { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (template == null) { + long startTime, long endTime, int uid, int tag) { + NetworkTemplate template; + try { + template = createTemplate(networkType, subscriberId); + } catch (IllegalArgumentException e) { + if (DBG) Log.e(TAG, "Cannot create template", e); return null; } NetworkStats result; - result = new NetworkStats(mContext, template, startTime, endTime); - result.startHistoryEnumeration(uid, tag); + try { + result = new NetworkStats(mContext, template, startTime, endTime); + result.startHistoryEnumeration(uid, tag); + } catch (RemoteException e) { + Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e); + return null; + } return result; } @@ -280,7 +270,7 @@ public class NetworkStatsManager { * calling user. Result is aggregated over state but not aggregated over time or uid. This means * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_ALL} and roaming is going to be + * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

      Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this @@ -299,44 +289,59 @@ public class NetworkStatsManager { */ public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { - NetworkTemplate template = createTemplate(networkType, subscriberId); - if (template == null) { + NetworkTemplate template; + try { + template = createTemplate(networkType, subscriberId); + } catch (IllegalArgumentException e) { + if (DBG) Log.e(TAG, "Cannot create template", e); return null; } + NetworkStats result; result = new NetworkStats(mContext, template, startTime, endTime); result.startUserUidEnumeration(); return result; } + /** @removed */ + public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback, + @Nullable Handler handler) {} + + /** @removed */ + public void registerDataUsageCallback(DataUsagePolicy policy, UsageCallback callback, + @Nullable Handler handler) {} + + /** @removed */ + public void unregisterDataUsageCallback(DataUsageCallback callback) {} + /** - * Registers to receive notifications about data usage on specified networks and uids. - * The callbacks will continue to be called as long as the process is live or - * {@link #unregisterDataUsageCallback} is called. + * Registers to receive notifications about data usage on specified networks. * - * @param policy {@link DataUsagePolicy} describing this request. - * @param callback The {@link DataUsageCallback} that the system will call when data usage - * has exceeded the specified threshold. + * #see registerUsageCallback(int, String[], long, UsageCallback, Handler) */ - public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback) { - registerDataUsageCallback(policy, callback, null /* handler */); + public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, + UsageCallback callback) { + registerUsageCallback(networkType, subscriberId, thresholdBytes, null /* handler */); } /** - * Registers to receive notifications about data usage on specified networks and uids. - * The callbacks will continue to be called as long as the process is live or - * {@link #unregisterDataUsageCallback} is called. + * Registers to receive notifications about data usage on specified networks. * - * @param policy {@link DataUsagePolicy} describing this request. - * @param callback The {@link DataUsageCallback} that the system will call when data usage + *

      The callbacks will continue to be called as long as the process is live or + * {@link #unregisterUsageCallback} is called. + * + * @param networkType Type of network to monitor. Either + {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. + * @param subscriberId If applicable, the subscriber id of the network interface. + * @param thresholdBytes Threshold in bytes to be notified on. + * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. * @param handler to dispatch callback events through, otherwise if {@code null} it uses * the calling thread. */ - public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback, - @Nullable Handler handler) { - checkNotNull(policy, "DataUsagePolicy cannot be null"); - checkNotNull(callback, "DataUsageCallback cannot be null"); + public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, + UsageCallback callback, @Nullable Handler handler) { + checkNotNull(callback, "UsageCallback cannot be null"); final Looper looper; if (handler == null) { @@ -345,62 +350,72 @@ public class NetworkStatsManager { looper = handler.getLooper(); } - if (DBG) Log.d(TAG, "registerDataUsageCallback called with " + policy); - - NetworkTemplate[] templates; - if (policy.subscriberIds == null || policy.subscriberIds.length == 0) { - templates = new NetworkTemplate[1]; - templates[0] = createTemplate(policy.networkType, null /* subscriberId */); - } else { - templates = new NetworkTemplate[policy.subscriberIds.length]; - for (int i = 0; i < policy.subscriberIds.length; i++) { - templates[i] = createTemplate(policy.networkType, policy.subscriberIds[i]); - } + if (DBG) { + Log.d(TAG, "registerUsageCallback called with: {" + + " networkType=" + networkType + + " subscriberId=" + subscriberId + + " thresholdBytes=" + thresholdBytes + + " }"); } + + NetworkTemplate template = createTemplate(networkType, subscriberId); DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, - templates, policy.uids, policy.thresholdInBytes); + template, thresholdBytes); try { - CallbackHandler callbackHandler = new CallbackHandler(looper, callback); - callback.request = mService.registerDataUsageCallback( + CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, + subscriberId, callback); + callback.request = mService.registerUsageCallback( mContext.getOpPackageName(), request, new Messenger(callbackHandler), new Binder()); - if (DBG) Log.d(TAG, "registerDataUsageCallback returned " + callback.request); + if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); if (callback.request == null) { Log.e(TAG, "Request from callback is null; should not happen"); } } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when registering callback"); + throw e.rethrowFromSystemServer(); } } /** * Unregisters callbacks on data usage. * - * @param callback The {@link DataUsageCallback} used when registering. + * @param callback The {@link UsageCallback} used when registering. */ - public void unregisterDataUsageCallback(DataUsageCallback callback) { + public void unregisterUsageCallback(UsageCallback callback) { if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { - throw new IllegalArgumentException("Invalid DataUsageCallback"); + throw new IllegalArgumentException("Invalid UsageCallback"); } try { - mService.unregisterDataUsageRequest(callback.request); + mService.unregisterUsageRequest(callback.request); } catch (RemoteException e) { if (DBG) Log.d(TAG, "Remote exception when unregistering callback"); + throw e.rethrowFromSystemServer(); } } - /** - * Base class for data usage callbacks. Should be extended by applications wanting - * notifications. - */ - public static class DataUsageCallback { - /** - * Called when data usage has reached the given policy threshold. - */ + /** @removed */ + public static abstract class DataUsageCallback { + /** @removed */ + @Deprecated public void onLimitReached() {} + } + /** + * Base class for usage callbacks. Should be extended by applications wanting notifications. + */ + public static abstract class UsageCallback { + + /** + * Called when data usage has reached the given threshold. + */ + public abstract void onThresholdReached(int networkType, String subscriberId); + + /** + * @hide used for internal bookkeeping + */ private DataUsageRequest request; } @@ -414,18 +429,24 @@ public class NetworkStatsManager { template = NetworkTemplate.buildTemplateWifiWildcard(); } break; default: { - Log.w(TAG, "Cannot create template for network type " + networkType - + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) + - "'."); + throw new IllegalArgumentException("Cannot create template for network type " + + networkType + ", subscriberId '" + + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); } } return template; } private static class CallbackHandler extends Handler { - private DataUsageCallback mCallback; - CallbackHandler(Looper looper, DataUsageCallback callback) { + private final int mNetworkType; + private final String mSubscriberId; + private UsageCallback mCallback; + + CallbackHandler(Looper looper, int networkType, String subscriberId, + UsageCallback callback) { super(looper); + mNetworkType = networkType; + mSubscriberId = subscriberId; mCallback = callback; } @@ -437,7 +458,7 @@ public class NetworkStatsManager { switch (message.what) { case CALLBACK_LIMIT_REACHED: { if (mCallback != null) { - mCallback.onLimitReached(); + mCallback.onThresholdReached(mNetworkType, mSubscriberId); } else { Log.e(TAG, "limit reached with released callback for " + request); } diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index 8526584d64..ac9a5a3668 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -20,7 +20,6 @@ import android.net.NetworkTemplate; import android.os.Parcel; import android.os.Parcelable; -import java.util.Arrays; import java.util.Objects; /** @@ -28,56 +27,33 @@ import java.util.Objects; * {@link android.app.usage.NetworkStatsManager#registerDataUsageCallback}. * If no {@code uid}s are set, callbacks are restricted to device-owners, * carrier-privileged apps, or system apps. + * + * @hide */ public final class DataUsageRequest implements Parcelable { - /** - * @hide - */ public static final String PARCELABLE_KEY = "DataUsageRequest"; - - /** - * @hide - */ public static final int REQUEST_ID_UNSET = 0; /** * Identifies the request. {@link DataUsageRequest}s should only be constructed by * the Framework and it is used internally to identify the request. - * @hide */ public final int requestId; /** - * Set of {@link NetworkTemplate}s describing the networks to monitor. - * @hide + * {@link NetworkTemplate} describing the network to monitor. */ - public final NetworkTemplate[] templates; - - /** - * Set of UIDs of which to monitor data usage. - * - *

      If not {@code null}, the caller will be notified when any of the uids exceed - * the given threshold. If {@code null} all uids for which the calling process has access - * to stats will be monitored. - * @hide - */ - public final int[] uids; + public final NetworkTemplate template; /** * Threshold in bytes to be notified on. - * @hide */ public final long thresholdInBytes; - /** - * @hide - */ - public DataUsageRequest(int requestId, NetworkTemplate[] templates, int[] uids, - long thresholdInBytes) { + public DataUsageRequest(int requestId, NetworkTemplate template, long thresholdInBytes) { this.requestId = requestId; - this.templates = templates; - this.uids = uids; + this.template = template; this.thresholdInBytes = thresholdInBytes; } @@ -89,8 +65,7 @@ public final class DataUsageRequest implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(requestId); - dest.writeTypedArray(templates, flags); - dest.writeIntArray(uids); + dest.writeParcelable(template, flags); dest.writeLong(thresholdInBytes); } @@ -99,11 +74,10 @@ public final class DataUsageRequest implements Parcelable { @Override public DataUsageRequest createFromParcel(Parcel in) { int requestId = in.readInt(); - NetworkTemplate[] templates = in.createTypedArray(NetworkTemplate.CREATOR); - int[] uids = in.createIntArray(); + NetworkTemplate template = in.readParcelable(null); long thresholdInBytes = in.readLong(); - DataUsageRequest result = new DataUsageRequest(requestId, - templates, uids, thresholdInBytes); + DataUsageRequest result = new DataUsageRequest(requestId, template, + thresholdInBytes); return result; } @@ -116,8 +90,7 @@ public final class DataUsageRequest implements Parcelable { @Override public String toString() { return "DataUsageRequest [ requestId=" + requestId - + ", networkTemplates=" + Arrays.toString(templates) - + ", uids=" + Arrays.toString(uids) + + ", networkTemplate=" + template + ", thresholdInBytes=" + thresholdInBytes + " ]"; } @@ -126,23 +99,13 @@ public final class DataUsageRequest implements Parcelable { if (obj instanceof DataUsageRequest == false) return false; DataUsageRequest that = (DataUsageRequest) obj; return that.requestId == this.requestId - && Arrays.deepEquals(that.templates, this.templates) - && Arrays.equals(that.uids, this.uids) + && Objects.equals(that.template, this.template) && that.thresholdInBytes == this.thresholdInBytes; } @Override public int hashCode() { - // Start with a non-zero constant. - int result = 17; - - // Include a hash for each field. - result = 31 * result + requestId; - result = 31 * result + Arrays.deepHashCode(templates); - result = 31 * result + Arrays.hashCode(uids); - result = 31 * result + (int) (thresholdInBytes ^ (thresholdInBytes >>> 32)); - - return result; + return Objects.hash(requestId, template, thresholdInBytes); } } diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 2eea9408f9..e693009c33 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -61,10 +61,10 @@ interface INetworkStatsService { void advisePersistThreshold(long thresholdBytes); /** Registers a callback on data usage. */ - DataUsageRequest registerDataUsageCallback(String callingPackage, + DataUsageRequest registerUsageCallback(String callingPackage, in DataUsageRequest request, in Messenger messenger, in IBinder binder); /** Unregisters a callback on data usage. */ - void unregisterDataUsageRequest(in DataUsageRequest request); + void unregisterUsageRequest(in DataUsageRequest request); } diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index 6f781b3ebb..230c2e9510 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -81,8 +81,6 @@ class NetworkStatsObservers { */ public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger, IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - checkVisibilityUids(callingUid, accessLevel, inputRequest.uids); - DataUsageRequest request = buildRequest(inputRequest); RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid, accessLevel); @@ -211,14 +209,13 @@ class NetworkStatsObservers { + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); } return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(), - request.templates, request.uids, thresholdInBytes); + request.template, thresholdInBytes); } private RequestInfo buildRequestInfo(DataUsageRequest request, Messenger messenger, IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - if (accessLevel <= NetworkStatsAccess.Level.USER - || request.uids != null && request.uids.length > 0) { + if (accessLevel <= NetworkStatsAccess.Level.USER) { return new UserUsageRequestInfo(this, request, messenger, binder, callingUid, accessLevel); } else { @@ -229,19 +226,6 @@ class NetworkStatsObservers { } } - private void checkVisibilityUids(int callingUid, @NetworkStatsAccess.Level int accessLevel, - int[] uids) { - if (uids == null) { - return; - } - for (int i = 0; i < uids.length; i++) { - if (!NetworkStatsAccess.isAccessibleToUser(uids[i], callingUid, accessLevel)) { - throw new SecurityException("Caller " + callingUid + " cannot monitor network stats" - + " for uid " + uids[i] + " with accessLevel " + accessLevel); - } - } - } - /** * Tracks information relevant to a data usage observer. * It will notice when the calling process dies so we can self-expire. @@ -359,15 +343,13 @@ class NetworkStatsObservers { @Override protected boolean checkStats() { - for (int i = 0; i < mRequest.templates.length; i++) { - long bytesSoFar = getTotalBytesForNetwork(mRequest.templates[i]); - if (LOGV) { - Slog.v(TAG, bytesSoFar + " bytes so far since notification for " - + mRequest.templates[i]); - } - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } + long bytesSoFar = getTotalBytesForNetwork(mRequest.template); + if (LOGV) { + Slog.v(TAG, bytesSoFar + " bytes so far since notification for " + + mRequest.template); + } + if (bytesSoFar > mRequest.thresholdInBytes) { + return true; } return false; } @@ -405,20 +387,17 @@ class NetworkStatsObservers { @Override protected boolean checkStats() { - int[] uidsToMonitor = getUidsToMonitor(); + int[] uidsToMonitor = mCollection.getRelevantUids(mAccessLevel, mCallingUid); - for (int i = 0; i < mRequest.templates.length; i++) { - for (int j = 0; j < uidsToMonitor.length; j++) { - long bytesSoFar = getTotalBytesForNetworkUid(mRequest.templates[i], - uidsToMonitor[j]); + for (int i = 0; i < uidsToMonitor.length; i++) { + long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]); - if (LOGV) { - Slog.v(TAG, bytesSoFar + " bytes so far since notification for " - + mRequest.templates[i] + " for uid=" + uidsToMonitor[j]); - } - if (bytesSoFar > mRequest.thresholdInBytes) { - return true; - } + if (LOGV) { + Slog.v(TAG, bytesSoFar + " bytes so far since notification for " + + mRequest.template + " for uid=" + uidsToMonitor[i]); + } + if (bytesSoFar > mRequest.thresholdInBytes) { + return true; } } return false; @@ -453,21 +432,6 @@ class NetworkStatsObservers { return 0; } } - - private int[] getUidsToMonitor() { - if (mRequest.uids == null || mRequest.uids.length == 0) { - return mCollection.getRelevantUids(mAccessLevel, mCallingUid); - } - // Pick only uids from the request that are currently accessible to the user - IntArray accessibleUids = new IntArray(mRequest.uids.length); - for (int i = 0; i < mRequest.uids.length; i++) { - int uid = mRequest.uids[i]; - if (NetworkStatsAccess.isAccessibleToUser(uid, mCallingUid, mAccessLevel)) { - accessibleUids.add(uid); - } - } - return accessibleUids.toArray(); - } } private static class StatsContext { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 2c2e9b91b5..8610fa1b7b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -578,9 +578,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (tag == TAG_NONE) { return getUidComplete().getHistory(template, uid, set, tag, fields, start, end, accessLevel); - } else { + } else if (uid == Binder.getCallingUid()) { return getUidTagComplete().getHistory(template, uid, set, tag, fields, start, end, accessLevel); + } else { + throw new SecurityException("Calling package " + mCallingPackage + + " cannot access tag information from a different uid"); } } @@ -761,12 +764,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public DataUsageRequest registerDataUsageCallback(String callingPackage, + public DataUsageRequest registerUsageCallback(String callingPackage, DataUsageRequest request, Messenger messenger, IBinder binder) { checkNotNull(callingPackage, "calling package is null"); checkNotNull(request, "DataUsageRequest is null"); - checkNotNull(request.templates, "NetworkTemplate is null"); - checkArgument(request.templates.length > 0); + checkNotNull(request.template, "NetworkTemplate is null"); checkNotNull(messenger, "messenger is null"); checkNotNull(binder, "binder is null"); @@ -788,7 +790,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void unregisterDataUsageRequest(DataUsageRequest request) { + public void unregisterUsageRequest(DataUsageRequest request) { checkNotNull(request, "DataUsageRequest is null"); int callingUid = Binder.getCallingUid(); From 92a0487493dbbb030ad4d7050da7aaaebb1fcf05 Mon Sep 17 00:00:00 2001 From: Ian Rogers Date: Wed, 18 May 2016 19:58:56 -0700 Subject: [PATCH 0315/1150] Fix 2 instances of buggy double check locking on non-volatile fields. Bug caught by Error Prone: http://errorprone.info/bugpattern/DoubleCheckedLocking Bug: 27723540 Change-Id: I0b0c06ce4ae1ffb668e8ab3a7fe07706df173f18 --- .../core/java/com/android/server/net/NetworkStatsObservers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index 6f781b3ebb..77292846be 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -68,7 +68,7 @@ class NetworkStatsObservers { private final AtomicInteger mNextDataUsageRequestId = new AtomicInteger(); // Lazily instantiated when an observer is registered. - private Handler mHandler; + private volatile Handler mHandler; /** * Creates a wrapper that contains the caller context and a normalized request. From bfd4e42c8d33b55db00afe336db02630b1240ac4 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Wed, 25 May 2016 09:57:21 -0700 Subject: [PATCH 0316/1150] Cleaning up NetworkStatsManager. - Throwing SecurityExceptionand and IllegalArgumentException instead of null for new APIs - removing @removed APIs Bug:27530098,27379882 Change-Id: Ifbe65bfc5051aa33aff2baa22cfa8e67b0f7c358 --- .../app/usage/NetworkStatsManager.java | 31 +++---------------- .../server/net/NetworkStatsObservers.java | 10 ------ 2 files changed, 4 insertions(+), 37 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 4a2811778a..720c84a8e2 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -240,18 +240,13 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. - * @return Statistics object or null if permissions are insufficient or error happened during - * statistics collection. + * @return Statistics object or null if an error happened during statistics collection. + * @throws SecurityException if permissions are insufficient to read network statistics. */ public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, - long startTime, long endTime, int uid, int tag) { + long startTime, long endTime, int uid, int tag) throws SecurityException { NetworkTemplate template; - try { - template = createTemplate(networkType, subscriberId); - } catch (IllegalArgumentException e) { - if (DBG) Log.e(TAG, "Cannot create template", e); - return null; - } + template = createTemplate(networkType, subscriberId); NetworkStats result; try { @@ -303,17 +298,6 @@ public class NetworkStatsManager { return result; } - /** @removed */ - public void registerDataUsageCallback(DataUsagePolicy policy, DataUsageCallback callback, - @Nullable Handler handler) {} - - /** @removed */ - public void registerDataUsageCallback(DataUsagePolicy policy, UsageCallback callback, - @Nullable Handler handler) {} - - /** @removed */ - public void unregisterDataUsageCallback(DataUsageCallback callback) {} - /** * Registers to receive notifications about data usage on specified networks. * @@ -396,13 +380,6 @@ public class NetworkStatsManager { } } - /** @removed */ - public static abstract class DataUsageCallback { - /** @removed */ - @Deprecated - public void onLimitReached() {} - } - /** * Base class for usage callbacks. Should be extended by applications wanting notifications. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index 230c2e9510..ea361700fa 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -190,11 +190,9 @@ class NetworkStatsObservers { private void handleUpdateStats(StatsContext statsContext) { if (mDataUsageRequests.size() == 0) { - if (LOGV) Slog.v(TAG, "No registered listeners of data usage"); return; } - if (LOGV) Slog.v(TAG, "Checking if any registered observer needs to be notified"); for (int i = 0; i < mDataUsageRequests.size(); i++) { RequestInfo requestInfo = mDataUsageRequests.valueAt(i); requestInfo.updateStats(statsContext); @@ -371,9 +369,6 @@ class NetworkStatsObservers { NetworkStats stats = mCollection.getSummary(template, Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, mAccessLevel, mCallingUid); - if (LOGV) { - Slog.v(TAG, "Netstats for " + template + ": " + stats); - } return stats.getTotalBytes(); } } @@ -391,11 +386,6 @@ class NetworkStatsObservers { for (int i = 0; i < uidsToMonitor.length; i++) { long bytesSoFar = getTotalBytesForNetworkUid(mRequest.template, uidsToMonitor[i]); - - if (LOGV) { - Slog.v(TAG, bytesSoFar + " bytes so far since notification for " - + mRequest.template + " for uid=" + uidsToMonitor[i]); - } if (bytesSoFar > mRequest.thresholdInBytes) { return true; } From ad683cadb293a97570ba1f31e64cf9c95bbb7d09 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 1 Jun 2016 17:51:28 -0700 Subject: [PATCH 0317/1150] IpConfigStore: Changes for parsing old wifi backup Some changes in IpConfigStore to parse old backup data. The old backup data contained a raw byte dump of the ipconfig.txt. So, make changes in IpConfigStore to parse the inputstream from backup data into IpConfiguration objects. Changes in the CL: 1. Make the |readIpAndProxyConfigurations| method static so that it can be used as a utility for parsing the backup data. 2. Create a new version of |readIpAndProxyConfigurations| method to accept an input stream parameter. 3. Make |writeConfig| method static so that it can be used for unit-testing the backup migration logic. BUG: 29075035 Change-Id: Ic074952d9f9ef143089a371e6c527470cb1c229c --- .../com/android/server/net/IpConfigStore.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 2807ec822b..4d56468f2f 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -27,6 +27,7 @@ import android.net.StaticIpConfiguration; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.net.DelayedDiskWrite; import java.io.BufferedInputStream; @@ -34,7 +35,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.net.InetAddress; import java.net.Inet4Address; @@ -67,7 +70,8 @@ public class IpConfigStore { this(new DelayedDiskWrite()); } - private boolean writeConfig(DataOutputStream out, int configKey, + @VisibleForTesting + public static boolean writeConfig(DataOutputStream out, int configKey, IpConfiguration config) throws IOException { boolean written = false; @@ -171,12 +175,25 @@ public class IpConfigStore { }); } - public SparseArray readIpAndProxyConfigurations(String filePath) { - SparseArray networks = new SparseArray(); + public static SparseArray readIpAndProxyConfigurations(String filePath) { + BufferedInputStream bufferedInputStream; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); + } catch (FileNotFoundException e) { + // Return an empty array here because callers expect an empty array when the file is + // not present. + loge("Error opening configuration file: " + e); + return new SparseArray<>(); + } + return readIpAndProxyConfigurations(bufferedInputStream); + } + public static SparseArray readIpAndProxyConfigurations( + InputStream inputStream) { + SparseArray networks = new SparseArray(); DataInputStream in = null; try { - in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); + in = new DataInputStream(inputStream); int version = in.readInt(); if (version != 2 && version != 1) { @@ -327,11 +344,11 @@ public class IpConfigStore { return networks; } - protected void loge(String s) { + protected static void loge(String s) { Log.e(TAG, s); } - protected void log(String s) { + protected static void log(String s) { Log.d(TAG, s); } } From 5065b30601928b98ec9973431e9c99db21f534b8 Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Wed, 15 Jun 2016 13:31:52 -0700 Subject: [PATCH 0318/1150] Fix runtime restart when using aggregated net observers. When observing network traffic on a per-iface basis (as opposed to a per-iface+uid basis), do not attempt to redistribute VPN traffic, because it is unnecessary and will lead to a crash further down the stack. This is a one-line functional change, but some comments have been added throughout to clarify behavior. Bug: 29390363 Change-Id: Icca13f181d7698ca3ddc92aa9248f06f130d49a3 --- .../com/android/server/net/NetworkStatsObservers.java | 8 +++++--- .../com/android/server/net/NetworkStatsRecorder.java | 8 +++++++- .../com/android/server/net/NetworkStatsService.java | 11 +++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index ea361700fa..3360584534 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -355,9 +355,10 @@ class NetworkStatsObservers { @Override protected void recordSample(StatsContext statsContext) { // Recorder does not need to be locked in this context since only the handler - // thread will update it + // thread will update it. We pass a null VPN array because usage is aggregated by uid + // for this snapshot, so VPN traffic can't be reattributed to responsible apps. mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, - statsContext.mVpnArray, statsContext.mCurrentTime); + null /* vpnArray */, statsContext.mCurrentTime); } /** @@ -396,7 +397,8 @@ class NetworkStatsObservers { @Override protected void recordSample(StatsContext statsContext) { // Recorder does not need to be locked in this context since only the handler - // thread will update it + // thread will update it. We pass the VPN info so VPN traffic is reattributed to + // responsible apps. mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, statsContext.mVpnArray, statsContext.mCurrentTime); } diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 04dc917ec3..090a0762a4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -22,6 +22,7 @@ import static android.net.TrafficStats.MB_IN_BYTES; import static android.text.format.DateUtils.YEAR_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.Nullable; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; @@ -199,9 +200,14 @@ public class NetworkStatsRecorder { * Record any delta that occurred since last {@link NetworkStats} snapshot, * using the given {@link Map} to identify network interfaces. First * snapshot is considered bootstrap, and is not counted as delta. + * + * @param vpnArray Optional info about the currently active VPN, if any. This is used to + * redistribute traffic from the VPN app to the underlying responsible apps. + * This should always be set to null if the provided snapshot is aggregated + * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state. */ public void recordSnapshotLocked(NetworkStats snapshot, - Map ifaceIdent, VpnInfo[] vpnArray, + Map ifaceIdent, @Nullable VpnInfo[] vpnArray, long currentTimeMillis) { final HashSet unknownIfaces = Sets.newHashSet(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 8610fa1b7b..23c111e56c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1009,9 +1009,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + + // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic + // can't be reattributed to responsible apps. + mDevRecorder.recordSnapshotLocked( + devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + mXtRecorder.recordSnapshotLocked( + xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + + // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); - mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, null, currentTime); - mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, null, currentTime); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); From 320e313d2ca2f1713f88cef153ab29b124cf3f92 Mon Sep 17 00:00:00 2001 From: Antonio Cansado Date: Mon, 20 Jun 2016 15:03:03 -0700 Subject: [PATCH 0319/1150] Fix infinite loop when registering data usage callback. Trivial fix is to call the method that takes the handler as a param. Bug: 29508547 Change-Id: I75ba30a1663be265eed56b24deda82e83fd47a43 --- core/java/android/app/usage/NetworkStatsManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 720c84a8e2..7961a72a12 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -305,7 +305,8 @@ public class NetworkStatsManager { */ public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback) { - registerUsageCallback(networkType, subscriberId, thresholdBytes, null /* handler */); + registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, + null /* handler */); } /** From e544a48eb24dcb1b6b8e4e85d00325c0eaf4b889 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Wed, 22 Jun 2016 11:35:10 -0700 Subject: [PATCH 0320/1150] Added a virtual interface for Video Telephony call usage counting 1. Added a virtual VT interface. 2. Qeury VT usage from telephony service. bug: 20888836 Change-Id: I3df0c22922f8394554230b53f8ae091e17c95595 --- .../server/net/NetworkStatsService.java | 64 ++++++++++++++++++- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 23c111e56c..4658c0463f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -31,6 +31,7 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; @@ -79,6 +80,7 @@ import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkInfo; import android.net.NetworkState; @@ -178,6 +180,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; + /** + * Virtual network interface for video telephony. This is for VT data usage counting purpose. + */ + public static final String VT_INTERFACE = "vt_data0"; + /** * Settings that can be changed externally. */ @@ -967,6 +974,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); + + // Build a separate virtual interface for VT (Video Telephony) data usage. + // Only do this when IMS is not metered, but VT is metered. + // If IMS is metered, then the IMS network usage has already included VT usage. + // VT is considered always metered in framework's layer. If VT is not metered + // per carrier's policy, modem will report 0 usage for VT calls. + if (state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { + + // Copy the identify from IMS one but mark it as metered. + NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), + ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), + ident.getRoaming(), true); + findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent); + } + if (isMobile) { mobileIfaces.add(baseIface); } @@ -1004,9 +1028,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to - // avoid overcounting dev stats. + // avoid over counting dev stats. final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + final NetworkStats xtSnapshot = getNetworkStatsXtAndVt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1311,6 +1335,42 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return uidSnapshot; } + /** + * Return snapshot of current XT plus VT statistics. + */ + private NetworkStats getNetworkStatsXtAndVt() throws RemoteException { + final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + + TelephonyManager tm = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + + long usage = tm.getVtDataUsage(); + + if (LOGV) Slog.d(TAG, "VT call data usage = " + usage); + + final NetworkStats vtSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 1); + + final NetworkStats.Entry entry = new NetworkStats.Entry(); + entry.iface = VT_INTERFACE; + entry.uid = -1; + entry.set = TAG_ALL; + entry.tag = TAG_NONE; + + // Since modem only tell us the total usage instead of each usage for RX and TX, + // we need to split it up (though it might not quite accurate). At + // least we can make sure the data usage report to the user will still be accurate. + entry.rxBytes = usage / 2; + entry.rxPackets = 0; + entry.txBytes = usage - entry.rxBytes; + entry.txPackets = 0; + vtSnapshot.combineValues(entry); + + // Merge VT int XT + xtSnapshot.combineAllValues(vtSnapshot); + + return xtSnapshot; + } + /** * Return snapshot of current tethering statistics. Will return empty * {@link NetworkStats} if any problems are encountered. From ab17d3a113b190aedf9282d4667cc39e130d3bd3 Mon Sep 17 00:00:00 2001 From: Daniel 2 Olofsson Date: Thu, 17 Jan 2013 12:05:34 +0100 Subject: [PATCH 0321/1150] Fix NativeDaemonConnectorException issue accessing null object When function getCode is called on NativeDaemonConnectorException object it may throw exception due to mEvent object not being set for certain constructors. Fix is to return a default error code as expected if mEvent object has not been set rather than trying to call mEvent.getCode(). Change-Id: Ia8aa23deb8871bb4df73096cc489b685a1765f16 --- .../java/com/android/server/NativeDaemonConnectorException.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnectorException.java b/services/core/java/com/android/server/NativeDaemonConnectorException.java index 590bbccdbc..4d8881c683 100644 --- a/services/core/java/com/android/server/NativeDaemonConnectorException.java +++ b/services/core/java/com/android/server/NativeDaemonConnectorException.java @@ -41,7 +41,7 @@ public class NativeDaemonConnectorException extends Exception { } public int getCode() { - return mEvent.getCode(); + return mEvent != null ? mEvent.getCode() : -1; } public String getCmd() { From bed14ecfc5c15c8c1229a3823e74b42308d2c226 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 May 2016 12:54:45 -0600 Subject: [PATCH 0322/1150] Avoid caching services with missing binders. When fetching system services early during boot, if the underlying binder interface hasn't been published yet, we end up caching a manager class that is broken for the remainder of the process lifetime, and innocent downstream callers end up using the broken cached manager. Fix this by using an explicit exception to quickly abort manager creation when the underlying binder is missing. The exception is only used to skip the remainder of the manager creation, and it doesn't actually crash the process. Bug: 28634953 Change-Id: I0cb62261e6d6833660704b93a11185aa11a2ac97 --- core/java/android/app/usage/NetworkStatsManager.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7961a72a12..e805fabc79 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,6 +34,7 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; /** @@ -95,10 +96,10 @@ public class NetworkStatsManager { /** * {@hide} */ - public NetworkStatsManager(Context context) { + public NetworkStatsManager(Context context) throws ServiceNotFoundException { mContext = context; mService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); } /** From 12255e3655823ed56d51baf75031dd6d125b598e Mon Sep 17 00:00:00 2001 From: Jeremy Joslin Date: Mon, 8 Aug 2016 16:07:37 -0700 Subject: [PATCH 0323/1150] VPN network stat accounting changes. Properly account for VPN apps that make heavy use of the tun interface. Prior to this change a VPN app could be incorrectly charged for more data than it actually used if it sent more traffic through the tun interface than the underlying interface. This change excludes VPN app traffic on the tun interface from the adjustment pool and doesn't redistribute traffic to the VPN app. Instead all of the redistributed traffic is deducted from the VPN app which effectively represents any overhead incurred by the VPN app. BUG: 30557871 Change-Id: I62a75a0c0c0111e052b7903baa9f5d6d94ef57fd --- core/java/android/net/NetworkStats.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25806fa776..f65a50f02d 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable { if (pool.isEmpty()) { return true; } - Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool); + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); deductTrafficFromVpnApp(tunUid, underlyingIface, moved); if (!moved.isEmpty()) { @@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable { * Initializes the data used by the migrateTun() method. * * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through tun0. - * (2) Adds up all the traffic through the tunUid's underlyingIface + * (1) Adds up all the traffic through the tunUid's underlyingIface * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry underlyingIfaceTotal) { @@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable { underlyingIfaceTotal.add(recycle); } - if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) { - // Add up all tunIface traffic. + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { + // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } @@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable { return pool; } - private Entry addTrafficToApplications(String tunIface, String underlyingIface, + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry pool) { Entry moved = new Entry(); Entry tmpEntry = new Entry(); tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (Objects.equals(iface[i], tunIface)) { + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { if (tunIfaceTotal.rxBytes > 0) { tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; } else { From 05cca1a4cb43d31da16430c797a776ffc91fccbe Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 23 Aug 2016 16:09:36 -0700 Subject: [PATCH 0324/1150] Do not print misleading debug messages in some scenarios. When the mobile network is not active, querying the network information might trigger the misleading debug messages. Added some condition checks to prevent this. bug: 30850733 Change-Id: Ice6d548a56f98bac7fe2ca6a06148350b505533d --- core/java/android/net/NetworkIdentity.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 9cd563e87c..d570e66a24 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -175,7 +175,11 @@ public class NetworkIdentity implements Comparable { if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { - Slog.w(TAG, "Active mobile network without subscriber!"); + if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED && + state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) { + Slog.w(TAG, "Active mobile network without subscriber! ni = " + + state.networkInfo); + } } subscriberId = state.subscriberId; From 88e33a286496ec643d0180e1026ded654cf2bb64 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Wed, 1 Jun 2016 17:51:28 -0700 Subject: [PATCH 0325/1150] IpConfigStore: Changes for parsing old wifi backup Some changes in IpConfigStore to parse old backup data. The old backup data contained a raw byte dump of the ipconfig.txt. So, make changes in IpConfigStore to parse the inputstream from backup data into IpConfiguration objects. Changes in the CL: 1. Make the |readIpAndProxyConfigurations| method static so that it can be used as a utility for parsing the backup data. 2. Create a new version of |readIpAndProxyConfigurations| method to accept an input stream parameter. 3. Make |writeConfig| method static so that it can be used for unit-testing the backup migration logic. BUG: 29075035 Change-Id: Ic074952d9f9ef143089a371e6c527470cb1c229c (cherry picked from commit ad683cadb293a97570ba1f31e64cf9c95bbb7d09) --- .../com/android/server/net/IpConfigStore.java | 29 +++++++++++++++---- 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 2807ec822b..4d56468f2f 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -27,6 +27,7 @@ import android.net.StaticIpConfiguration; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.net.DelayedDiskWrite; import java.io.BufferedInputStream; @@ -34,7 +35,9 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.EOFException; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.net.InetAddress; import java.net.Inet4Address; @@ -67,7 +70,8 @@ public class IpConfigStore { this(new DelayedDiskWrite()); } - private boolean writeConfig(DataOutputStream out, int configKey, + @VisibleForTesting + public static boolean writeConfig(DataOutputStream out, int configKey, IpConfiguration config) throws IOException { boolean written = false; @@ -171,12 +175,25 @@ public class IpConfigStore { }); } - public SparseArray readIpAndProxyConfigurations(String filePath) { - SparseArray networks = new SparseArray(); + public static SparseArray readIpAndProxyConfigurations(String filePath) { + BufferedInputStream bufferedInputStream; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); + } catch (FileNotFoundException e) { + // Return an empty array here because callers expect an empty array when the file is + // not present. + loge("Error opening configuration file: " + e); + return new SparseArray<>(); + } + return readIpAndProxyConfigurations(bufferedInputStream); + } + public static SparseArray readIpAndProxyConfigurations( + InputStream inputStream) { + SparseArray networks = new SparseArray(); DataInputStream in = null; try { - in = new DataInputStream(new BufferedInputStream(new FileInputStream(filePath))); + in = new DataInputStream(inputStream); int version = in.readInt(); if (version != 2 && version != 1) { @@ -327,11 +344,11 @@ public class IpConfigStore { return networks; } - protected void loge(String s) { + protected static void loge(String s) { Log.e(TAG, s); } - protected void log(String s) { + protected static void log(String s) { Log.d(TAG, s); } } From 218bfe7a33f584f06695847ec17570ef529b5fff Mon Sep 17 00:00:00 2001 From: Jeremy Joslin Date: Mon, 8 Aug 2016 16:07:37 -0700 Subject: [PATCH 0326/1150] VPN network stat accounting changes. Properly account for VPN apps that make heavy use of the tun interface. Prior to this change a VPN app could be incorrectly charged for more data than it actually used if it sent more traffic through the tun interface than the underlying interface. This change excludes VPN app traffic on the tun interface from the adjustment pool and doesn't redistribute traffic to the VPN app. Instead all of the redistributed traffic is deducted from the VPN app which effectively represents any overhead incurred by the VPN app. BUG: 30557871 Change-Id: I62a75a0c0c0111e052b7903baa9f5d6d94ef57fd --- core/java/android/net/NetworkStats.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25806fa776..f65a50f02d 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable { if (pool.isEmpty()) { return true; } - Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool); + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); deductTrafficFromVpnApp(tunUid, underlyingIface, moved); if (!moved.isEmpty()) { @@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable { * Initializes the data used by the migrateTun() method. * * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through tun0. - * (2) Adds up all the traffic through the tunUid's underlyingIface + * (1) Adds up all the traffic through the tunUid's underlyingIface * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry underlyingIfaceTotal) { @@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable { underlyingIfaceTotal.add(recycle); } - if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) { - // Add up all tunIface traffic. + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { + // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } @@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable { return pool; } - private Entry addTrafficToApplications(String tunIface, String underlyingIface, + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry pool) { Entry moved = new Entry(); Entry tmpEntry = new Entry(); tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (Objects.equals(iface[i], tunIface)) { + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { if (tunIfaceTotal.rxBytes > 0) { tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; } else { From ed7fcb4d26b56fef0d4d0f5139119b4e350996a4 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Tue, 18 Oct 2016 16:41:47 -0700 Subject: [PATCH 0327/1150] Define API for metering network stats buckets. This is a continuation of b/26545374, since now we can also set the metered bit with NetworkScorer. The tracking of metered state changes will be implemented in a seperate CL. Bug: 31015360 Bug: 26545374 Test: N/A Change-Id: I0eccd10c0316357abb03af4d9cf0c4191a66abfb --- core/java/android/app/usage/NetworkStats.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 226aa8f270..f64bec73e4 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -163,6 +163,29 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** @hide */ + @IntDef({METERED_ALL, METERED_NO, METERED_YES}) + @Retention(RetentionPolicy.SOURCE) + public @interface Metered {} + + /** + * Combined usage across all metered states. Covers metered and unmetered usage. + */ + public static final int METERED_ALL = -1; + + /** + * Usage that occurs on an unmetered network. + */ + public static final int METERED_NO = 0x1; + + /** + * Usage that occurs on a metered network. + * + *

      A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. + */ + public static final int METERED_YES = 0x2; + /** @hide */ @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) @Retention(RetentionPolicy.SOURCE) @@ -200,6 +223,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mMetered; private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; @@ -278,6 +302,21 @@ public final class NetworkStats implements AutoCloseable { return mState; } + /** + * Metered state. One of the following values:

      + *

        + *
      • {@link #METERED_ALL}
      • + *
      • {@link #METERED_NO}
      • + *
      • {@link #METERED_YES}
      • + *
      + *

      A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. Apps may warn before using these networks for large downloads. The + * metered state can be set by the user within data usage network restrictions. + */ + public @Metered int getMetered() { + return mMetered; + } + /** * Roaming state. One of the following values:

      *

        @@ -491,6 +530,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metered tracking. + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; @@ -539,6 +580,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + From 357f8fabc84b14ea3590d6b911ee5bf7b2256db7 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Fri, 21 Oct 2016 12:44:26 -0700 Subject: [PATCH 0328/1150] Implement metered tracking for NetworkStats summary queries. Dependent on ag/1550196 where API is defined. Bug: 31015360 Bug: 26545374 Test: runtest --path frameworks/base/core/tests/coretests/src/android/net/NetworkStatsTest.java, other test classes. Change-Id: I968b9e3352d7880e3fc438f12de628a2da057e0a --- core/java/android/app/usage/NetworkStats.java | 12 +- .../app/usage/NetworkStatsManager.java | 43 +++++--- core/java/android/net/NetworkIdentity.java | 6 +- core/java/android/net/NetworkStats.java | 103 ++++++++++++++---- ...droid_internal_net_NetworkStatsFactory.cpp | 8 +- .../server/net/NetworkIdentitySet.java | 13 +++ .../server/net/NetworkStatsCollection.java | 3 + 7 files changed, 139 insertions(+), 49 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4..3670b914ec 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index e805fabc79..da5aa61f1f 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -52,16 +52,17 @@ import android.util.Log; * {@link #querySummaryForUser}

        * {@link #querySummary}

        * These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state and roaming combination. In case of the user-wide and - * device-wide summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key, state, metered and roaming combination. In case of the user-wide + * and device-wide summaries a single bucket containing the totalised network usage is returned. *

        * History queries *

        * {@link #queryDetailsForUid}

        * {@link #queryDetails}

        - * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there - * can be multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * These queries do not aggregate over time but do aggregate over state, metered and roaming. + * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to + * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

        * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the @@ -104,10 +105,11 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This - * means the bucket's start and end timestamp are going to be the same as the 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp are going to be the same as the + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -143,8 +145,10 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -178,9 +182,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. - * State and uid are going to vary, and tag is going to be the same. + * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -263,10 +268,12 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. This means - * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be + * calling user. Result is aggregated over state but not aggregated over time, uid, tag, + * metered, nor roaming. This means buckets' start and end timestamps are going to be between + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

        Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d570e66a24..c704ef0c9c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; - boolean metered = false; + boolean metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -185,9 +186,6 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); - metered = !state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02d..77ce65b081 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 9fa90acc02..4a2b88142e 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID metered; jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; @@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW metered(env, get_int_array(env, stats, + gNetworkStatsClassInfo.metered, size, grow)); + if (metered.get() == NULL) return -1; ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; @@ -265,7 +269,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Roaming is populated in Java-land by inspecting the iface properties. + // Metered and Roaming are populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -279,6 +283,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); @@ -311,6 +316,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 959a823290..c48f43058f 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + public boolean isAnyMemberMetered() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getMetered()) { + return true; + } + } + return false; + } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ public boolean isAnyMemberRoaming() { if (isEmpty()) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 673dd8fbbd..c45b4169f5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; @@ -242,6 +244,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; From 4f1700dd160b41e0af83a3efc982dde0bd79c2b0 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Mon, 7 Nov 2016 11:31:24 -0800 Subject: [PATCH 0329/1150] Fix documentation for NetworkStatsManager methods. Test: N/A Change-Id: I054ce104e561ece8e414c7ddad718665e51a692e --- core/java/android/app/usage/NetworkStatsManager.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index da5aa61f1f..6cd4e92383 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -182,10 +182,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, - * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, - * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * end timestamps. Not aggregated over state, uid, metered, or roaming. This means buckets' + * start and end timestamps are going to be the same as the 'startTime' and 'endTime' + * parameters. State, uid, metered, and roaming are going to vary, and tag is going to be the + * same. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -231,7 +231,9 @@ public class NetworkStatsManager { * belonging to calling user. Result is aggregated over state but not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the - * same as the 'uid' parameter and tag the same as 'tag' parameter. + * same as the 'uid' parameter and tag the same as 'tag' parameter. metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be + * {@link NetworkStats.Bucket#ROAMING_ALL}. *

        Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. From cbd14a4f622d50565143fe2dff87081b41c29594 Mon Sep 17 00:00:00 2001 From: Sohani Rao Date: Thu, 29 Sep 2016 16:20:45 -0700 Subject: [PATCH 0330/1150] Permissions check for Wifi Display configuration Wifi Display is configured using the AIDL call setMiracastMode() and using a message over the async channel SET_WFD_INFO. Enforce permissions on the calling uid before updating the config Bug: 18668877 Test: Unit tests Change-Id: I0be2d2af49070aad759f24bd31331f7df39a0422 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index ee2e895af5..8b1cfaee81 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -28,5 +28,6 @@ interface IWifiP2pManager Messenger getMessenger(); Messenger getP2pStateMachineMessenger(); void setMiracastMode(int mode); + void checkConfigureWifiDisplayPermission(); } From e2667a9df69f6aae63c2885781b156e2c05b0ecc Mon Sep 17 00:00:00 2001 From: Sohani Rao Date: Thu, 29 Sep 2016 16:20:45 -0700 Subject: [PATCH 0331/1150] Permissions check for Wifi Display configuration Wifi Display is configured using the AIDL call setMiracastMode() and using a message over the async channel SET_WFD_INFO. Enforce permissions on the calling uid before updating the config Bug: 18668877 Test: Unit tests Change-Id: I0be2d2af49070aad759f24bd31331f7df39a0422 Merged-In: I0be2d2af49070aad759f24bd31331f7df39a0422 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index ee2e895af5..8b1cfaee81 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -28,5 +28,6 @@ interface IWifiP2pManager Messenger getMessenger(); Messenger getP2pStateMachineMessenger(); void setMiracastMode(int mode); + void checkConfigureWifiDisplayPermission(); } From 66dca17fe7752a071f53bd99787df647f8e4335c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 21 Nov 2016 12:14:50 -0700 Subject: [PATCH 0332/1150] StrictMode to detect untagged network traffic. Define some constants for early use in AOSP code. Test: builds, boots, all common traffic tagged Bug: 30943431 Change-Id: Ia58a8933bccfddbc027afb78c63ae65bd71ce562 --- core/java/android/net/TrafficStats.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 1ac9fca51b..e7436be273 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -108,6 +108,26 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; + /** @hide */ + public static final int TAG_SYSTEM_DHCP = 0xFFFFFF05; + /** @hide */ + public static final int TAG_SYSTEM_NTP = 0xFFFFFF06; + /** @hide */ + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF07; + /** @hide */ + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF08; + /** @hide */ + public static final int TAG_SYSTEM_GPS = 0xFFFFFF09; + /** @hide */ + public static final int TAG_SYSTEM_PAC = 0xFFFFFF0A; + + /** + * Sockets that are strictly local on device; never hits network. + * + * @hide + */ + public static final int TAG_SYSTEM_LOCAL = 0xFFFFFFAA; + private static INetworkStatsService sStatsService; private synchronized static INetworkStatsService getStatsService() { From 21c5c6fb0a00d1a90b464cf4b145de4579b05431 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Wed, 12 Oct 2016 14:21:51 -0700 Subject: [PATCH 0333/1150] Secure MATCH_UNINSTALLED_PACKAGES across users Introduce a new internal flag MATCH_ANY_USER for genuine uses of searching through all apps on the device. Some temporary accommodations for Launchers that reach across to the work profile until we have a new LauncherApps API to do that officially. Bug: 31000380 Test: CTS tests added Change-Id: I2e43dc49d6c2e11814a8f8d1eb07ef557f31af34 --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4658c0463f..8ca608693b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1212,7 +1212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Build list of UIDs that we should clean up int[] uids = new int[0]; final List apps = mContext.getPackageManager().getInstalledApplications( - PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS); + PackageManager.MATCH_ANY_USER + | PackageManager.MATCH_DISABLED_COMPONENTS); for (ApplicationInfo app : apps) { final int uid = UserHandle.getUid(userId, app.uid); uids = ArrayUtils.appendInt(uids, uid); From 2838d9bb56be242278719dd396829b4f391268b0 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 18 Apr 2016 16:23:06 -0700 Subject: [PATCH 0334/1150] DO NOT MERGE: Indicate the NsdServiceInfo attributes are only filled in for a resolved service. Fixes: 28530428 (cherry picked from commit 79a3c031a09ff02e1f22c87024ae220c32e04c6c) Change-Id: If2bfc06589adb361f11b89cd5923cb5c255cb680 --- core/java/android/net/nsd/NsdManager.java | 10 +++++----- core/java/android/net/nsd/NsdServiceInfo.java | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 86bd502826..33d12a3a3f 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -103,11 +103,11 @@ import com.android.internal.util.Protocol; * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on * {@link DiscoveryListener#onServiceLost}. * - *

        Once the peer application discovers the "Example" http srevice, and needs to receive data - * from the "Example" application, it can initiate a resolve with {@link #resolveService} to - * resolve the host and port details for the purpose of establishing a connection. A successful - * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified - * on {@link ResolveListener#onResolveFailed}. + *

        Once the peer application discovers the "Example" http service, and either needs to read the + * attributes of the service or wants to receive data from the "Example" application, it can + * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port + * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a + * failure is notified on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 4a06fb1220..7b845be749 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -250,7 +250,8 @@ public final class NsdServiceInfo implements Parcelable { } /** - * Retrive attributes as a map of String keys to byte[] values. + * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only + * valid for a resolved service. * *

        The returned map is unmodifiable; changes must be made through {@link #setAttribute} and * {@link #removeAttribute}. From b135f1d5a8147e0a0d6e1872e241ed4d599391bd Mon Sep 17 00:00:00 2001 From: Jeremy Joslin Date: Mon, 8 Aug 2016 16:07:37 -0700 Subject: [PATCH 0335/1150] DO NOT MERGE: VPN network stat accounting changes. Properly account for VPN apps that make heavy use of the tun interface. Prior to this change a VPN app could be incorrectly charged for more data than it actually used if it sent more traffic through the tun interface than the underlying interface. This change excludes VPN app traffic on the tun interface from the adjustment pool and doesn't redistribute traffic to the VPN app. Instead all of the redistributed traffic is deducted from the VPN app which effectively represents any overhead incurred by the VPN app. BUG: 30557871 (cherry picked from commit 12255e3655823ed56d51baf75031dd6d125b598e) Change-Id: I06f01aa8fe5fdc06b2d36cfb9c68feb244c2e5de --- core/java/android/net/NetworkStats.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 25806fa776..f65a50f02d 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -904,7 +904,8 @@ public class NetworkStats implements Parcelable { if (pool.isEmpty()) { return true; } - Entry moved = addTrafficToApplications(tunIface, underlyingIface, tunIfaceTotal, pool); + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); deductTrafficFromVpnApp(tunUid, underlyingIface, moved); if (!moved.isEmpty()) { @@ -919,9 +920,9 @@ public class NetworkStats implements Parcelable { * Initializes the data used by the migrateTun() method. * * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through tun0. - * (2) Adds up all the traffic through the tunUid's underlyingIface + * (1) Adds up all the traffic through the tunUid's underlyingIface * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry underlyingIfaceTotal) { @@ -941,8 +942,9 @@ public class NetworkStats implements Parcelable { underlyingIfaceTotal.add(recycle); } - if (recycle.tag == TAG_NONE && Objects.equals(tunIface, recycle.iface)) { - // Add up all tunIface traffic. + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { + // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } @@ -958,13 +960,15 @@ public class NetworkStats implements Parcelable { return pool; } - private Entry addTrafficToApplications(String tunIface, String underlyingIface, + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, Entry tunIfaceTotal, Entry pool) { Entry moved = new Entry(); Entry tmpEntry = new Entry(); tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (Objects.equals(iface[i], tunIface)) { + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { if (tunIfaceTotal.rxBytes > 0) { tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; } else { From ebace400924d9f1f2b6c72fbc65fb90efa13b354 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Tue, 18 Oct 2016 16:41:47 -0700 Subject: [PATCH 0336/1150] DO NOT MERGE: Define API for metering network stats buckets. This is a continuation of b/26545374, since now we can also set the metered bit with NetworkScorer. The tracking of metered state changes will be implemented in a seperate CL. Bug: 31015360 Bug: 26545374 Test: N/A (cherry picked from commit ed7fcb4d26b56fef0d4d0f5139119b4e350996a4) Change-Id: I6a2fcc8577d62daa8823dff9e0128a5cf39ede7b --- core/java/android/app/usage/NetworkStats.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 226aa8f270..f64bec73e4 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -163,6 +163,29 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** @hide */ + @IntDef({METERED_ALL, METERED_NO, METERED_YES}) + @Retention(RetentionPolicy.SOURCE) + public @interface Metered {} + + /** + * Combined usage across all metered states. Covers metered and unmetered usage. + */ + public static final int METERED_ALL = -1; + + /** + * Usage that occurs on an unmetered network. + */ + public static final int METERED_NO = 0x1; + + /** + * Usage that occurs on a metered network. + * + *

        A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. + */ + public static final int METERED_YES = 0x2; + /** @hide */ @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) @Retention(RetentionPolicy.SOURCE) @@ -200,6 +223,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mMetered; private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; @@ -278,6 +302,21 @@ public final class NetworkStats implements AutoCloseable { return mState; } + /** + * Metered state. One of the following values:

        + *

          + *
        • {@link #METERED_ALL}
        • + *
        • {@link #METERED_NO}
        • + *
        • {@link #METERED_YES}
        • + *
        + *

        A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. Apps may warn before using these networks for large downloads. The + * metered state can be set by the user within data usage network restrictions. + */ + public @Metered int getMetered() { + return mMetered; + } + /** * Roaming state. One of the following values:

        *

          @@ -491,6 +530,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metered tracking. + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; @@ -539,6 +580,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + From 92b61750693eb16eeafd97ad98d39b84541cc360 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Fri, 21 Oct 2016 12:44:26 -0700 Subject: [PATCH 0337/1150] DO NOT MERGE: Implement metered tracking for NetworkStats summary queries. Dependent on ag/1550196 where API is defined. Bug: 31015360 Bug: 26545374 Test: runtest --path frameworks/base/core/tests/coretests/src/android/net/NetworkStatsTest.java, other test classes. (cherry picked from commit 357f8fabc84b14ea3590d6b911ee5bf7b2256db7) Change-Id: I46da93ba4afa968facf98f7c3d844fd0c469095a --- core/java/android/app/usage/NetworkStats.java | 12 +- .../app/usage/NetworkStatsManager.java | 43 +++++--- core/java/android/net/NetworkIdentity.java | 6 +- core/java/android/net/NetworkStats.java | 103 ++++++++++++++---- ...droid_internal_net_NetworkStatsFactory.cpp | 8 +- .../server/net/NetworkIdentitySet.java | 13 +++ .../server/net/NetworkStatsCollection.java | 3 + 7 files changed, 139 insertions(+), 49 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4..3670b914ec 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7961a72a12..840413a115 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -51,16 +51,17 @@ import android.util.Log; * {@link #querySummaryForUser}

          * {@link #querySummary}

          * These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state and roaming combination. In case of the user-wide and - * device-wide summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key, state, metered and roaming combination. In case of the user-wide + * and device-wide summaries a single bucket containing the totalised network usage is returned. *

          * History queries *

          * {@link #queryDetailsForUid}

          * {@link #queryDetails}

          - * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there - * can be multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * These queries do not aggregate over time but do aggregate over state, metered and roaming. + * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to + * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

          * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the @@ -103,10 +104,11 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This - * means the bucket's start and end timestamp are going to be the same as the 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp are going to be the same as the + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -142,8 +144,10 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -177,9 +181,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. - * State and uid are going to vary, and tag is going to be the same. + * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -262,10 +267,12 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. This means - * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be + * calling user. Result is aggregated over state but not aggregated over time, uid, tag, + * metered, nor roaming. This means buckets' start and end timestamps are going to be between + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

          Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d570e66a24..c704ef0c9c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; - boolean metered = false; + boolean metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -185,9 +186,6 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); - metered = !state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02d..77ce65b081 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 9fa90acc02..4a2b88142e 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID metered; jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; @@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW metered(env, get_int_array(env, stats, + gNetworkStatsClassInfo.metered, size, grow)); + if (metered.get() == NULL) return -1; ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; @@ -265,7 +269,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Roaming is populated in Java-land by inspecting the iface properties. + // Metered and Roaming are populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -279,6 +283,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); @@ -311,6 +316,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 959a823290..c48f43058f 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + public boolean isAnyMemberMetered() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getMetered()) { + return true; + } + } + return false; + } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ public boolean isAnyMemberRoaming() { if (isEmpty()) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 673dd8fbbd..c45b4169f5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; @@ -242,6 +244,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; From ed23aa6ca4c102e85b467fa4ec71a7829e678781 Mon Sep 17 00:00:00 2001 From: Jeff Davidson Date: Mon, 12 Dec 2016 11:55:37 -0800 Subject: [PATCH 0338/1150] Add Log.wtf when getSummaryForAllUid NPEs. This will provide stack trace information from the system process which should enable us to more easily track down where the crash is occurring. Test: Builds locally Bug: 33427276 Change-Id: I584a568fc038771afb28a534e2eefe2f763ed5e1 --- .../server/net/NetworkStatsService.java | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4658c0463f..e2e74e904a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -553,15 +553,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - final NetworkStats stats = - getUidComplete().getSummary(template, start, end, accessLevel); - if (includeTags) { - final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, accessLevel); - stats.combineAllValues(tagStats); + try { + @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + final NetworkStats stats = + getUidComplete().getSummary(template, start, end, accessLevel); + if (includeTags) { + final NetworkStats tagStats = getUidTagComplete() + .getSummary(template, start, end, accessLevel); + stats.combineAllValues(tagStats); + } + return stats; + } catch (NullPointerException e) { + // TODO: Track down and fix the cause of this crash and remove this catch block. + Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e); + throw e; } - return stats; } @Override From feb5df98146ef7be03f5704c7976f1a49dbccd9b Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Fri, 13 Jan 2017 10:23:30 -0800 Subject: [PATCH 0339/1150] Support protofied dumpsys for NetStats Bug 34228873 Test: manual tests with "incident_report netstats" Change-Id: I359b364c64d9798fd4229018a905658d5d46ea5c --- core/java/android/net/NetworkIdentity.java | 19 ++++++++++ .../java/android/net/NetworkStatsHistory.java | 30 ++++++++++++++++ .../server/net/NetworkIdentitySet.java | 12 +++++++ .../server/net/NetworkStatsCollection.java | 34 ++++++++++++++++-- .../server/net/NetworkStatsRecorder.java | 11 ++++++ .../server/net/NetworkStatsService.java | 36 +++++++++++++++++++ 6 files changed, 140 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index c704ef0c9c..0775bdaaf3 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -24,8 +24,10 @@ import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; +import android.service.NetworkIdentityProto; import android.telephony.TelephonyManager; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import java.util.Objects; @@ -110,6 +112,23 @@ public class NetworkIdentity implements Comparable { return builder.append("}").toString(); } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + proto.write(NetworkIdentityProto.TYPE, mType); + + // Not dumping mSubType, subtypes are no longer supported. + + if (mSubscriberId != null) { + proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId)); + } + proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); + proto.write(NetworkIdentityProto.ROAMING, mRoaming); + proto.write(NetworkIdentityProto.METERED, mMetered); + + proto.end(start); + } + public int getType() { return mType; } diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 4a4accbba5..5f521de63c 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -31,7 +31,10 @@ import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; import android.os.Parcelable; +import android.service.NetworkStatsHistoryBucketProto; +import android.service.NetworkStatsHistoryProto; import android.util.MathUtils; +import android.util.proto.ProtoOutputStream; import com.android.internal.util.IndentingPrintWriter; @@ -628,6 +631,33 @@ public class NetworkStatsHistory implements Parcelable { } } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + + for (int i = 0; i < bucketCount; i++) { + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); + + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); + writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); + writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); + writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); + writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); + writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); + + proto.end(startBucket); + } + + proto.end(start); + } + + private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) { + if (array != null) { + proto.write(tag, array[index]); + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index c48f43058f..ee00fdc333 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -17,6 +17,8 @@ package com.android.server.net; import android.net.NetworkIdentity; +import android.service.NetworkIdentitySetProto; +import android.util.proto.ProtoOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -143,4 +145,14 @@ public class NetworkIdentitySet extends HashSet implements final NetworkIdentity anotherIdent = another.iterator().next(); return ident.compareTo(anotherIdent); } + + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + for (NetworkIdentity ident : this) { + ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES); + } + + proto.end(start); + } } diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index c45b4169f5..03543007c8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -34,9 +34,13 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.Binder; +import android.service.NetworkStatsCollectionKeyProto; +import android.service.NetworkStatsCollectionProto; +import android.service.NetworkStatsCollectionStatsProto; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; +import android.util.proto.ProtoOutputStream; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; @@ -532,12 +536,15 @@ public class NetworkStatsCollection implements FileRotator.Reader { / mBucketDuration); } - public void dump(IndentingPrintWriter pw) { + private ArrayList getSortedKeys() { final ArrayList keys = Lists.newArrayList(); keys.addAll(mStats.keySet()); Collections.sort(keys); + return keys; + } - for (Key key : keys) { + public void dump(IndentingPrintWriter pw) { + for (Key key : getSortedKeys()) { pw.print("ident="); pw.print(key.ident.toString()); pw.print(" uid="); pw.print(key.uid); pw.print(" set="); pw.print(NetworkStats.setToString(key.set)); @@ -550,6 +557,29 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + public void writeToProto(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + + for (Key key : getSortedKeys()) { + final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + + // Key + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); + key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY); + proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + proto.end(startKey); + + // Value + final NetworkStatsHistory history = mStats.get(key); + history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY); + proto.end(startStats); + } + + proto.end(start); + } + public void dumpCheckin(PrintWriter pw, long start, long end) { dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 090a0762a4..80309e19eb 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -29,9 +29,11 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.DropBoxManager; +import android.service.NetworkStatsRecorderProto; import android.util.Log; import android.util.MathUtils; import android.util.Slog; +import android.util.proto.ProtoOutputStream; import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; @@ -465,6 +467,15 @@ public class NetworkStatsRecorder { } } + public void writeToProtoLocked(ProtoOutputStream proto, long tag) { + final long start = proto.start(tag); + if (mPending != null) { + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); + } + getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + proto.end(start); + } + public void dumpCheckin(PrintWriter pw, long start, long end) { // Only load and dump stats from the requested window getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 386e78b518..104c29619c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -104,6 +104,8 @@ import android.os.SystemClock; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; +import android.service.NetworkInterfaceProto; +import android.service.NetworkStatsServiceDumpProto; import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -115,6 +117,7 @@ import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; import android.util.TrustedTime; +import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnInfo; @@ -1255,6 +1258,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, " "); synchronized (mStatsLock) { + if (args.length > 0 && "--proto".equals(args[0])) { + // In this case ignore all other arguments. + dumpProto(fd); + return; + } + if (poll) { performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE); pw.println("Forced poll"); @@ -1327,6 +1336,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private void dumpProto(FileDescriptor fd) { + final ProtoOutputStream proto = new ProtoOutputStream(fd); + + // TODO Right now it writes all history. Should it limit to the "since-boot" log? + + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); + mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); + mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); + mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); + mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + + proto.flush(); + } + + private static void dumpInterfaces(ProtoOutputStream proto, long tag, + ArrayMap ifaces) { + for (int i = 0; i < ifaces.size(); i++) { + final long start = proto.start(tag); + + proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); + ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES); + + proto.end(start); + } + } + /** * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. From 8ad38f0f6c161a01495735aa1c77cc80b383f688 Mon Sep 17 00:00:00 2001 From: "Philip P. Moltmann" Date: Mon, 18 Apr 2016 16:23:06 -0700 Subject: [PATCH 0340/1150] DO NOT MERGE: Indicate the NsdServiceInfo attributes are only filled in for a resolved service. Fixes: 28530428 (cherry picked from commit 79a3c031a09ff02e1f22c87024ae220c32e04c6c) (cherry picked from commit 2838d9bb56be242278719dd396829b4f391268b0) Change-Id: Ib8f8da947af804c8b203928e57ed6a8aedbf0684 --- core/java/android/net/nsd/NsdManager.java | 10 +++++----- core/java/android/net/nsd/NsdServiceInfo.java | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 86bd502826..33d12a3a3f 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -103,11 +103,11 @@ import com.android.internal.util.Protocol; * to {@link DiscoveryListener#onServiceFound} and a service lost is notified on * {@link DiscoveryListener#onServiceLost}. * - *

          Once the peer application discovers the "Example" http srevice, and needs to receive data - * from the "Example" application, it can initiate a resolve with {@link #resolveService} to - * resolve the host and port details for the purpose of establishing a connection. A successful - * resolve is notified on {@link ResolveListener#onServiceResolved} and a failure is notified - * on {@link ResolveListener#onResolveFailed}. + *

          Once the peer application discovers the "Example" http service, and either needs to read the + * attributes of the service or wants to receive data from the "Example" application, it can + * initiate a resolve with {@link #resolveService} to resolve the attributes, host, and port + * details. A successful resolve is notified on {@link ResolveListener#onServiceResolved} and a + * failure is notified on {@link ResolveListener#onResolveFailed}. * * Applications can reserve for a service type at * http://www.iana.org/form/ports-service. Existing services can be found at diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 4a06fb1220..7b845be749 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -250,7 +250,8 @@ public final class NsdServiceInfo implements Parcelable { } /** - * Retrive attributes as a map of String keys to byte[] values. + * Retrieve attributes as a map of String keys to byte[] values. The attributes map is only + * valid for a resolved service. * *

          The returned map is unmodifiable; changes must be made through {@link #setAttribute} and * {@link #removeAttribute}. From 88b52b25f728a79e666c9c166e7e3120e6f78f36 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Tue, 18 Oct 2016 16:41:47 -0700 Subject: [PATCH 0341/1150] DO NOT MERGE: Define API for metering network stats buckets. This is a continuation of b/26545374, since now we can also set the metered bit with NetworkScorer. The tracking of metered state changes will be implemented in a seperate CL. Bug: 31015360 Bug: 26545374 Test: N/A (cherry picked from commit ed7fcb4d26b56fef0d4d0f5139119b4e350996a4) (cherry picked from commit ebace400924d9f1f2b6c72fbc65fb90efa13b354) Change-Id: I01ebb270c5bf7f2383e8923cce72545ca1bee118 --- core/java/android/app/usage/NetworkStats.java | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 226aa8f270..f64bec73e4 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -163,6 +163,29 @@ public final class NetworkStats implements AutoCloseable { */ public static final int UID_TETHERING = TrafficStats.UID_TETHERING; + /** @hide */ + @IntDef({METERED_ALL, METERED_NO, METERED_YES}) + @Retention(RetentionPolicy.SOURCE) + public @interface Metered {} + + /** + * Combined usage across all metered states. Covers metered and unmetered usage. + */ + public static final int METERED_ALL = -1; + + /** + * Usage that occurs on an unmetered network. + */ + public static final int METERED_NO = 0x1; + + /** + * Usage that occurs on a metered network. + * + *

          A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. + */ + public static final int METERED_YES = 0x2; + /** @hide */ @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) @Retention(RetentionPolicy.SOURCE) @@ -200,6 +223,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mMetered; private int mRoaming; private long mBeginTimeStamp; private long mEndTimeStamp; @@ -278,6 +302,21 @@ public final class NetworkStats implements AutoCloseable { return mState; } + /** + * Metered state. One of the following values:

          + *

            + *
          • {@link #METERED_ALL}
          • + *
          • {@link #METERED_NO}
          • + *
          • {@link #METERED_YES}
          • + *
          + *

          A network is classified as metered when the user is sensitive to heavy data usage on + * that connection. Apps may warn before using these networks for large downloads. The + * metered state can be set by the user within data usage network restrictions. + */ + public @Metered int getMetered() { + return mMetered; + } + /** * Roaming state. One of the following values:

          *

            @@ -491,6 +530,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + // TODO: Implement metered tracking. + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; @@ -539,6 +580,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; bucketOut.mEndTimeStamp = mRecycledHistoryEntry.bucketStart + From f57c4def50cb4e8702f87ea0e4c62446f2ef6433 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Fri, 21 Oct 2016 12:44:26 -0700 Subject: [PATCH 0342/1150] DO NOT MERGE: Implement metered tracking for NetworkStats summary queries. Dependent on ag/1550196 where API is defined. Bug: 31015360 Bug: 26545374 Test: runtest --path frameworks/base/core/tests/coretests/src/android/net/NetworkStatsTest.java, other test classes. (cherry picked from commit 357f8fabc84b14ea3590d6b911ee5bf7b2256db7) (cherry picked from commit 92b61750693eb16eeafd97ad98d39b84541cc360) Change-Id: I79e401fc4159264a075febba82bd8c295b8e677f --- core/java/android/app/usage/NetworkStats.java | 12 +- .../app/usage/NetworkStatsManager.java | 43 +++++--- core/java/android/net/NetworkIdentity.java | 6 +- core/java/android/net/NetworkStats.java | 103 ++++++++++++++---- ...droid_internal_net_NetworkStatsFactory.cpp | 8 +- .../server/net/NetworkIdentitySet.java | 13 +++ .../server/net/NetworkStatsCollection.java | 3 + 7 files changed, 139 insertions(+), 49 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4..3670b914ec 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7961a72a12..840413a115 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -51,16 +51,17 @@ import android.util.Log; * {@link #querySummaryForUser}

            * {@link #querySummary}

            * These queries aggregate network usage across the whole interval. Therefore there will be only one - * bucket for a particular key and state and roaming combination. In case of the user-wide and - * device-wide summaries a single bucket containing the totalised network usage is returned. + * bucket for a particular key, state, metered and roaming combination. In case of the user-wide + * and device-wide summaries a single bucket containing the totalised network usage is returned. *

            * History queries *

            * {@link #queryDetailsForUid}

            * {@link #queryDetails}

            - * These queries do not aggregate over time but do aggregate over state and roaming. Therefore there - * can be multiple buckets for a particular key but all Bucket's state is going to be - * {@link NetworkStats.Bucket#STATE_ALL} and all Bucket's roaming is going to be + * These queries do not aggregate over time but do aggregate over state, metered and roaming. + * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to + * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

            * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the @@ -103,10 +104,11 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result is summarised data usage for the whole - * device. Result is a single Bucket aggregated over time, state, uid, tag and roaming. This - * means the bucket's start and end timestamp are going to be the same as the 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid - * {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE} + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp are going to be the same as the + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -142,8 +144,10 @@ public class NetworkStatsManager { * Query network usage statistics summaries. Result is summarised data usage for all uids * belonging to calling user. Result is a single Bucket aggregated over time, state and uid. * This means the bucket's start and end timestamp are going to be the same as the 'startTime' - * and 'endTime' parameters, state is going to be {@link NetworkStats.Bucket#STATE_ALL} and uid - * {@link NetworkStats.Bucket#UID_ALL}. + * and 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -177,9 +181,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state or uid. This means buckets' start and end - * timestamps are going to be the same as the 'startTime' and 'endTime' parameters. - * State and uid are going to vary, and tag is going to be the same. + * end timestamps. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, + * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming + * {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -262,10 +267,12 @@ public class NetworkStatsManager { /** * Query network usage statistics details. Result filtered to include only uids belonging to - * calling user. Result is aggregated over state but not aggregated over time or uid. This means - * buckets' start and end timestamps are going to be between 'startTime' and 'endTime' - * parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE} and roaming is going to be + * calling user. Result is aggregated over state but not aggregated over time, uid, tag, + * metered, nor roaming. This means buckets' start and end timestamps are going to be between + * 'startTime' and 'endTime' parameters. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, + * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be + * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be * {@link NetworkStats.Bucket#ROAMING_ALL}. *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d570e66a24..c704ef0c9c 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -171,7 +171,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; boolean roaming = false; - boolean metered = false; + boolean metered = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED); if (isNetworkTypeMobile(type)) { if (state.subscriberId == null) { @@ -185,9 +186,6 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; roaming = state.networkInfo.isRoaming(); - metered = !state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - } else if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02d..77ce65b081 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 9fa90acc02..4a2b88142e 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -43,6 +43,7 @@ static struct { jfieldID uid; jfieldID set; jfieldID tag; + jfieldID metered; jfieldID roaming; jfieldID rxBytes; jfieldID rxPackets; @@ -239,6 +240,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW tag(env, get_int_array(env, stats, gNetworkStatsClassInfo.tag, size, grow)); if (tag.get() == NULL) return -1; + ScopedIntArrayRW metered(env, get_int_array(env, stats, + gNetworkStatsClassInfo.metered, size, grow)); + if (metered.get() == NULL) return -1; ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; @@ -265,7 +269,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Roaming is populated in Java-land by inspecting the iface properties. + // Metered and Roaming are populated in Java-land by inspecting the iface properties. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -279,6 +283,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.uid, uid.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.set, set.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); @@ -311,6 +316,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 959a823290..c48f43058f 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -91,6 +91,19 @@ public class NetworkIdentitySet extends HashSet implements } } + /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + public boolean isAnyMemberMetered() { + if (isEmpty()) { + return false; + } + for (NetworkIdentity ident : this) { + if (ident.getMetered()) { + return true; + } + } + return false; + } + /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ public boolean isAnyMemberRoaming() { if (isEmpty()) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 673dd8fbbd..c45b4169f5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,8 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.NetworkStats.SET_ALL; @@ -242,6 +244,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; entry.rxPackets = historyEntry.rxPackets; From 289eac11a25a477be60cb5efdb986038db133ff9 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 19 Jan 2017 11:55:54 -0700 Subject: [PATCH 0343/1150] StrictMode to detect untagged network traffic. Network usage is tracked by the kernel at the UID level, which is granular enough for normal apps, but large components (such as the system server) are impossible to debug without adding additional socket tagging to help identify subsystems within a UID. To help ensure that system components tag all their network traffic, this change offers a new StrictMode option to detect and report untagged sockets. Test: builds, boots, all common traffic tagged Bug: 30943431, 30414041 Change-Id: I825c7941076054732264690247de2863342638e2 --- core/java/android/net/TrafficStats.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7436be273..fc66395bcd 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -166,6 +166,24 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); } + /** + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. Only one active tag per thread is supported. + *

            + * Changes only take effect during subsequent calls to + * {@link #tagSocket(Socket)}. + *

            + * Tags between {@code 0xFFFFFF00} and {@code 0xFFFFFFFF} are reserved and + * used internally by system services like {@link DownloadManager} when + * performing traffic on behalf of an application. + * + * @return the current tag for the calling thread, which can be used to + * restore any existing values after a nested operation is finished + */ + public static int getAndSetThreadStatsTag(int tag) { + return NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + } + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. The tag used internally is well-defined to From 921f6f6797e630af87e8768765eb205776d70237 Mon Sep 17 00:00:00 2001 From: Jeremy Joslin Date: Mon, 8 Aug 2016 16:07:37 -0700 Subject: [PATCH 0344/1150] VPN network stat accounting changes. Properly account for VPN apps that make heavy use of the tun interface. Prior to this change a VPN app could be incorrectly charged for more data than it actually used if it sent more traffic through the tun interface than the underlying interface. This change excludes VPN app traffic on the tun interface from the adjustment pool and doesn't redistribute traffic to the VPN app. Instead all of the redistributed traffic is deducted from the VPN app which effectively represents any overhead incurred by the VPN app. BUG: 30557871 (cherry picked from commit 12255e3655823ed56d51baf75031dd6d125b598e) Change-Id: I06f01aa8fe5fdc06b2d36cfb9c68feb244c2e5de --- core/java/android/net/NetworkStats.java | 103 ++++++------------------ 1 file changed, 24 insertions(+), 79 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 77ce65b081..f65a50f02d 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,18 +68,11 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #metered} value to account for all metered states. */ - public static final int METERED_ALL = -1; - /** {@link #metered} value where native, unmetered data is accounted. */ - public static final int METERED_NO = 0; - /** {@link #metered} value where metered data is accounted. */ - public static final int METERED_YES = 1; - - /** {@link #roaming} value to account for all roaming states. */ + /** {@link #set} value for all roaming values. */ public static final int ROAMING_ALL = -1; - /** {@link #roaming} value where native, non-roaming data is accounted. */ + /** {@link #set} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #roaming} value where roaming data is accounted. */ + /** {@link #set} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -95,7 +88,6 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; - private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -108,12 +100,6 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; - /** - * Note that this is only populated w/ the default value when read from /proc or written - * to disk. We merge in the correct value when reporting this value to clients of - * getSummary(). - */ - public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -137,17 +123,16 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, - txPackets, operations); + this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, + operations); } - public Entry(String iface, int uid, int set, int tag, int metered, int roaming, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, + long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; - this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -180,7 +165,6 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); - builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -194,18 +178,13 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered - && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets - && txBytes == e.txBytes && txPackets == e.txPackets - && operations == e.operations && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming + && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes + && txPackets == e.txPackets && operations == e.operations + && iface.equals(e.iface); } return false; } - - @Override - public int hashCode() { - return Objects.hash(uid, set, tag, metered, roaming, iface); - } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -217,7 +196,6 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; - this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -231,7 +209,6 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; - this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -249,7 +226,6 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); - metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -267,7 +243,6 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); - dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -302,11 +277,10 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, - operations)); + iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @@ -320,7 +294,6 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); - metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -334,7 +307,6 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; - metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -355,7 +327,6 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; - entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -410,8 +381,7 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, - entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -439,11 +409,10 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && Objects.equals(iface, this.iface[i])) { + && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { return i; } } @@ -455,7 +424,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -469,8 +438,7 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && metered == this.metered[i] && roaming == this.roaming[i] - && Objects.equals(iface, this.iface[i])) { + && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { return i; } } @@ -484,7 +452,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -574,7 +542,6 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; - entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -670,12 +637,11 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; - entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.metered, entry.roaming, i); + entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -721,7 +687,6 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; - entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -751,7 +716,6 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; - entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -798,7 +762,6 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); - pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -866,22 +829,6 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } - /** - * Return text description of {@link #metered} value. - */ - public static String meteredToString(int metered) { - switch (metered) { - case METERED_ALL: - return "ALL"; - case METERED_NO: - return "NO"; - case METERED_YES: - return "YES"; - default: - return "UNKNOWN"; - } - } - /** * Return text description of {@link #roaming} value. */ @@ -1051,7 +998,6 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; - tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1071,25 +1017,24 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; - moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, - // which should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO, which + // should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO); + ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO); + ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } From a471b1647eb06a8a0f1745b06b9714877c3605a8 Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Tue, 18 Oct 2016 16:41:47 -0700 Subject: [PATCH 0345/1150] Define API for metering network stats buckets. This is a continuation of b/26545374, since now we can also set the metered bit with NetworkScorer. The tracking of metered state changes will be implemented in a seperate CL. Bug: 31015360 Bug: 26545374 Test: N/A (cherry picked from commit ed7fcb4d26b56fef0d4d0f5139119b4e350996a4) Change-Id: I6a2fcc8577d62daa8823dff9e0128a5cf39ede7b --- core/java/android/app/usage/NetworkStats.java | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 3670b914ec..f64bec73e4 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,15 +256,6 @@ public final class NetworkStats implements AutoCloseable { return tag; } - private static @Metered int convertMetered(int metered) { - switch (metered) { - case android.net.NetworkStats.METERED_ALL : return METERED_ALL; - case android.net.NetworkStats.METERED_NO: return METERED_NO; - case android.net.NetworkStats.METERED_YES: return METERED_YES; - } - return 0; - } - private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -539,7 +530,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); + // TODO: Implement metered tracking. + bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; From 29a9cf2250e0eaed062fd0f990a04b923896279b Mon Sep 17 00:00:00 2001 From: Stephen Chen Date: Fri, 21 Oct 2016 12:44:26 -0700 Subject: [PATCH 0346/1150] Implement metered tracking for NetworkStats summary queries. Dependent on ag/1550196 where API is defined. Bug: 31015360 Bug: 26545374 Test: runtest --path frameworks/base/core/tests/coretests/src/android/net/NetworkStatsTest.java, other test classes. (cherry picked from commit 357f8fabc84b14ea3590d6b911ee5bf7b2256db7) Change-Id: I46da93ba4afa968facf98f7c3d844fd0c469095a --- core/java/android/app/usage/NetworkStats.java | 12 +- core/java/android/net/NetworkStats.java | 103 ++++++++++++++---- 2 files changed, 89 insertions(+), 26 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index f64bec73e4..3670b914ec 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -256,6 +256,15 @@ public final class NetworkStats implements AutoCloseable { return tag; } + private static @Metered int convertMetered(int metered) { + switch (metered) { + case android.net.NetworkStats.METERED_ALL : return METERED_ALL; + case android.net.NetworkStats.METERED_NO: return METERED_NO; + case android.net.NetworkStats.METERED_YES: return METERED_YES; + } + return 0; + } + private static @Roaming int convertRoaming(int roaming) { switch (roaming) { case android.net.NetworkStats.ROAMING_ALL : return ROAMING_ALL; @@ -530,8 +539,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - // TODO: Implement metered tracking. - bucketOut.mMetered = Bucket.METERED_ALL; + bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; bucketOut.mEndTimeStamp = mEndTimeStamp; diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f65a50f02d..77ce65b081 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -68,11 +68,18 @@ public class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** {@link #set} value for all roaming values. */ + /** {@link #metered} value to account for all metered states. */ + public static final int METERED_ALL = -1; + /** {@link #metered} value where native, unmetered data is accounted. */ + public static final int METERED_NO = 0; + /** {@link #metered} value where metered data is accounted. */ + public static final int METERED_YES = 1; + + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; - /** {@link #set} value where native, non-roaming data is accounted. */ + /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; - /** {@link #set} value where roaming data is accounted. */ + /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; // TODO: move fields to "mVariable" notation @@ -88,6 +95,7 @@ public class NetworkStats implements Parcelable { private int[] uid; private int[] set; private int[] tag; + private int[] metered; private int[] roaming; private long[] rxBytes; private long[] rxPackets; @@ -100,6 +108,12 @@ public class NetworkStats implements Parcelable { public int uid; public int set; public int tag; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int metered; /** * Note that this is only populated w/ the default value when read from /proc or written * to disk. We merge in the correct value when reporting this value to clients of @@ -123,16 +137,17 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, ROAMING_NO, rxBytes, rxPackets, txBytes, txPackets, - operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, + txPackets, operations); } - public Entry(String iface, int uid, int set, int tag, int roaming, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; + this.metered = metered; this.roaming = roaming; this.rxBytes = rxBytes; this.rxPackets = rxPackets; @@ -165,6 +180,7 @@ public class NetworkStats implements Parcelable { builder.append(" uid=").append(uid); builder.append(" set=").append(setToString(set)); builder.append(" tag=").append(tagToString(tag)); + builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); @@ -178,13 +194,18 @@ public class NetworkStats implements Parcelable { public boolean equals(Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; - return uid == e.uid && set == e.set && tag == e.tag && roaming == e.roaming - && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes - && txPackets == e.txPackets && operations == e.operations - && iface.equals(e.iface); + return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered + && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && txBytes == e.txBytes && txPackets == e.txPackets + && operations == e.operations && iface.equals(e.iface); } return false; } + + @Override + public int hashCode() { + return Objects.hash(uid, set, tag, metered, roaming, iface); + } } public NetworkStats(long elapsedRealtime, int initialSize) { @@ -196,6 +217,7 @@ public class NetworkStats implements Parcelable { this.uid = new int[initialSize]; this.set = new int[initialSize]; this.tag = new int[initialSize]; + this.metered = new int[initialSize]; this.roaming = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; @@ -209,6 +231,7 @@ public class NetworkStats implements Parcelable { this.uid = EmptyArray.INT; this.set = EmptyArray.INT; this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; @@ -226,6 +249,7 @@ public class NetworkStats implements Parcelable { uid = parcel.createIntArray(); set = parcel.createIntArray(); tag = parcel.createIntArray(); + metered = parcel.createIntArray(); roaming = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); @@ -243,6 +267,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(uid); dest.writeIntArray(set); dest.writeIntArray(tag); + dest.writeIntArray(metered); dest.writeIntArray(roaming); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); @@ -277,10 +302,11 @@ public class NetworkStats implements Parcelable { } @VisibleForTesting - public NetworkStats addValues(String iface, int uid, int set, int tag, int roaming, + public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { return addValues(new Entry( - iface, uid, set, tag, roaming, rxBytes, rxPackets, txBytes, txPackets, operations)); + iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, + operations)); } /** @@ -294,6 +320,7 @@ public class NetworkStats implements Parcelable { uid = Arrays.copyOf(uid, newLength); set = Arrays.copyOf(set, newLength); tag = Arrays.copyOf(tag, newLength); + metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); @@ -307,6 +334,7 @@ public class NetworkStats implements Parcelable { uid[size] = entry.uid; set[size] = entry.set; tag[size] = entry.tag; + metered[size] = entry.metered; roaming[size] = entry.roaming; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; @@ -327,6 +355,7 @@ public class NetworkStats implements Parcelable { entry.uid = uid[i]; entry.set = set[i]; entry.tag = tag[i]; + entry.metered = metered[i]; entry.roaming = roaming[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; @@ -381,7 +410,8 @@ public class NetworkStats implements Parcelable { * also be used to subtract values from existing rows. */ public NetworkStats combineValues(Entry entry) { - final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.roaming); + final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, + entry.roaming); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -409,10 +439,11 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -424,7 +455,7 @@ public class NetworkStats implements Parcelable { * search around the hinted index as an optimization. */ @VisibleForTesting - public int findIndexHinted(String iface, int uid, int set, int tag, int roaming, + public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -438,7 +469,8 @@ public class NetworkStats implements Parcelable { } if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] - && roaming == this.roaming[i] && Objects.equals(iface, this.iface[i])) { + && metered == this.metered[i] && roaming == this.roaming[i] + && Objects.equals(iface, this.iface[i])) { return i; } } @@ -452,7 +484,7 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); if (j == -1) { operations[i] = 0; } else { @@ -542,6 +574,7 @@ public class NetworkStats implements Parcelable { entry.uid = limitUid; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.rxBytes = 0; entry.rxPackets = 0; @@ -637,11 +670,12 @@ public class NetworkStats implements Parcelable { entry.uid = left.uid[i]; entry.set = left.set[i]; entry.tag = left.tag[i]; + entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.roaming, i); + entry.metered, entry.roaming, i); if (j == -1) { // newly appearing row, return entire value entry.rxBytes = left.rxBytes[i]; @@ -687,6 +721,7 @@ public class NetworkStats implements Parcelable { entry.uid = UID_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; entry.operations = 0L; @@ -716,6 +751,7 @@ public class NetworkStats implements Parcelable { entry.iface = IFACE_ALL; entry.set = SET_ALL; entry.tag = TAG_NONE; + entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; for (int i = 0; i < size; i++) { @@ -762,6 +798,7 @@ public class NetworkStats implements Parcelable { pw.print(" uid="); pw.print(uid[i]); pw.print(" set="); pw.print(setToString(set[i])); pw.print(" tag="); pw.print(tagToString(tag[i])); + pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); @@ -829,6 +866,22 @@ public class NetworkStats implements Parcelable { return "0x" + Integer.toHexString(tag); } + /** + * Return text description of {@link #metered} value. + */ + public static String meteredToString(int metered) { + switch (metered) { + case METERED_ALL: + return "ALL"; + case METERED_NO: + return "NO"; + case METERED_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + /** * Return text description of {@link #roaming} value. */ @@ -998,6 +1051,7 @@ public class NetworkStats implements Parcelable { tmpEntry.uid = uid[i]; tmpEntry.tag = tag[i]; tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { @@ -1017,24 +1071,25 @@ public class NetworkStats implements Parcelable { moved.set = SET_DBG_VPN_OUT; moved.tag = TAG_NONE; moved.iface = underlyingIface; + moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than // the TAG_NONE traffic. // - // Relies on the fact that the underlying traffic only has state ROAMING_NO, which - // should be the case as it comes directly from the /proc file. We only blend in the + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - ROAMING_NO); + METERED_NO, ROAMING_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } From b1f605fc33846070bcd39677b57d3633a4bbbff9 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 12 Jan 2017 18:38:57 -0800 Subject: [PATCH 0347/1150] Add API Surface for creating IpSec Transforms This CL adds an API to set up an IPSec Security Association and Security Policy to perform Transport-Mode and Tunnel-Mode encapuslation of IP Packets. Bug: 30984788 Bug: 34811752 Test: 34812052, 34811227 Change-Id: Ic9f63c7bb366302a24baa3e1b79020210910ac0a --- core/java/android/net/IpSecAlgorithm.java | 181 +++++++++ core/java/android/net/IpSecConfig.aidl | 20 + core/java/android/net/IpSecConfig.java | 197 +++++++++ core/java/android/net/IpSecManager.java | 379 +++++++++++++++++ core/java/android/net/IpSecTransform.java | 471 ++++++++++++++++++++++ 5 files changed, 1248 insertions(+) create mode 100644 core/java/android/net/IpSecAlgorithm.java create mode 100644 core/java/android/net/IpSecConfig.aidl create mode 100644 core/java/android/net/IpSecConfig.java create mode 100644 core/java/android/net/IpSecManager.java create mode 100644 core/java/android/net/IpSecTransform.java diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java new file mode 100644 index 0000000000..da5cb37961 --- /dev/null +++ b/core/java/android/net/IpSecAlgorithm.java @@ -0,0 +1,181 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.StringDef; +import android.os.Parcel; +import android.os.Parcelable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to + * RFC 4301. + */ +public final class IpSecAlgorithm implements Parcelable { + + /** + * AES-CBC Encryption/Ciphering Algorithm. + * + *

            Valid lengths for this key are {128, 192, 256}. + */ + public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + + /** + * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new + * applications and is provided for legacy compatibility with 3gpp infrastructure. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. + */ + public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; + + /** + * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in + * new applications and is provided for legacy compatibility with 3gpp infrastructure. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. + */ + public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; + + /** + * SHA256 HMAC Authentication/Integrity Algorithm. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. + */ + public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; + + /** + * SHA384 HMAC Authentication/Integrity Algorithm. + * + *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. + */ + public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; + /** + * SHA512 HMAC Authentication/Integrity Algorithm + * + *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. + */ + public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; + + /** @hide */ + @StringDef({ + ALGO_CRYPT_AES_CBC, + ALGO_AUTH_HMAC_MD5, + ALGO_AUTH_HMAC_SHA1, + ALGO_AUTH_HMAC_SHA256, + ALGO_AUTH_HMAC_SHA512 + }) + @Retention(RetentionPolicy.SOURCE) + public @interface AlgorithmName {} + + private final String mName; + private final byte[] mKey; + private final int mTruncLenBits; + + /** + * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the + * algorithm + * + * @param algorithm type for IpSec. + * @param key non-null Key padded to a multiple of 8 bits. + */ + public IpSecAlgorithm(String algorithm, byte[] key) { + this(algorithm, key, key.length * 8); + } + + /** + * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the + * algorithm + * + * @param algoName precise name of the algorithm to be used. + * @param key non-null Key padded to a multiple of 8 bits. + * @param truncLenBits the number of bits of output hash to use; only meaningful for + * Authentication. + */ + public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) { + if (!isTruncationLengthValid(algoName, truncLenBits)) { + throw new IllegalArgumentException("Unknown algorithm or invalid length"); + } + mName = algoName; + mKey = key.clone(); + mTruncLenBits = Math.min(truncLenBits, key.length * 8); + } + + /** Retrieve the algorithm name */ + public String getName() { + return mName; + } + + /** Retrieve the key for this algorithm */ + public byte[] getKey() { + return mKey.clone(); + } + + /** + * Retrieve the truncation length, in bits, for the key in this algo. By default this will be + * the length in bits of the key. + */ + public int getTruncationLengthBits() { + return mTruncLenBits; + } + + /* Parcelable Implementation */ + public int describeContents() { + return 0; + } + + /** Write to parcel */ + public void writeToParcel(Parcel out, int flags) { + out.writeString(mName); + out.writeByteArray(mKey); + out.writeInt(mTruncLenBits); + } + + /** Parcelable Creator */ + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecAlgorithm createFromParcel(Parcel in) { + return new IpSecAlgorithm(in); + } + + public IpSecAlgorithm[] newArray(int size) { + return new IpSecAlgorithm[size]; + } + }; + + private IpSecAlgorithm(Parcel in) { + mName = in.readString(); + mKey = in.createByteArray(); + mTruncLenBits = in.readInt(); + } + + private static boolean isTruncationLengthValid(String algo, int truncLenBits) { + switch (algo) { + case ALGO_AUTH_HMAC_MD5: + return (truncLenBits >= 96 && truncLenBits <= 128); + case ALGO_AUTH_HMAC_SHA1: + return (truncLenBits >= 96 && truncLenBits <= 160); + case ALGO_AUTH_HMAC_SHA256: + return (truncLenBits >= 96 && truncLenBits <= 256); + case ALGO_AUTH_HMAC_SHA384: + return (truncLenBits >= 192 && truncLenBits <= 384); + case ALGO_AUTH_HMAC_SHA512: + return (truncLenBits >= 256 && truncLenBits <= 512); + default: + return false; + } + } +}; diff --git a/core/java/android/net/IpSecConfig.aidl b/core/java/android/net/IpSecConfig.aidl new file mode 100644 index 0000000000..eaefca74d3 --- /dev/null +++ b/core/java/android/net/IpSecConfig.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable IpSecConfig; diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java new file mode 100644 index 0000000000..b58bf421a8 --- /dev/null +++ b/core/java/android/net/IpSecConfig.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** @hide */ +public final class IpSecConfig implements Parcelable { + private static final String TAG = IpSecConfig.class.getSimpleName(); + + //MODE_TRANSPORT or MODE_TUNNEL + int mode; + + // For tunnel mode + InetAddress localAddress; + + InetAddress remoteAddress; + + // Limit selection by network interface + Network network; + + public static class Flow { + // Minimum requirements for identifying a transform + // SPI identifying the IPsec flow in packet processing + // and a remote IP address + int spi; + + // Encryption Algorithm + IpSecAlgorithm encryptionAlgo; + + // Authentication Algorithm + IpSecAlgorithm authenticationAlgo; + } + + Flow[] flow = new Flow[2]; + + // For tunnel mode IPv4 UDP Encapsulation + // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE + int encapType; + int encapLocalPort; + int encapRemotePort; + + // An optional protocol to match with the selector + int selectorProto; + + // A bitmask of FEATURE_* indicating which of the fields + // of this class are valid. + long features; + + // An interval, in seconds between the NattKeepalive packets + int nattKeepaliveInterval; + + public InetAddress getLocalIp() { + return localAddress; + } + + public int getSpi(int direction) { + return flow[direction].spi; + } + + public InetAddress getRemoteIp() { + return remoteAddress; + } + + public IpSecAlgorithm getEncryptionAlgo(int direction) { + return flow[direction].encryptionAlgo; + } + + public IpSecAlgorithm getAuthenticationAlgo(int direction) { + return flow[direction].authenticationAlgo; + } + + Network getNetwork() { + return network; + } + + public int getEncapType() { + return encapType; + } + + public int getEncapLocalPort() { + return encapLocalPort; + } + + public int getEncapRemotePort() { + return encapRemotePort; + } + + public int getSelectorProto() { + return selectorProto; + } + + int getNattKeepaliveInterval() { + return nattKeepaliveInterval; + } + + public boolean hasProperty(int featureBits) { + return (features & featureBits) == featureBits; + } + + // Parcelable Methods + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeLong(features); + // TODO: Use a byte array or other better method for storing IPs that can also include scope + out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); + // TODO: Use a byte array or other better method for storing IPs that can also include scope + out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); + out.writeParcelable(network, flags); + out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags); + out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags); + out.writeInt(encapType); + out.writeInt(encapLocalPort); + out.writeInt(encapRemotePort); + out.writeInt(selectorProto); + } + + // Package Private: Used by the IpSecTransform.Builder; + // there should be no public constructor for this object + IpSecConfig() { + flow[IpSecTransform.DIRECTION_IN].spi = 0; + flow[IpSecTransform.DIRECTION_OUT].spi = 0; + nattKeepaliveInterval = 0; //FIXME constant + } + + private static InetAddress readInetAddressFromParcel(Parcel in) { + String addrString = in.readString(); + if (addrString == null) { + return null; + } + try { + return InetAddress.getByName(addrString); + } catch (UnknownHostException e) { + Log.wtf(TAG, "Invalid IpAddress " + addrString); + return null; + } + } + + private IpSecConfig(Parcel in) { + features = in.readLong(); + localAddress = readInetAddressFromParcel(in); + remoteAddress = readInetAddressFromParcel(in); + network = (Network) in.readParcelable(Network.class.getClassLoader()); + flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); + flow[IpSecTransform.DIRECTION_IN].encryptionAlgo = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + flow[IpSecTransform.DIRECTION_IN].authenticationAlgo = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); + flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + encapType = in.readInt(); + encapLocalPort = in.readInt(); + encapRemotePort = in.readInt(); + selectorProto = in.readInt(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecConfig createFromParcel(Parcel in) { + return new IpSecConfig(in); + } + + public IpSecConfig[] newArray(int size) { + return new IpSecConfig[size]; + } + }; +} diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java new file mode 100644 index 0000000000..2c544e9b9b --- /dev/null +++ b/core/java/android/net/IpSecManager.java @@ -0,0 +1,379 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.SystemApi; +import android.content.Context; +import android.os.INetworkManagementService; +import android.os.ParcelFileDescriptor; +import android.util.AndroidException; +import dalvik.system.CloseGuard; +import java.io.FileDescriptor; +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.net.Socket; + +/** + * This class contains methods for managing IPsec sessions, which will perform kernel-space + * encryption and decryption of socket or Network traffic. + * + *

            An IpSecManager may be obtained by calling {@link + * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link + * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} + */ +public final class IpSecManager { + private static final String TAG = "IpSecManager"; + + /** + * Indicates that the combination of remote InetAddress and SPI was non-unique for a given + * request. If encountered, selection of a new SPI is required before a transform may be + * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random + * or reserved using reserveSecurityParameterIndex. + */ + public static final class SpiUnavailableException extends AndroidException { + private final int mSpi; + + /** + * Construct an exception indicating that a transform with the given SPI is already in use + * or otherwise unavailable. + * + * @param msg Description indicating the colliding SPI + * @param spi the SPI that could not be used due to a collision + */ + SpiUnavailableException(String msg, int spi) { + super(msg + "(spi: " + spi + ")"); + mSpi = spi; + } + + /** Retrieve the SPI that caused a collision */ + public int getSpi() { + return mSpi; + } + } + + /** + * Indicates that the requested system resource for IPsec, such as a socket or other system + * resource is unavailable. If this exception is thrown, try releasing allocated objects of the + * type requested. + */ + public static final class ResourceUnavailableException extends AndroidException { + + ResourceUnavailableException(String msg) { + super(msg); + } + } + + private final Context mContext; + private final INetworkManagementService mService; + + public static final class SecurityParameterIndex implements AutoCloseable { + private final Context mContext; + private final InetAddress mDestinationAddress; + private final CloseGuard mCloseGuard = CloseGuard.get(); + private int mSpi; + + /** Return the underlying SPI held by this object */ + public int getSpi() { + return mSpi; + } + + private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi) + throws ResourceUnavailableException, SpiUnavailableException { + mContext = context; + mDestinationAddress = destinationAddress; + mSpi = spi; + mCloseGuard.open("open"); + } + + /** + * Release an SPI that was previously reserved. + * + *

            Release an SPI for use by other users in the system. This will fail if the SPI is + * currently in use by an IpSecTransform. + * + * @param destinationAddress SPIs must be unique for each combination of SPI and destination + * address. Thus, the destinationAddress to which the SPI will communicate must be + * supplied. + * @param spi the previously reserved SPI to be freed. + */ + @Override + public void close() { + mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI + mCloseGuard.close(); + } + + @Override + protected void finalize() { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + close(); + } + } + + /** + * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. + * + *

            No IPsec packet may contain an SPI of 0. + */ + public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + + /** + * Reserve an SPI for traffic bound towards the specified destination address. + * + *

            If successful, this SPI is guaranteed available until released by a call to {@link + * SecurityParameterIndex#close()}. + * + * @param destinationAddress SPIs must be unique for each combination of SPI and destination + * address. + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @return the reserved SecurityParameterIndex + * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated + * for this user + * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved + */ + public SecurityParameterIndex reserveSecurityParameterIndex( + InetAddress destinationAddress, int requestedSpi) + throws SpiUnavailableException, ResourceUnavailableException { + return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi); + } + + /** + * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec + * encapsulation of the traffic flowing between the socket and the remote InetAddress of that + * transform. For security reasons, attempts to send traffic to any IP address other than the + * address associated with that transform will throw an IOException. In addition, if the + * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to + * send() or receive() until the transform is removed from the socket by calling {@link + * #removeTransportModeTransform(Socket, IpSecTransform)}; + * + * @param socket a stream socket + * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + */ + public void applyTransportModeTransform(Socket socket, IpSecTransform transform) + throws IOException { + applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform); + } + + /** + * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec + * encapsulation of the traffic flowing between the socket and the remote InetAddress of that + * transform. For security reasons, attempts to send traffic to any IP address other than the + * address associated with that transform will throw an IOException. In addition, if the + * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to + * send() or receive() until the transform is removed from the socket by calling {@link + * #removeTransportModeTransform(DatagramSocket, IpSecTransform)}; + * + * @param socket a datagram socket + * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + */ + public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) + throws IOException { + applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); + } + + /* Call down to activate a transform */ + private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + + /** + * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to + * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to + * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic). + * Applications should probably not use this API directly. Instead, they should use {@link + * VpnService} to provide VPN capability in a more generic fashion. + * + * @param net a {@link Network} that will be tunneled via IP Sec. + * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. + * @hide + */ + @SystemApi + public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} + + /** + * Remove a transform from a given stream socket. Once removed, traffic on the socket will not + * be encypted. This allows sockets that have been used for IPsec to be reclaimed for + * communication in the clear in the event socket reuse is desired. This operation will succeed + * regardless of the underlying state of a transform. If a transform is removed, communication + * on all sockets to which that transform was applied will fail until this method is called. + * + * @param socket a socket that previously had a transform applied to it. + * @param transform the IPsec Transform that was previously applied to the given socket + */ + public void removeTransportModeTransform(Socket socket, IpSecTransform transform) { + removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform); + } + + /** + * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not + * be encypted. This allows sockets that have been used for IPsec to be reclaimed for + * communication in the clear in the event socket reuse is desired. This operation will succeed + * regardless of the underlying state of a transform. If a transform is removed, communication + * on all sockets to which that transform was applied will fail until this method is called. + * + * @param socket a socket that previously had a transform applied to it. + * @param transform the IPsec Transform that was previously applied to the given socket + */ + public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) { + removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); + } + + /* Call down to activate a transform */ + private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + + /** + * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of + * cleanup if a tunneled Network experiences a change in default route. The Network will drop + * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is + * lost, all traffic will drop. + * + * @param net a network that currently has transform applied to it. + * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given + * network + * @hide + */ + @SystemApi + public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} + + /** + * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for + * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic. + * + *

            The socket provided by this class cannot be re-bound or closed via the inner + * FileDescriptor. Instead, disposing of this socket requires a call to close(). + */ + public static final class UdpEncapsulationSocket implements AutoCloseable { + private final FileDescriptor mFd; + private final Context mContext; + private final CloseGuard mCloseGuard = CloseGuard.get(); + + private UdpEncapsulationSocket(Context context, int port) + throws ResourceUnavailableException { + mContext = context; + mCloseGuard.open("constructor"); + // TODO: go down to the kernel and get a socket on the specified + mFd = new FileDescriptor(); + } + + private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException { + mContext = context; + mCloseGuard.open("constructor"); + // TODO: go get a random socket on a random port + mFd = new FileDescriptor(); + } + + /** Access the inner UDP Encapsulation Socket */ + public FileDescriptor getSocket() { + return mFd; + } + + /** Retrieve the port number of the inner encapsulation socket */ + public int getPort() { + return 0; // TODO get the port number from the Socket; + } + + @Override + /** + * Release the resources that have been reserved for this Socket. + * + *

            This method closes the underlying socket, reducing a user's allocated sockets in the + * system. This must be done as part of cleanup following use of a socket. Failure to do so + * will cause the socket to count against a total allocation limit for IpSec and eventually + * fail due to resource limits. + * + * @param fd a file descriptor previously returned as a UDP Encapsulation socket. + */ + public void close() { + // TODO: Go close the socket + mCloseGuard.close(); + } + + @Override + protected void finalize() throws Throwable { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + + close(); + } + }; + + /** + * Open a socket that is bound to a free UDP port on the system. + * + *

            By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by + * the caller. This provides safe access to a socket on a port that can later be used as a UDP + * Encapsulation port. + * + *

            This socket reservation works in conjunction with IpSecTransforms, which may re-use the + * socket port. Explicitly opening this port is only necessary if communication is desired on + * that port. + * + * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this + * method will bind to the specified port or fail. To retrieve the port number, call {@link + * android.system.Os#getsockname(FileDescriptor)}. + * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime + * of the object. + */ + // Returning a socket in this fashion that has been created and bound by the system + // is the only safe way to ensure that a socket is both accessible to the user and + // safely usable for Encapsulation without allowing a user to possibly unbind from/close + // the port, which could potentially impact the traffic of the next user who binds to that + // socket. + public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) + throws IOException, ResourceUnavailableException { + // Temporary code + return new UdpEncapsulationSocket(mContext, port); + } + + /** + * Open a socket that is bound to a port selected by the system. + * + *

            By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by + * the caller. This provides safe access to a socket on a port that can later be used as a UDP + * Encapsulation port. + * + *

            This socket reservation works in conjunction with IpSecTransforms, which may re-use the + * socket port. Explicitly opening this port is only necessary if communication is desired on + * that port. + * + * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port + */ + // Returning a socket in this fashion that has been created and bound by the system + // is the only safe way to ensure that a socket is both accessible to the user and + // safely usable for Encapsulation without allowing a user to possibly unbind from/close + // the port, which could potentially impact the traffic of the next user who binds to that + // socket. + public UdpEncapsulationSocket openUdpEncapsulationSocket() + throws IOException, ResourceUnavailableException { + // Temporary code + return new UdpEncapsulationSocket(mContext); + } + + /** + * Retrieve an instance of an IpSecManager within you application context + * + * @param context the application context for this manager + * @hide + */ + public IpSecManager(Context context, INetworkManagementService service) { + mContext = checkNotNull(context, "missing context"); + mService = checkNotNull(service, "missing service"); + } +} diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java new file mode 100644 index 0000000000..d6dd28bec3 --- /dev/null +++ b/core/java/android/net/IpSecTransform.java @@ -0,0 +1,471 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.annotation.IntDef; +import android.annotation.SystemApi; +import android.content.Context; +import android.system.ErrnoException; +import android.util.Log; +import dalvik.system.CloseGuard; +import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.InetAddress; + +/** + * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec. + * + *

            IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout + * the lifetime of the underlying transform. If a transform object leaves scope, the underlying + * transform may be disabled automatically, with likely undesirable results. + * + *

            An IpSecTransform may either represent a tunnel mode transform that operates on a wide array + * of traffic or may represent a transport mode transform operating on a Socket or Sockets. + */ +public final class IpSecTransform implements AutoCloseable { + private static final String TAG = "IpSecTransform"; + + /** + * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies + * to traffic towards the host. + */ + public static final int DIRECTION_IN = 0; + + /** + * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies + * to traffic from the host. + */ + public static final int DIRECTION_OUT = 1; + + /** @hide */ + @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) + @Retention(RetentionPolicy.SOURCE) + public @interface TransformDirection {} + + /** @hide */ + private static final int MODE_TUNNEL = 0; + + /** @hide */ + private static final int MODE_TRANSPORT = 1; + + /** @hide */ + public static final int ENCAP_NONE = 0; + + /** + * IpSec traffic will be encapsulated within UDP as per RFC3498. + * + * @hide + */ + public static final int ENCAP_ESPINUDP = 1; + + /** + * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad + * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP. + * + * @hide + */ + public static final int ENCAP_ESPINUDP_NONIKE = 2; + + /** @hide */ + @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE}) + @Retention(RetentionPolicy.SOURCE) + public @interface EncapType {} + + /** + * Sentinel for an invalid transform (means that this transform is inactive). + * + * @hide + */ + public static final int INVALID_TRANSFORM_ID = -1; + + private IpSecTransform(Context context, IpSecConfig config) { + mContext = context; + mConfig = config; + mTransformId = INVALID_TRANSFORM_ID; + } + + private IpSecTransform activate() + throws IOException, IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException { + int transformId; + synchronized (this) { + //try { + transformId = INVALID_TRANSFORM_ID; + //} catch (RemoteException e) { + // throw e.rethrowFromSystemServer(); + //} + + if (transformId < 0) { + throw new ErrnoException("addTransform", -transformId).rethrowAsIOException(); + } + + startKeepalive(mContext); // Will silently fail if not required + mTransformId = transformId; + Log.d(TAG, "Added Transform with Id " + transformId); + } + mCloseGuard.open("build"); + + return this; + } + + /** + * Deactivate an IpSecTransform and free all resources for that transform that are managed by + * the system for this Transform. + * + *

            Deactivating a transform while it is still applied to any Socket will result in sockets + * refusing to send or receive data. This method will silently succeed if the specified + * transform has already been removed; thus, it is always safe to attempt cleanup when a + * transform is no longer needed. + */ + public void close() { + Log.d(TAG, "Removing Transform with Id " + mTransformId); + + // Always safe to attempt cleanup + if (mTransformId == INVALID_TRANSFORM_ID) { + return; + } + //try { + stopKeepalive(); + //} catch (RemoteException e) { + // transform.setTransformId(transformId); + // throw e.rethrowFromSystemServer(); + //} finally { + mTransformId = INVALID_TRANSFORM_ID; + //} + mCloseGuard.close(); + } + + @Override + protected void finalize() throws Throwable { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } + + /* Package */ + IpSecConfig getConfig() { + return mConfig; + } + + private final IpSecConfig mConfig; + private int mTransformId; + private final Context mContext; + private final CloseGuard mCloseGuard = CloseGuard.get(); + private ConnectivityManager.PacketKeepalive mKeepalive; + private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE; + private Object mKeepaliveSyncLock = new Object(); + private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback = + new ConnectivityManager.PacketKeepaliveCallback() { + + @Override + public void onStarted() { + synchronized (mKeepaliveSyncLock) { + mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS; + mKeepaliveSyncLock.notifyAll(); + } + } + + @Override + public void onStopped() { + synchronized (mKeepaliveSyncLock) { + mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE; + mKeepaliveSyncLock.notifyAll(); + } + } + + @Override + public void onError(int error) { + synchronized (mKeepaliveSyncLock) { + mKeepaliveStatus = error; + mKeepaliveSyncLock.notifyAll(); + } + } + }; + + /* Package */ + void startKeepalive(Context c) { + if (mConfig.getNattKeepaliveInterval() == 0) { + return; + } + + ConnectivityManager cm = + (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); + + if (mKeepalive != null) { + Log.e(TAG, "Keepalive already started for this IpSecTransform."); + return; + } + + synchronized (mKeepaliveSyncLock) { + mKeepalive = + cm.startNattKeepalive( + mConfig.getNetwork(), + mConfig.getNattKeepaliveInterval(), + mKeepaliveCallback, + mConfig.getLocalIp(), + mConfig.getEncapLocalPort(), + mConfig.getRemoteIp()); + try { + mKeepaliveSyncLock.wait(2000); + } catch (InterruptedException e) { + } + } + if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) { + throw new UnsupportedOperationException("Packet Keepalive cannot be started"); + } + } + + /* Package */ + void stopKeepalive() { + if (mKeepalive == null) { + return; + } + mKeepalive.stop(); + synchronized (mKeepaliveSyncLock) { + if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) { + try { + mKeepaliveSyncLock.wait(2000); + } catch (InterruptedException e) { + } + } + } + } + + /* Package */ + void setTransformId(int transformId) { + mTransformId = transformId; + } + + /* Package */ + int getTransformId() { + return mTransformId; + } + + /** + * Builder object to facilitate the creation of IpSecTransform objects. + * + *

            Apply additional properties to the transform and then call a build() method to return an + * IpSecTransform object. + * + * @see Builder#buildTransportModeTransform(InetAddress) + */ + public static class Builder { + private Context mContext; + private IpSecConfig mConfig; + + /** + * Add an encryption algorithm to the transform for the given direction. + * + *

            If encryption is set for a given direction without also providing an SPI for that + * direction, creation of an IpSecTransform will fail upon calling a build() method. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. + */ + public IpSecTransform.Builder setEncryption( + @TransformDirection int direction, IpSecAlgorithm algo) { + mConfig.flow[direction].encryptionAlgo = algo; + return this; + } + + /** + * Add an authentication/integrity algorithm to the transform. + * + *

            If authentication is set for a given direction without also providing an SPI for that + * direction, creation of an IpSecTransform will fail upon calling a build() method. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. + */ + public IpSecTransform.Builder setAuthentication( + @TransformDirection int direction, IpSecAlgorithm algo) { + mConfig.flow[direction].authenticationAlgo = algo; + return this; + } + + /** + * Set the SPI, which uniquely identifies a particular IPsec session from others. Because + * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a + * given destination address. + * + *

            Care should be chosen when selecting an SPI to ensure that is is as unique as + * possible. Random number generation is a reasonable approach to selecting an SPI. For + * outbound SPIs, they must be reserved by calling {@link + * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * fail to build. + * + *

            Unless an SPI is set for a given direction, traffic in that direction will be + * sent/received without any IPsec applied. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param spi a unique 32-bit integer to identify transformed traffic + */ + public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) { + mConfig.flow[direction].spi = spi; + return this; + } + + /** + * Set the SPI, which uniquely identifies a particular IPsec session from others. Because + * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a + * given destination address. + * + *

            Care should be chosen when selecting an SPI to ensure that is is as unique as + * possible. Random number generation is a reasonable approach to selecting an SPI. For + * outbound SPIs, they must be reserved by calling {@link + * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * fail to activate. + * + *

            Unless an SPI is set for a given direction, traffic in that direction will be + * sent/received without any IPsec applied. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed + * traffic + */ + public IpSecTransform.Builder setSpi( + @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { + mConfig.flow[direction].spi = spi.getSpi(); + return this; + } + + /** + * Specify the network on which this transform will emit its traffic; (otherwise it will + * emit on the default network). + * + *

            Restricts the transformed traffic to a particular {@link Network}. This is required in + * tunnel mode. + * + * @hide + */ + @SystemApi + public IpSecTransform.Builder setUnderlyingNetwork(Network net) { + mConfig.network = net; + return this; + } + + /** + * Add UDP encapsulation to an IPv4 transform + * + *

            This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for + * details on how UDP should be applied to IPsec. + * + * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and + * receiving encapsulating traffic. + * @param remotePort the UDP port number of the remote that will send and receive + * encapsulated traffic. In the case of IKE, this is likely port 4500. + */ + public IpSecTransform.Builder setIpv4Encapsulation( + IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { + // TODO: check encap type is valid. + mConfig.encapType = ENCAP_ESPINUDP; + mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket + mConfig.encapRemotePort = remotePort; + return this; + } + + // TODO: Decrease the minimum keepalive to maybe 10? + // TODO: Probably a better exception to throw for NATTKeepalive failure + // TODO: Specify the needed NATT keepalive permission. + /** + * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded + * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot + * be activated, then the transform will fail to activate and throw an IOException. + * + * @param intervalSeconds the maximum number of seconds between keepalive packets, no less + * than 20s and no more than 3600s. + * @hide + */ + @SystemApi + public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) { + mConfig.nattKeepaliveInterval = intervalSeconds; + return this; + } + + /** + * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform. + * Some parameters have interdependencies that are checked at build time. If a well-formed + * transform cannot be created from the supplied parameters, this method will throw an + * Exception. + * + *

            Upon a successful return from this call, the provided IpSecTransform will be active + * and may be applied to sockets. If too many IpSecTransform objects are active for a given + * user this operation will fail and throw ResourceUnavailableException. To avoid these + * exceptions, unused Transform objects must be cleaned up by calling {@link + * IpSecTransform#close()} when they are no longer needed. + * + * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this + * socket will cause the transform to be applied. + *

            Note that an active transform will not impact any network traffic until it has + * been applied to one or more Sockets. Calling this method is a necessary precondition + * for applying it to a socket, but is not sufficient to actually apply IPsec. + * @throws IllegalArgumentException indicating that a particular combination of transform + * properties is invalid. + * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms + * may be allocated + * @throws SpiUnavailableException if the SPI collides with an existing transform + * (unlikely). + * @throws ResourceUnavailableException if the current user currently has exceeded the + * number of allowed active transforms. + */ + public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) + throws IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException, IOException { + //FIXME: argument validation here + //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); + mConfig.mode = MODE_TRANSPORT; + mConfig.remoteAddress = remoteAddress; + return new IpSecTransform(mContext, mConfig).activate(); + } + + /** + * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some + * parameters have interdependencies that are checked at build time. + * + * @param localAddress the {@link InetAddress} that provides the local endpoint for this + * IPsec tunnel. This is almost certainly an address belonging to the {@link Network} + * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. + * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this + * IPsec tunnel. + * @throws IllegalArgumentException indicating that a particular combination of transform + * properties is invalid. + * @hide + */ + @SystemApi + public IpSecTransform buildTunnelModeTransform( + InetAddress localAddress, InetAddress remoteAddress) { + //FIXME: argument validation here + //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); + mConfig.localAddress = localAddress; + mConfig.remoteAddress = remoteAddress; + mConfig.mode = MODE_TUNNEL; + return new IpSecTransform(mContext, mConfig); + } + + /** + * Create a new IpSecTransform.Builder to construct an IpSecTransform + * + * @param context current Context + */ + public Builder(Context context) { + mContext = context; + mConfig = new IpSecConfig(); + } + } +} From 662a01236a9a84a73778c78e5571a7d1bafc024b Mon Sep 17 00:00:00 2001 From: Ryuki Nakamura Date: Wed, 1 Mar 2017 10:40:36 +0900 Subject: [PATCH 0348/1150] Fix NPE while performing NetworkStatsService.removeUidsLocked() Symptom: NPE occurred while performing NetworkStatsService.removeUidsLocked(). Root cause: NetworkStatsService refers to mUidRecorder at NetworkStatsService.removeUidsLocked() when mUserReceiver received Intent.ACTION_USER_REMOVED. However NetworkStatsService sets mUidRecorder to null without unregistering mUserReceiver when mShutdownReceiver received Intent.ACTION_SHUTDOWN. Therefore NPE occurred when mUserReceiver received Intent.ACTION_USER_REMOVED after mShutdownReceiver received Intent.ACTION_SHUTDOWN. Solution: Unregister mUserReceiver before setting mUidRecorder to null when mShutdownReceiver received Intent.ACTION_SHUTDOWN. Bug: 36015339 Change-Id: I9279e4c6ae07d94e7ec519c40b2d973c84d8fef1 --- .../core/java/com/android/server/net/NetworkStatsService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4658c0463f..060dd73d11 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -381,6 +381,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); + mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() From d2a1dad9a89f68b02ba568cfae025914704a608e Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 1 Mar 2017 18:55:06 -0800 Subject: [PATCH 0349/1150] Add a Skeleton IpSecService -Add IpSecService with the necessary glue to connect to netd -Add code to retrieve IpSecService from System Server Bug: 34811227 Test: Service boots (and dumpsys works), more via b/34811227 Merged-In: I4cdcb643421141202f77a0e2f87a37012de0cd92 Change-Id: I4cdcb643421141202f77a0e2f87a37012de0cd92 --- core/java/android/net/IIpSecService.aidl | 24 ++++ core/java/android/net/IpSecManager.java | 31 +++-- .../java/com/android/server/IpSecService.java | 114 ++++++++++++++++++ 3 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 core/java/android/net/IIpSecService.aidl create mode 100644 services/core/java/com/android/server/IpSecService.java diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl new file mode 100644 index 0000000000..b8737fef72 --- /dev/null +++ b/core/java/android/net/IIpSecService.aidl @@ -0,0 +1,24 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +/** + * @hide + */ +interface IIpSecService +{ +} diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 2c544e9b9b..93a76dfbb4 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -18,8 +18,6 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SystemApi; -import android.content.Context; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.util.AndroidException; import dalvik.system.CloseGuard; @@ -79,11 +77,10 @@ public final class IpSecManager { } } - private final Context mContext; - private final INetworkManagementService mService; + private final IIpSecService mService; public static final class SecurityParameterIndex implements AutoCloseable { - private final Context mContext; + private final IIpSecService mService; private final InetAddress mDestinationAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi; @@ -93,9 +90,10 @@ public final class IpSecManager { return mSpi; } - private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi) + private SecurityParameterIndex( + IIpSecService service, InetAddress destinationAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { - mContext = context; + mService = service; mDestinationAddress = destinationAddress; mSpi = spi; mCloseGuard.open("open"); @@ -152,7 +150,7 @@ public final class IpSecManager { public SecurityParameterIndex reserveSecurityParameterIndex( InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { - return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi); + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); } /** @@ -260,19 +258,19 @@ public final class IpSecManager { */ public static final class UdpEncapsulationSocket implements AutoCloseable { private final FileDescriptor mFd; - private final Context mContext; + private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); - private UdpEncapsulationSocket(Context context, int port) + private UdpEncapsulationSocket(IIpSecService service, int port) throws ResourceUnavailableException { - mContext = context; + mService = service; mCloseGuard.open("constructor"); // TODO: go down to the kernel and get a socket on the specified mFd = new FileDescriptor(); } - private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException { - mContext = context; + private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException { + mService = service; mCloseGuard.open("constructor"); // TODO: go get a random socket on a random port mFd = new FileDescriptor(); @@ -339,7 +337,7 @@ public final class IpSecManager { public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) throws IOException, ResourceUnavailableException { // Temporary code - return new UdpEncapsulationSocket(mContext, port); + return new UdpEncapsulationSocket(mService, port); } /** @@ -363,7 +361,7 @@ public final class IpSecManager { public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { // Temporary code - return new UdpEncapsulationSocket(mContext); + return new UdpEncapsulationSocket(mService); } /** @@ -372,8 +370,7 @@ public final class IpSecManager { * @param context the application context for this manager * @hide */ - public IpSecManager(Context context, INetworkManagementService service) { - mContext = checkNotNull(context, "missing context"); + public IpSecManager(IIpSecService service) { mService = checkNotNull(service, "missing service"); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java new file mode 100644 index 0000000000..994adc480f --- /dev/null +++ b/services/core/java/com/android/server/IpSecService.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static android.Manifest.permission.DUMP; + +import android.content.Context; +import android.net.IIpSecService; +import android.net.INetd; +import android.net.util.NetdService; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** @hide */ +public class IpSecService extends IIpSecService.Stub { + private static final String TAG = "IpSecService"; + private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + private static final String NETD_SERVICE_NAME = "netd"; + + /** Binder context for this service */ + private final Context mContext; + + private Object mLock = new Object(); + + private static final int NETD_FETCH_TIMEOUT = 5000; //ms + + /** + * Constructs a new IpSecService instance + * + * @param context Binder context for this service + */ + private IpSecService(Context context) { + mContext = context; + } + + static IpSecService create(Context context) throws InterruptedException { + final IpSecService service = new IpSecService(context); + service.connectNativeNetdService(); + return service; + } + + public void systemReady() { + if (isNetdAlive()) { + Slog.d(TAG, "IpSecService is ready"); + } else { + Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); + } + } + + private void connectNativeNetdService() { + // Avoid blocking the system server to do this + Thread t = + new Thread( + new Runnable() { + @Override + public void run() { + synchronized (mLock) { + NetdService.get(NETD_FETCH_TIMEOUT); + } + } + }); + t.run(); + } + + INetd getNetdInstance() { + final INetd netd = NetdService.getInstance(); + if (netd == null) { + throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer(); + } + return netd; + } + + boolean isNetdAlive() { + synchronized (mLock) { + final INetd netd = getNetdInstance(); + if (netd == null) { + return false; + } + + try { + return netd.isAlive(); + } catch (RemoteException re) { + return false; + } + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(DUMP, TAG); + + pw.println("IpSecService Log:"); + pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); + pw.println(); + } +} From 927e040ae3afa5138f60b0ed3539253755a37dbd Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 1 Mar 2017 18:55:06 -0800 Subject: [PATCH 0350/1150] Add a Skeleton IpSecService -Add IpSecService with the necessary glue to connect to netd -Add code to retrieve IpSecService from System Server Bug: 34811227 Test: Service boots (and dumpsys works), more via b/34811227 Change-Id: I4cdcb643421141202f77a0e2f87a37012de0cd92 --- core/java/android/net/IIpSecService.aidl | 24 ++++ core/java/android/net/IpSecManager.java | 31 +++-- .../java/com/android/server/IpSecService.java | 114 ++++++++++++++++++ 3 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 core/java/android/net/IIpSecService.aidl create mode 100644 services/core/java/com/android/server/IpSecService.java diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl new file mode 100644 index 0000000000..b8737fef72 --- /dev/null +++ b/core/java/android/net/IIpSecService.aidl @@ -0,0 +1,24 @@ +/* +** Copyright 2017, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.net; + +/** + * @hide + */ +interface IIpSecService +{ +} diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 2c544e9b9b..93a76dfbb4 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -18,8 +18,6 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SystemApi; -import android.content.Context; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.util.AndroidException; import dalvik.system.CloseGuard; @@ -79,11 +77,10 @@ public final class IpSecManager { } } - private final Context mContext; - private final INetworkManagementService mService; + private final IIpSecService mService; public static final class SecurityParameterIndex implements AutoCloseable { - private final Context mContext; + private final IIpSecService mService; private final InetAddress mDestinationAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi; @@ -93,9 +90,10 @@ public final class IpSecManager { return mSpi; } - private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi) + private SecurityParameterIndex( + IIpSecService service, InetAddress destinationAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { - mContext = context; + mService = service; mDestinationAddress = destinationAddress; mSpi = spi; mCloseGuard.open("open"); @@ -152,7 +150,7 @@ public final class IpSecManager { public SecurityParameterIndex reserveSecurityParameterIndex( InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { - return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi); + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); } /** @@ -260,19 +258,19 @@ public final class IpSecManager { */ public static final class UdpEncapsulationSocket implements AutoCloseable { private final FileDescriptor mFd; - private final Context mContext; + private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); - private UdpEncapsulationSocket(Context context, int port) + private UdpEncapsulationSocket(IIpSecService service, int port) throws ResourceUnavailableException { - mContext = context; + mService = service; mCloseGuard.open("constructor"); // TODO: go down to the kernel and get a socket on the specified mFd = new FileDescriptor(); } - private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException { - mContext = context; + private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException { + mService = service; mCloseGuard.open("constructor"); // TODO: go get a random socket on a random port mFd = new FileDescriptor(); @@ -339,7 +337,7 @@ public final class IpSecManager { public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) throws IOException, ResourceUnavailableException { // Temporary code - return new UdpEncapsulationSocket(mContext, port); + return new UdpEncapsulationSocket(mService, port); } /** @@ -363,7 +361,7 @@ public final class IpSecManager { public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { // Temporary code - return new UdpEncapsulationSocket(mContext); + return new UdpEncapsulationSocket(mService); } /** @@ -372,8 +370,7 @@ public final class IpSecManager { * @param context the application context for this manager * @hide */ - public IpSecManager(Context context, INetworkManagementService service) { - mContext = checkNotNull(context, "missing context"); + public IpSecManager(IIpSecService service) { mService = checkNotNull(service, "missing service"); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java new file mode 100644 index 0000000000..994adc480f --- /dev/null +++ b/services/core/java/com/android/server/IpSecService.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server; + +import static android.Manifest.permission.DUMP; + +import android.content.Context; +import android.net.IIpSecService; +import android.net.INetd; +import android.net.util.NetdService; +import android.os.RemoteException; +import android.util.Log; +import android.util.Slog; + +import java.io.FileDescriptor; +import java.io.PrintWriter; + +/** @hide */ +public class IpSecService extends IIpSecService.Stub { + private static final String TAG = "IpSecService"; + private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + private static final String NETD_SERVICE_NAME = "netd"; + + /** Binder context for this service */ + private final Context mContext; + + private Object mLock = new Object(); + + private static final int NETD_FETCH_TIMEOUT = 5000; //ms + + /** + * Constructs a new IpSecService instance + * + * @param context Binder context for this service + */ + private IpSecService(Context context) { + mContext = context; + } + + static IpSecService create(Context context) throws InterruptedException { + final IpSecService service = new IpSecService(context); + service.connectNativeNetdService(); + return service; + } + + public void systemReady() { + if (isNetdAlive()) { + Slog.d(TAG, "IpSecService is ready"); + } else { + Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); + } + } + + private void connectNativeNetdService() { + // Avoid blocking the system server to do this + Thread t = + new Thread( + new Runnable() { + @Override + public void run() { + synchronized (mLock) { + NetdService.get(NETD_FETCH_TIMEOUT); + } + } + }); + t.run(); + } + + INetd getNetdInstance() { + final INetd netd = NetdService.getInstance(); + if (netd == null) { + throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer(); + } + return netd; + } + + boolean isNetdAlive() { + synchronized (mLock) { + final INetd netd = getNetdInstance(); + if (netd == null) { + return false; + } + + try { + return netd.isAlive(); + } catch (RemoteException re) { + return false; + } + } + } + + @Override + protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + mContext.enforceCallingOrSelfPermission(DUMP, TAG); + + pw.println("IpSecService Log:"); + pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); + pw.println(); + } +} From 909d66e80a6d2170cbb5dee36f0e63bf0175c931 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 29 Mar 2017 10:47:59 -0700 Subject: [PATCH 0351/1150] Change reserveSecurityParameterIndex() to take a remoteAddress To make the SPI reservation more semantically consistent with the transform creation API, and to ensure that we always create SPI reservations relative to a well-known remote, we should take the SPI request relative to a remote (rather than to a destination). This necessitates that we now consider direction separately, which is used for keying the SA-Id. Bug: 36073210 Test: compilation Change-Id: I81e955c20128c1f8e04fd68eb26669561f827a78 --- core/java/android/net/IpSecManager.java | 26 ++++++++++------------- core/java/android/net/IpSecTransform.java | 4 ++-- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 93a76dfbb4..83f4cc97b8 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -81,7 +81,7 @@ public final class IpSecManager { public static final class SecurityParameterIndex implements AutoCloseable { private final IIpSecService mService; - private final InetAddress mDestinationAddress; + private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi; @@ -91,10 +91,10 @@ public final class IpSecManager { } private SecurityParameterIndex( - IIpSecService service, InetAddress destinationAddress, int spi) + IIpSecService service, int direction, InetAddress remoteAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; - mDestinationAddress = destinationAddress; + mRemoteAddress = remoteAddress; mSpi = spi; mCloseGuard.open("open"); } @@ -102,13 +102,9 @@ public final class IpSecManager { /** * Release an SPI that was previously reserved. * - *

            Release an SPI for use by other users in the system. This will fail if the SPI is - * currently in use by an IpSecTransform. - * - * @param destinationAddress SPIs must be unique for each combination of SPI and destination - * address. Thus, the destinationAddress to which the SPI will communicate must be - * supplied. - * @param spi the previously reserved SPI to be freed. + *

            Release an SPI for use by other users in the system. If a SecurityParameterIndex is + * applied to an IpSecTransform, it will become unusable for future transforms but should + * still be closed to ensure system resources are released. */ @Override public void close() { @@ -134,13 +130,13 @@ public final class IpSecManager { public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** - * Reserve an SPI for traffic bound towards the specified destination address. + * Reserve an SPI for traffic bound towards the specified remote address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param destinationAddress SPIs must be unique for each combination of SPI and destination - * address. + * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated @@ -148,9 +144,9 @@ public final class IpSecManager { * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( - InetAddress destinationAddress, int requestedSpi) + int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); } /** diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index d6dd28bec3..5c0bbe6a14 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -307,7 +307,7 @@ public final class IpSecTransform implements AutoCloseable { *

            Care should be chosen when selecting an SPI to ensure that is is as unique as * possible. Random number generation is a reasonable approach to selecting an SPI. For * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will * fail to build. * *

            Unless an SPI is set for a given direction, traffic in that direction will be @@ -329,7 +329,7 @@ public final class IpSecTransform implements AutoCloseable { *

            Care should be chosen when selecting an SPI to ensure that is is as unique as * possible. Random number generation is a reasonable approach to selecting an SPI. For * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will * fail to activate. * *

            Unless an SPI is set for a given direction, traffic in that direction will be From 55e8910aa8ad2b2bad4ac97af637de33f605e188 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 30 Mar 2017 11:01:37 -0700 Subject: [PATCH 0352/1150] IpSecManager and IpSecTransform API Cleanup -Remove Int-based SPI usage from the IpSecTransform.Builder This is essentially a less-safe method overload, and it is both unnecessary and difficult to implement: the cross-validation between SPI and Transform is actually useful, and the kernel requires two different mechanisms to use an unreserved vs a reserved (alloc'd) SPI: CREATESA vs UPDATESA, which makes this hard to support. API Council has questioned the value of this, and they are right: everything points to "remove this". In the future, if we find that SPI reservation is overhead, we can always add it back. -Hiding the TunnelMode builder method and application/remove methods. These will not land by the time the next API stabilizes, so better to hide them now that this is a near-certainty. Expectation is to un-hide them in the subsequent API bump. Bug: 36073210 Test: Compilation, verified nobody is calling these stubs Change-Id: Ic1a3f2cf7128633318ac175d6b56b45eb8d21cab --- core/java/android/net/IpSecManager.java | 2 -- core/java/android/net/IpSecTransform.java | 30 +++-------------------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 83f4cc97b8..3fcdb7e28c 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -197,7 +197,6 @@ public final class IpSecManager { * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @hide */ - @SystemApi public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} /** @@ -242,7 +241,6 @@ public final class IpSecManager { * network * @hide */ - @SystemApi public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} /** diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 5c0bbe6a14..74d60106c0 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -305,32 +305,9 @@ public final class IpSecTransform implements AutoCloseable { * given destination address. * *

            Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. Random number generation is a reasonable approach to selecting an SPI. For - * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will - * fail to build. - * - *

            Unless an SPI is set for a given direction, traffic in that direction will be - * sent/received without any IPsec applied. - * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} - * @param spi a unique 32-bit integer to identify transformed traffic - */ - public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) { - mConfig.flow[direction].spi = spi; - return this; - } - - /** - * Set the SPI, which uniquely identifies a particular IPsec session from others. Because - * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a - * given destination address. - * - *

            Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. Random number generation is a reasonable approach to selecting an SPI. For - * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will - * fail to activate. + * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int, + * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being + * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}. * *

            Unless an SPI is set for a given direction, traffic in that direction will be * sent/received without any IPsec applied. @@ -447,7 +424,6 @@ public final class IpSecTransform implements AutoCloseable { * properties is invalid. * @hide */ - @SystemApi public IpSecTransform buildTunnelModeTransform( InetAddress localAddress, InetAddress remoteAddress) { //FIXME: argument validation here From 031acb850ff1763a5db86752a4b0e1892aebbeed Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 7 Mar 2017 13:23:36 -0800 Subject: [PATCH 0353/1150] Add Initial IPsec APIs to IpSecService -Plumb IpSecManager APIs to NetD -Add Resource Management to IpSecService Bug: 33695893 Test: CTS verifies nearly all of these paths Change-Id: Ic43965c6158f28cac53810adbf5cf50d2c54f920 --- core/java/android/net/IIpSecService.aidl | 22 + core/java/android/net/IpSecAlgorithm.java | 2 + core/java/android/net/IpSecConfig.java | 70 ++-- core/java/android/net/IpSecManager.java | 112 ++++- core/java/android/net/IpSecTransform.java | 141 ++++--- .../java/com/android/server/IpSecService.java | 396 +++++++++++++++++- 6 files changed, 619 insertions(+), 124 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index b8737fef72..0aa3ce66eb 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -16,9 +16,31 @@ package android.net; +import android.net.Network; +import android.net.IpSecConfig; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + /** * @hide */ interface IIpSecService { + Bundle reserveSecurityParameterIndex( + int direction, in String remoteAddress, int requestedSpi, in IBinder binder); + + void releaseSecurityParameterIndex(int resourceId); + + Bundle openUdpEncapsulationSocket(int port, in IBinder binder); + + void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket); + + Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder); + + void deleteTransportModeTransform(int transformId); + + void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + + void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); } diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index da5cb37961..7fea4a25ca 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -164,6 +164,8 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { + case ALGO_CRYPT_AES_CBC: + return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); case ALGO_AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); case ALGO_AUTH_HMAC_SHA1: diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index b58bf421a8..13dc19f685 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -23,7 +23,7 @@ import java.net.UnknownHostException; /** @hide */ public final class IpSecConfig implements Parcelable { - private static final String TAG = IpSecConfig.class.getSimpleName(); + private static final String TAG = "IpSecConfig"; //MODE_TRANSPORT or MODE_TUNNEL int mode; @@ -43,13 +43,13 @@ public final class IpSecConfig implements Parcelable { int spi; // Encryption Algorithm - IpSecAlgorithm encryptionAlgo; + IpSecAlgorithm encryption; // Authentication Algorithm - IpSecAlgorithm authenticationAlgo; + IpSecAlgorithm authentication; } - Flow[] flow = new Flow[2]; + Flow[] flow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE @@ -57,17 +57,15 @@ public final class IpSecConfig implements Parcelable { int encapLocalPort; int encapRemotePort; - // An optional protocol to match with the selector - int selectorProto; - - // A bitmask of FEATURE_* indicating which of the fields - // of this class are valid. - long features; - // An interval, in seconds between the NattKeepalive packets int nattKeepaliveInterval; - public InetAddress getLocalIp() { + // Transport or Tunnel + public int getMode() { + return mode; + } + + public InetAddress getLocalAddress() { return localAddress; } @@ -75,19 +73,19 @@ public final class IpSecConfig implements Parcelable { return flow[direction].spi; } - public InetAddress getRemoteIp() { + public InetAddress getRemoteAddress() { return remoteAddress; } - public IpSecAlgorithm getEncryptionAlgo(int direction) { - return flow[direction].encryptionAlgo; + public IpSecAlgorithm getEncryption(int direction) { + return flow[direction].encryption; } - public IpSecAlgorithm getAuthenticationAlgo(int direction) { - return flow[direction].authenticationAlgo; + public IpSecAlgorithm getAuthentication(int direction) { + return flow[direction].authentication; } - Network getNetwork() { + public Network getNetwork() { return network; } @@ -103,18 +101,10 @@ public final class IpSecConfig implements Parcelable { return encapRemotePort; } - public int getSelectorProto() { - return selectorProto; - } - - int getNattKeepaliveInterval() { + public int getNattKeepaliveInterval() { return nattKeepaliveInterval; } - public boolean hasProperty(int featureBits) { - return (features & featureBits) == featureBits; - } - // Parcelable Methods @Override @@ -124,31 +114,25 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeLong(features); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); out.writeParcelable(network, flags); out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); out.writeInt(encapType); out.writeInt(encapLocalPort); out.writeInt(encapRemotePort); - out.writeInt(selectorProto); } // Package Private: Used by the IpSecTransform.Builder; // there should be no public constructor for this object - IpSecConfig() { - flow[IpSecTransform.DIRECTION_IN].spi = 0; - flow[IpSecTransform.DIRECTION_OUT].spi = 0; - nattKeepaliveInterval = 0; //FIXME constant - } + IpSecConfig() {} private static InetAddress readInetAddressFromParcel(Parcel in) { String addrString = in.readString(); @@ -164,24 +148,22 @@ public final class IpSecConfig implements Parcelable { } private IpSecConfig(Parcel in) { - features = in.readLong(); localAddress = readInetAddressFromParcel(in); remoteAddress = readInetAddressFromParcel(in); network = (Network) in.readParcelable(Network.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); - flow[IpSecTransform.DIRECTION_IN].encryptionAlgo = + flow[IpSecTransform.DIRECTION_IN].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_IN].authenticationAlgo = + flow[IpSecTransform.DIRECTION_IN].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); - flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo = + flow[IpSecTransform.DIRECTION_OUT].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo = + flow[IpSecTransform.DIRECTION_OUT].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); encapType = in.readInt(); encapLocalPort = in.readInt(); encapRemotePort = in.readInt(); - selectorProto = in.readInt(); } public static final Parcelable.Creator CREATOR = diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 3fcdb7e28c..6852beb065 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -17,8 +17,11 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; -import android.annotation.SystemApi; +import android.annotation.NonNull; +import android.os.Binder; +import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.util.AndroidException; import dalvik.system.CloseGuard; import java.io.FileDescriptor; @@ -38,6 +41,29 @@ import java.net.Socket; public final class IpSecManager { private static final String TAG = "IpSecManager"; + /** + * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. + * + *

            No IPsec packet may contain an SPI of 0. + */ + public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + + /** @hide */ + public interface Status { + public static final int OK = 0; + public static final int RESOURCE_UNAVAILABLE = 1; + public static final int SPI_UNAVAILABLE = 2; + } + + /** @hide */ + public static final String KEY_STATUS = "status"; + /** @hide */ + public static final String KEY_RESOURCE_ID = "resourceId"; + /** @hide */ + public static final String KEY_SPI = "spi"; + /** @hide */ + public static final int INVALID_RESOURCE_ID = 0; + /** * Indicates that the combination of remote InetAddress and SPI was non-unique for a given * request. If encountered, selection of a new SPI is required before a transform may be @@ -83,22 +109,14 @@ public final class IpSecManager { private final IIpSecService mService; private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); - private int mSpi; + private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; + private int mResourceId; /** Return the underlying SPI held by this object */ public int getSpi() { return mSpi; } - private SecurityParameterIndex( - IIpSecService service, int direction, InetAddress remoteAddress, int spi) - throws ResourceUnavailableException, SpiUnavailableException { - mService = service; - mRemoteAddress = remoteAddress; - mSpi = spi; - mCloseGuard.open("open"); - } - /** * Release an SPI that was previously reserved. * @@ -108,7 +126,7 @@ public final class IpSecManager { */ @Override public void close() { - mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI + mSpi = INVALID_SECURITY_PARAMETER_INDEX; mCloseGuard.close(); } @@ -120,14 +138,52 @@ public final class IpSecManager { close(); } - } - /** - * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. - * - *

            No IPsec packet may contain an SPI of 0. - */ - public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + private SecurityParameterIndex( + @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) + throws ResourceUnavailableException, SpiUnavailableException { + mService = service; + mRemoteAddress = remoteAddress; + try { + Bundle result = + mService.reserveSecurityParameterIndex( + direction, remoteAddress.getHostAddress(), spi, new Binder()); + + if (result == null) { + throw new NullPointerException("Received null response from IpSecService"); + } + + int status = result.getInt(KEY_STATUS); + switch (status) { + case Status.OK: + break; + case Status.RESOURCE_UNAVAILABLE: + throw new ResourceUnavailableException( + "No more SPIs may be allocated by this requester."); + case Status.SPI_UNAVAILABLE: + throw new SpiUnavailableException("Requested SPI is unavailable", spi); + default: + throw new RuntimeException( + "Unknown status returned by IpSecService: " + status); + } + mSpi = result.getInt(KEY_SPI); + mResourceId = result.getInt(KEY_RESOURCE_ID); + + if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { + throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); + } + + if (mResourceId == INVALID_RESOURCE_ID) { + throw new RuntimeException( + "Invalid Resource ID returned by IpSecService: " + status); + } + + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mCloseGuard.open("open"); + } + } /** * Reserve an SPI for traffic bound towards the specified remote address. @@ -184,7 +240,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ - private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + try { + mService.applyTransportModeTransform(pfd, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to @@ -228,7 +290,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ - private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + try { + mService.removeTransportModeTransform(pfd, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of @@ -255,7 +323,7 @@ public final class IpSecManager { private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); - private UdpEncapsulationSocket(IIpSecService service, int port) + private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) throws ResourceUnavailableException { mService = service; mCloseGuard.open("constructor"); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 74d60106c0..801e98c7b1 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -15,11 +15,21 @@ */ package android.net; +import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static android.net.IpSecManager.KEY_RESOURCE_ID; +import static android.net.IpSecManager.KEY_STATUS; + import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; -import android.system.ErrnoException; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; +import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.IOException; import java.lang.annotation.Retention; @@ -86,39 +96,64 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} - /** - * Sentinel for an invalid transform (means that this transform is inactive). - * - * @hide - */ - public static final int INVALID_TRANSFORM_ID = -1; - private IpSecTransform(Context context, IpSecConfig config) { mContext = context; mConfig = config; - mTransformId = INVALID_TRANSFORM_ID; + mResourceId = INVALID_RESOURCE_ID; + } + + private IIpSecService getIpSecService() { + IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE); + if (b == null) { + throw new RemoteException("Failed to connect to IpSecService") + .rethrowAsRuntimeException(); + } + + return IIpSecService.Stub.asInterface(b); + } + + private void checkResultStatusAndThrow(int status) + throws IOException, IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException { + switch (status) { + case IpSecManager.Status.OK: + return; + // TODO: Pass Error string back from bundle so that errors can be more specific + case IpSecManager.Status.RESOURCE_UNAVAILABLE: + throw new IpSecManager.ResourceUnavailableException( + "Failed to allocate a new IpSecTransform"); + case IpSecManager.Status.SPI_UNAVAILABLE: + Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); + // Fall through + default: + throw new IllegalStateException( + "Failed to Create a Transform with status code " + status); + } } private IpSecTransform activate() throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { - int transformId; synchronized (this) { - //try { - transformId = INVALID_TRANSFORM_ID; - //} catch (RemoteException e) { - // throw e.rethrowFromSystemServer(); - //} + try { + IIpSecService svc = getIpSecService(); + Bundle result = svc.createTransportModeTransform(mConfig, new Binder()); + int status = result.getInt(KEY_STATUS); + checkResultStatusAndThrow(status); + mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); - if (transformId < 0) { - throw new ErrnoException("addTransform", -transformId).rethrowAsIOException(); + /* Keepalive will silently fail if not needed by the config; but, if needed and + * it fails to start, we need to bail because a transform will not be reliable + * to use if keepalive is expected to offload and fails. + */ + // FIXME: if keepalive fails, we need to fail spectacularly + startKeepalive(mContext); + Log.d(TAG, "Added Transform with Id " + mResourceId); + mCloseGuard.open("build"); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); } - - startKeepalive(mContext); // Will silently fail if not required - mTransformId = transformId; - Log.d(TAG, "Added Transform with Id " + transformId); } - mCloseGuard.open("build"); return this; } @@ -133,21 +168,27 @@ public final class IpSecTransform implements AutoCloseable { * transform is no longer needed. */ public void close() { - Log.d(TAG, "Removing Transform with Id " + mTransformId); + Log.d(TAG, "Removing Transform with Id " + mResourceId); // Always safe to attempt cleanup - if (mTransformId == INVALID_TRANSFORM_ID) { + if (mResourceId == INVALID_RESOURCE_ID) { + mCloseGuard.close(); return; } - //try { - stopKeepalive(); - //} catch (RemoteException e) { - // transform.setTransformId(transformId); - // throw e.rethrowFromSystemServer(); - //} finally { - mTransformId = INVALID_TRANSFORM_ID; - //} - mCloseGuard.close(); + try { + /* Order matters here because the keepalive is best-effort but could fail in some + * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we + * still want to clear out the transform. + */ + IIpSecService svc = getIpSecService(); + svc.deleteTransportModeTransform(mResourceId); + stopKeepalive(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); + } } @Override @@ -164,7 +205,7 @@ public final class IpSecTransform implements AutoCloseable { } private final IpSecConfig mConfig; - private int mTransformId; + private int mResourceId; private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); private ConnectivityManager.PacketKeepalive mKeepalive; @@ -200,6 +241,7 @@ public final class IpSecTransform implements AutoCloseable { /* Package */ void startKeepalive(Context c) { + // FIXME: NO_KEEPALIVE needs to be a constant if (mConfig.getNattKeepaliveInterval() == 0) { return; } @@ -208,7 +250,7 @@ public final class IpSecTransform implements AutoCloseable { (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); if (mKeepalive != null) { - Log.e(TAG, "Keepalive already started for this IpSecTransform."); + Log.wtf(TAG, "Keepalive already started for this IpSecTransform."); return; } @@ -218,10 +260,11 @@ public final class IpSecTransform implements AutoCloseable { mConfig.getNetwork(), mConfig.getNattKeepaliveInterval(), mKeepaliveCallback, - mConfig.getLocalIp(), + mConfig.getLocalAddress(), mConfig.getEncapLocalPort(), - mConfig.getRemoteIp()); + mConfig.getRemoteAddress()); try { + // FIXME: this is still a horrible way to fudge the synchronous callback mKeepaliveSyncLock.wait(2000); } catch (InterruptedException e) { } @@ -231,6 +274,11 @@ public final class IpSecTransform implements AutoCloseable { } } + /* Package */ + int getResourceId() { + return mResourceId; + } + /* Package */ void stopKeepalive() { if (mKeepalive == null) { @@ -247,16 +295,6 @@ public final class IpSecTransform implements AutoCloseable { } } - /* Package */ - void setTransformId(int transformId) { - mTransformId = transformId; - } - - /* Package */ - int getTransformId() { - return mTransformId; - } - /** * Builder object to facilitate the creation of IpSecTransform objects. * @@ -280,7 +318,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].encryptionAlgo = algo; + mConfig.flow[direction].encryption = algo; return this; } @@ -295,7 +333,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].authenticationAlgo = algo; + mConfig.flow[direction].authentication = algo; return this; } @@ -318,6 +356,8 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { + // TODO: convert to using the resource Id of the SPI. Then build() can validate + // the owner in the IpSecService mConfig.flow[direction].spi = spi.getSpi(); return this; } @@ -439,7 +479,8 @@ public final class IpSecTransform implements AutoCloseable { * * @param context current Context */ - public Builder(Context context) { + public Builder(@NonNull Context context) { + Preconditions.checkNotNull(context); mContext = context; mConfig = new IpSecConfig(); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 994adc480f..a7ce95ba0c 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -17,23 +17,40 @@ package com.android.server; import static android.Manifest.permission.DUMP; +import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static android.net.IpSecManager.KEY_RESOURCE_ID; +import static android.net.IpSecManager.KEY_SPI; +import static android.net.IpSecManager.KEY_STATUS; import android.content.Context; import android.net.IIpSecService; import android.net.INetd; +import android.net.IpSecAlgorithm; +import android.net.IpSecConfig; +import android.net.IpSecManager; +import android.net.IpSecTransform; import android.net.util.NetdService; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.util.Log; import android.util.Slog; - +import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicInteger; /** @hide */ public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final String NETD_SERVICE_NAME = "netd"; + private static final int[] DIRECTIONS = + new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; /** Binder context for this service */ private final Context mContext; @@ -42,6 +59,159 @@ public class IpSecService extends IIpSecService.Stub { private static final int NETD_FETCH_TIMEOUT = 5000; //ms + private AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); + + private abstract class ManagedResource implements IBinder.DeathRecipient { + final int pid; + final int uid; + private IBinder mBinder; + + ManagedResource(IBinder binder) { + super(); + mBinder = binder; + pid = Binder.getCallingPid(); + uid = Binder.getCallingUid(); + + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + + /** + * When this record is no longer needed for managing system resources this function should + * unlink all references held by the record to allow efficient garbage collection. + */ + public final void release() { + //Release all the underlying system resources first + releaseResources(); + + if (mBinder != null) { + mBinder.unlinkToDeath(this, 0); + } + mBinder = null; + + //remove this record so that it can be cleaned up + nullifyRecord(); + } + + /** + * If the Binder object dies, this function is called to free the system resources that are + * being managed by this record and to subsequently release this record for garbage + * collection + */ + public final void binderDied() { + release(); + } + + /** + * Implement this method to release all object references contained in the subclass to allow + * efficient garbage collection of the record. This should remove any references to the + * record from all other locations that hold a reference as the record is no longer valid. + */ + protected abstract void nullifyRecord(); + + /** + * Implement this method to release all system resources that are being protected by this + * record. Once the resources are released, the record should be invalidated and no longer + * used by calling releaseRecord() + */ + protected abstract void releaseResources(); + }; + + private final class TransformRecord extends ManagedResource { + private IpSecConfig mConfig; + private int mResourceId; + + TransformRecord(IpSecConfig config, int resourceId, IBinder binder) { + super(binder); + mConfig = config; + mResourceId = resourceId; + } + + public IpSecConfig getConfig() { + return mConfig; + } + + @Override + protected void releaseResources() { + for (int direction : DIRECTIONS) { + try { + getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, + direction, + (mConfig.getLocalAddress() != null) + ? mConfig.getLocalAddress().getHostAddress() + : "", + (mConfig.getRemoteAddress() != null) + ? mConfig.getRemoteAddress().getHostAddress() + : "", + mConfig.getSpi(direction)); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); + } + } + } + + @Override + protected void nullifyRecord() { + mConfig = null; + mResourceId = INVALID_RESOURCE_ID; + } + } + + private final class SpiRecord extends ManagedResource { + private final int mDirection; + private final String mLocalAddress; + private final String mRemoteAddress; + private final IBinder mBinder; + private int mSpi; + private int mResourceId; + + SpiRecord( + int resourceId, + int direction, + String localAddress, + String remoteAddress, + int spi, + IBinder binder) { + super(binder); + mResourceId = resourceId; + mDirection = direction; + mLocalAddress = localAddress; + mRemoteAddress = remoteAddress; + mSpi = spi; + mBinder = binder; + } + + protected void releaseResources() { + try { + getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); + } + } + + protected void nullifyRecord() { + mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + mResourceId = INVALID_RESOURCE_ID; + } + } + + @GuardedBy("mSpiRecords") + private final SparseArray mSpiRecords = new SparseArray<>(); + + @GuardedBy("mTransformRecords") + private final SparseArray mTransformRecords = new SparseArray<>(); + /** * Constructs a new IpSecService instance * @@ -80,22 +250,21 @@ public class IpSecService extends IIpSecService.Stub { t.run(); } - INetd getNetdInstance() { + INetd getNetdInstance() throws RemoteException { final INetd netd = NetdService.getInstance(); if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer(); + throw new RemoteException("Failed to Get Netd Instance"); } return netd; } boolean isNetdAlive() { synchronized (mLock) { - final INetd netd = getNetdInstance(); - if (netd == null) { - return false; - } - try { + final INetd netd = getNetdInstance(); + if (netd == null) { + return false; + } return netd.isAlive(); } catch (RemoteException re) { return false; @@ -103,6 +272,217 @@ public class IpSecService extends IIpSecService.Stub { } } + @Override + /** Get a new SPI and maintain the reservation in the system server */ + public Bundle reserveSecurityParameterIndex( + int direction, String remoteAddress, int requestedSpi, IBinder binder) + throws RemoteException { + int resourceId = mNextResourceId.getAndIncrement(); + + int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + String localAddress = ""; + Bundle retBundle = new Bundle(3); + try { + spi = + getNetdInstance() + .ipSecAllocateSpi( + resourceId, + direction, + localAddress, + remoteAddress, + requestedSpi); + Log.d(TAG, "Allocated SPI " + spi); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + retBundle.putInt(KEY_SPI, spi); + synchronized (mSpiRecords) { + mSpiRecords.put( + resourceId, + new SpiRecord( + resourceId, direction, localAddress, remoteAddress, spi, binder)); + } + } catch (ServiceSpecificException e) { + // TODO: Add appropriate checks when other ServiceSpecificException types are supported + retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + retBundle.putInt(KEY_SPI, spi); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return retBundle; + } + + /** Release a previously allocated SPI that has been registered with the system server */ + @Override + public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {} + + /** + * Open a socket via the system server and bind it to the specified port (random if port=0). + * This will return a PFD to the user that represent a bound UDP socket. The system server will + * cache the socket and a record of its owner so that it can and must be freed when no longer + * needed. + */ + @Override + public Bundle openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException { + return null; + } + + /** close a socket that has been been allocated by and registered with the system server */ + @Override + public void closeUdpEncapsulationSocket(ParcelFileDescriptor socket) {} + + /** + * Create a transport mode transform, which represent two security associations (one in each + * direction) in the kernel. The transform will be cached by the system server and must be freed + * when no longer needed. It is possible to free one, deleting the SA from underneath sockets + * that are using it, which will result in all of those sockets becoming unable to send or + * receive data. + */ + @Override + public Bundle createTransportModeTransform(IpSecConfig c, IBinder binder) + throws RemoteException { + // TODO: Basic input validation here since it's coming over the Binder + int resourceId = mNextResourceId.getAndIncrement(); + for (int direction : DIRECTIONS) { + IpSecAlgorithm auth = c.getAuthentication(direction); + IpSecAlgorithm crypt = c.getEncryption(direction); + try { + int result = + getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + (c.getNetwork() != null) + ? c.getNetwork().getNetworkHandle() + : 0, + c.getSpi(direction), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : null, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : null, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + c.getEncapType(), + c.getEncapLocalPort(), + c.getEncapRemotePort()); + if (result != c.getSpi(direction)) { + // TODO: cleanup the first SA if creation of second SA fails + Bundle retBundle = new Bundle(2); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); + retBundle.putInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); + return retBundle; + } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + synchronized (mTransformRecords) { + mTransformRecords.put(resourceId, new TransformRecord(c, resourceId, binder)); + } + + Bundle retBundle = new Bundle(2); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + return retBundle; + } + + /** + * Delete a transport mode transform that was previously allocated by + registered with the + * system server. If this is called on an inactive (or non-existent) transform, it will not + * return an error. It's safe to de-allocate transforms that may have already been deleted for + * other reasons. + */ + @Override + public void deleteTransportModeTransform(int resourceId) throws RemoteException { + synchronized (mTransformRecords) { + TransformRecord record; + // We want to non-destructively get so that we can check credentials before removing + // this from the records. + record = mTransformRecords.get(resourceId); + + if (record == null) { + throw new IllegalArgumentException( + "Transform " + resourceId + " is not available to be deleted"); + } + + if (record.pid != Binder.getCallingPid() || record.uid != Binder.getCallingUid()) { + throw new SecurityException("Only the owner of an IpSec Transform may delete it!"); + } + + // TODO: if releaseResources() throws RemoteException, we can try again to clean up on + // binder death. Need to make sure that path is actually functional. + record.releaseResources(); + mTransformRecords.remove(resourceId); + record.nullifyRecord(); + } + } + + /** + * Apply an active transport mode transform to a socket, which will apply the IPsec security + * association as a correspondent policy to the provided socket + */ + @Override + public void applyTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + throws RemoteException { + + synchronized (mTransformRecords) { + TransformRecord info; + // FIXME: this code should be factored out into a security check + getter + info = mTransformRecords.get(resourceId); + + if (info == null) { + throw new IllegalArgumentException("Transform " + resourceId + " is not active"); + } + + // TODO: make this a function. + if (info.pid != getCallingPid() || info.uid != getCallingUid()) { + throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); + } + + IpSecConfig c = info.getConfig(); + try { + for (int direction : DIRECTIONS) { + getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + c.getSpi(direction)); + } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + } + /** + * Remove a transport mode transform from a socket, applying the default (empty) policy. This + * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of + * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not + * used: reserved for future improved input validation. + */ + @Override + public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + throws RemoteException { + try { + getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); From f1077c30952f17a34b545ac3374625c0d8be1bd3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 31 Mar 2017 14:08:23 -0600 Subject: [PATCH 0354/1150] Consistent dump() permission checking. This change introduces new methods on DumpUtils that can check if the caller has DUMP and/or PACKAGE_USAGE_STATS access. It then moves all existing dump() methods to use these checks so that we emit consistent error messages. Test: cts-tradefed run commandAndExit cts-dev -m CtsSecurityTestCases -t android.security.cts.ServicePermissionsTest Bug: 32806790 Change-Id: Iaff6b9506818ee082b1e169c89ebe1001b3bfeca --- services/core/java/com/android/server/NsdService.java | 9 ++------- .../java/com/android/server/net/NetworkStatsService.java | 3 ++- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index a44b065d42..8ae95d5ada 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -41,6 +41,7 @@ import java.util.HashMap; import java.util.concurrent.CountDownLatch; import com.android.internal.util.AsyncChannel; +import com.android.internal.util.DumpUtils; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -811,13 +812,7 @@ public class NsdService extends INsdManager.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) - != PackageManager.PERMISSION_GRANTED) { - pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid=" - + Binder.getCallingPid() - + ", uid=" + Binder.getCallingUid()); - return; - } + if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; for (ClientInfo client : mClients.values()) { pw.println("Client Info"); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 6d666e890f..e746355097 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -122,6 +122,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; @@ -1234,7 +1235,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { - mContext.enforceCallingOrSelfPermission(DUMP, TAG); + if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; long duration = DateUtils.DAY_IN_MILLIS; final HashSet argSet = new HashSet(); From 32be63d083539cabd4ae677e5167d7ac5153ee87 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 5 Apr 2017 14:06:11 +0900 Subject: [PATCH 0355/1150] Nsdmanager/NsdService: add logging This patch adds basic logging to NsdManager and NsdService, and improves the facilities for pretty printing the event ids defined in NsdManager. It also includes a few minor cleanups: - adding 'final' on effectively final instance variables of NsdManager and NsdService. - similarly, adding 'static' on effectively static class fields. - regrouping instance variables together. Test: no functional changes Bug: 33074219 Change-Id: I360d539e73cc8e4b45d4e0d20b2e345455fdb10c --- core/java/android/net/nsd/NsdManager.java | 49 ++++++-- .../java/com/android/server/NsdService.java | 107 +++++++++--------- 2 files changed, 94 insertions(+), 62 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 33d12a3a3f..1dde3cad23 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -45,7 +45,7 @@ import com.android.internal.util.Protocol; * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * *

            The API is asynchronous and responses to requests from an application are on listener - * callbacks on a seperate thread. + * callbacks on a seperate internal thread. * *

            There are three main operations the API supports - registration, discovery and resolution. *

            @@ -119,8 +119,8 @@ import com.android.internal.util.Protocol;
              * {@see NsdServiceInfo}
              */
             public final class NsdManager {
            -    private static final String TAG = "NsdManager";
            -    INsdManager mService;
            +    private static final String TAG = NsdManager.class.getSimpleName();
            +    private static final boolean DBG = false;
             
                 /**
                  * Broadcast intent action to indicate whether network service discovery is
            @@ -130,8 +130,7 @@ public final class NsdManager {
                  * @see #EXTRA_NSD_STATE
                  */
                 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
            -    public static final String ACTION_NSD_STATE_CHANGED =
            -        "android.net.nsd.STATE_CHANGED";
            +    public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
             
                 /**
                  * The lookup key for an int that indicates whether network service discovery is enabled
            @@ -208,13 +207,47 @@ public final class NsdManager {
                 /** Dns based service discovery protocol */
                 public static final int PROTOCOL_DNS_SD = 0x0001;
             
            -    private Context mContext;
            +    private static final SparseArray EVENT_NAMES = new SparseArray<>();
            +    static {
            +        EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES");
            +        EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED");
            +        EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED");
            +        EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
            +        EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
            +        EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY");
            +        EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED");
            +        EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED");
            +        EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE");
            +        EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED");
            +        EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
            +        EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
            +        EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(ENABLE, "ENABLE");
            +        EVENT_NAMES.put(DISABLE, "DISABLE");
            +        EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
            +    }
            +
            +    /** @hide */
            +    public static String nameOf(int event) {
            +        String name = EVENT_NAMES.get(event);
            +        if (name == null) {
            +            return Integer.toString(event);
            +        }
            +        return name;
            +    }
            +
            +    private final INsdManager mService;
            +    private final Context mContext;
             
                 private static final int INVALID_LISTENER_KEY = 0;
                 private static final int BUSY_LISTENER_KEY = -1;
                 private int mListenerKey = 1;
                 private final SparseArray mListenerMap = new SparseArray();
            -    private final SparseArray mServiceMap = new SparseArray();
            +    private final SparseArray mServiceMap = new SparseArray<>();
                 private final Object mMapLock = new Object();
             
                 private final AsyncChannel mAsyncChannel = new AsyncChannel();
            @@ -300,6 +333,7 @@ public final class NsdManager {
             
                     @Override
                     public void handleMessage(Message message) {
            +            if (DBG) Log.d(TAG, "received " + nameOf(message.what));
                         switch (message.what) {
                             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                                 mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
            @@ -377,7 +411,6 @@ public final class NsdManager {
             
                 // if the listener is already in the map, reject it.  Otherwise, add it and
                 // return its key.
            -
                 private int putListener(Object listener, NsdServiceInfo s) {
                     if (listener == null) return INVALID_LISTENER_KEY;
                     int key;
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index a44b065d42..121e0fb552 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -56,46 +56,27 @@ public class NsdService extends INsdManager.Stub {
                 private static final String TAG = "NsdService";
                 private static final String MDNS_TAG = "mDnsConnector";
             
            -    private static final boolean DBG = false;
            +    private static final boolean DBG = true;
             
            -    private Context mContext;
            -    private ContentResolver mContentResolver;
            -    private NsdStateMachine mNsdStateMachine;
            +    private final Context mContext;
            +    private final ContentResolver mContentResolver;
            +    private final NsdStateMachine mNsdStateMachine;
            +    private final NativeDaemonConnector mNativeConnector;
            +    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
             
                 /**
                  * Clients receiving asynchronous messages
                  */
            -    private HashMap mClients = new HashMap();
            +    private final HashMap mClients = new HashMap<>();
             
                 /* A map from unique id to client info */
            -    private SparseArray mIdToClientInfoMap= new SparseArray();
            +    private final SparseArray mIdToClientInfoMap= new SparseArray<>();
             
            -    private AsyncChannel mReplyChannel = new AsyncChannel();
            +    private final AsyncChannel mReplyChannel = new AsyncChannel();
             
            -    private int INVALID_ID = 0;
            +    private static final int INVALID_ID = 0;
                 private int mUniqueId = 1;
             
            -    private static final int BASE = Protocol.BASE_NSD_MANAGER;
            -    private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
            -    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
            -
            -    static {
            -        sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
            -        sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
            -        sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
            -        sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
            -        sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
            -    }
            -
            -    private static String cmdToString(int cmd) {
            -        cmd -= BASE;
            -        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
            -            return sCmdToString[cmd];
            -        } else {
            -            return null;
            -        }
            -    }
            -
                 private class NsdStateMachine extends StateMachine {
             
                     private final DefaultState mDefaultState = new DefaultState();
            @@ -104,7 +85,7 @@ public class NsdService extends INsdManager.Stub {
             
                     @Override
                     protected String getWhatToString(int what) {
            -            return cmdToString(what);
            +            return NsdManager.nameOf(what);
                     }
             
                     /**
            @@ -113,13 +94,13 @@ public class NsdService extends INsdManager.Stub {
                     private void registerForNsdSetting() {
                         ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
                             @Override
            -                    public void onChange(boolean selfChange) {
            -                        if (isNsdEnabled()) {
            -                            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
            -                        } else {
            -                            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
            -                        }
            +                public void onChange(boolean selfChange) {
            +                    if (isNsdEnabled()) {
            +                        mNsdStateMachine.sendMessage(NsdManager.ENABLE);
            +                    } else {
            +                        mNsdStateMachine.sendMessage(NsdManager.DISABLE);
                                 }
            +                }
                         };
             
                         mContext.getContentResolver().registerContentObserver(
            @@ -411,7 +392,8 @@ public class NsdService extends INsdManager.Stub {
                             int id = Integer.parseInt(cooked[1]);
                             ClientInfo clientInfo = mIdToClientInfoMap.get(id);
                             if (clientInfo == null) {
            -                    Slog.e(TAG, "Unique id with no client mapping: " + id);
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
                                 handled = false;
                                 return handled;
                             }
            @@ -422,42 +404,43 @@ public class NsdService extends INsdManager.Stub {
                                 // This can happen because of race conditions. For example,
                                 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
                                 // and we may get in this situation.
            -                    Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.d(TAG, String.format(
            +                            "Notification %s for listener id %d that is no longer active",
            +                            name, id));
                                 handled = false;
                                 return handled;
                             }
            -
            +                if (DBG) {
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
            +                }
                             switch (code) {
                                 case NativeResponseCode.SERVICE_FOUND:
                                     /* NNN uniqueId serviceName regType domain */
            -                        if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                                     clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
                                             clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_LOST:
                                     /* NNN uniqueId serviceName regType domain */
            -                        if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                                     clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
                                             clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
                                     /* NNN uniqueId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
                                             NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
                                 case NativeResponseCode.SERVICE_REGISTERED:
                                     /* NNN regId serviceName regType */
            -                        if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], null);
                                     clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
                                             id, clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
                                     /* NNN regId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
                                            NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
            @@ -469,7 +452,6 @@ public class NsdService extends INsdManager.Stub {
                                     break;
                                 case NativeResponseCode.SERVICE_RESOLVED:
                                     /* NNN resolveId fullName hostName port txtlen txtdata */
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
                                     int index = 0;
                                     while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
                                         if (cooked[2].charAt(index) == '\\') {
            @@ -506,7 +488,6 @@ public class NsdService extends INsdManager.Stub {
                                     break;
                                 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
                                     /* NNN resolveId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
                                     stopResolveService(id);
                                     removeRequestMap(clientId, id, clientInfo);
                                     clientInfo.mResolvedService = null;
            @@ -518,13 +499,11 @@ public class NsdService extends INsdManager.Stub {
                                     stopGetAddrInfo(id);
                                     removeRequestMap(clientId, id, clientInfo);
                                     clientInfo.mResolvedService = null;
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
                                             NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
                                 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
                                     /* NNN resolveId hostname ttl addr */
            -                        if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
                                     try {
                                         clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
                                         clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
            @@ -570,9 +549,6 @@ public class NsdService extends INsdManager.Stub {
                     return sb.toString();
                 }
             
            -    private NativeDaemonConnector mNativeConnector;
            -    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
            -
                 private NsdService(Context context) {
                     mContext = context;
                     mContentResolver = context.getContentResolver();
            @@ -633,7 +609,7 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 /* These should be in sync with system/netd/server/ResponseCode.h */
            -    class NativeResponseCode {
            +    static final class NativeResponseCode {
                     public static final int SERVICE_DISCOVERY_FAILED    =   602;
                     public static final int SERVICE_FOUND               =   603;
                     public static final int SERVICE_LOST                =   604;
            @@ -649,6 +625,29 @@ public class NsdService extends INsdManager.Stub {
             
                     public static final int SERVICE_GET_ADDR_FAILED     =   611;
                     public static final int SERVICE_GET_ADDR_SUCCESS    =   612;
            +
            +        private static final SparseArray CODE_NAMES = new SparseArray<>();
            +        static {
            +            CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
            +            CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
            +            CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
            +            CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
            +            CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
            +            CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
            +            CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
            +            CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
            +            CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
            +            CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
            +            CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
            +        }
            +
            +        static String nameOf(int code) {
            +            String name = CODE_NAMES.get(code);
            +            if (name == null) {
            +                return Integer.toString(code);
            +            }
            +            return name;
            +        }
                 }
             
                 private class NativeEvent {
            @@ -868,10 +867,10 @@ public class NsdService extends INsdManager.Stub {
                     private NsdServiceInfo mResolvedService;
             
                     /* A map from client id to unique id sent to mDns */
            -        private SparseArray mClientIds = new SparseArray();
            +        private final SparseArray mClientIds = new SparseArray<>();
             
                     /* A map from client id to the type of the request we had received */
            -        private SparseArray mClientRequests = new SparseArray();
            +        private final SparseArray mClientRequests = new SparseArray<>();
             
                     private ClientInfo(AsyncChannel c, Messenger m) {
                         mChannel = c;
            
            From f0c840913d1ac48d3128a5c54074e4bcb08abceb Mon Sep 17 00:00:00 2001
            From: Hugo Benichi 
            Date: Wed, 5 Apr 2017 14:43:29 +0900
            Subject: [PATCH 0356/1150] NsdService: minor cleanups
            
            Minor cleanups in switches of processMessage and handleNativeEvent.
            
            Test: no functional changes
            Bug: 33074219
            Change-Id: I9ad4ce812c0d2c02a671a7a871ad427e4ce29b4a
            ---
             .../java/com/android/server/NsdService.java   | 28 +++++++------------
             1 file changed, 10 insertions(+), 18 deletions(-)
            
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index 121e0fb552..a691af9c01 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -252,20 +252,17 @@ public class NsdService extends INsdManager.Stub {
                         public boolean processMessage(Message msg) {
                             ClientInfo clientInfo;
                             NsdServiceInfo servInfo;
            -                boolean result = HANDLED;
                             int id;
                             switch (msg.what) {
            -                  case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
            +                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                                     //First client
                                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
                                             mClients.size() == 0) {
                                         startMDnsDaemon();
                                     }
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                                 case NsdManager.DISABLE:
                                     //TODO: cleanup clients
                                     transitionTo(mDisabledState);
            @@ -376,26 +373,23 @@ public class NsdService extends INsdManager.Stub {
                                 case NsdManager.NATIVE_DAEMON_EVENT:
                                     NativeEvent event = (NativeEvent) msg.obj;
                                     if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
            -                            result = NOT_HANDLED;
            +                            return NOT_HANDLED;
                                     }
                                     break;
                                 default:
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                             }
            -                return result;
            +                return HANDLED;
                         }
             
                         private boolean handleNativeEvent(int code, String raw, String[] cooked) {
            -                boolean handled = true;
                             NsdServiceInfo servInfo;
                             int id = Integer.parseInt(cooked[1]);
                             ClientInfo clientInfo = mIdToClientInfoMap.get(id);
                             if (clientInfo == null) {
                                 String name = NativeResponseCode.nameOf(code);
                                 Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
            -                    handled = false;
            -                    return handled;
            +                    return false;
                             }
             
                             /* This goes in response as msg.arg2 */
            @@ -408,8 +402,7 @@ public class NsdService extends INsdManager.Stub {
                                 Slog.d(TAG, String.format(
                                         "Notification %s for listener id %d that is no longer active",
                                         name, id));
            -                    handled = false;
            -                    return handled;
            +                    return false;
                             }
                             if (DBG) {
                                 String name = NativeResponseCode.nameOf(code);
            @@ -517,10 +510,9 @@ public class NsdService extends INsdManager.Stub {
                                     clientInfo.mResolvedService = null;
                                     break;
                                 default:
            -                        handled = false;
            -                        break;
            +                        return false;
                             }
            -                return handled;
            +                return true;
                         }
                    }
                 }
            
            From 8ea66052f2c2b31506884bd7c691d1ab90d3bacc Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Wed, 1 Mar 2017 18:55:06 -0800
            Subject: [PATCH 0357/1150] Add a Skeleton IpSecService
            
            -Add IpSecService with the necessary glue to connect to netd
            -Add code to retrieve IpSecService from System Server
            
            Bug: 30984788
            Test: b/34812052, b/34811227
            Change-Id: I4cdcb643421141202f77a0e2f87a37012de0cd92
            (cherry picked from commit 28084d89ec136b56f5012be33a0dea147962f9f6)
            ---
             core/java/android/net/IIpSecService.aidl      |  24 ++++
             core/java/android/net/IpSecManager.java       |  31 +++--
             .../java/com/android/server/IpSecService.java | 114 ++++++++++++++++++
             3 files changed, 152 insertions(+), 17 deletions(-)
             create mode 100644 core/java/android/net/IIpSecService.aidl
             create mode 100644 services/core/java/com/android/server/IpSecService.java
            
            diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl
            new file mode 100644
            index 0000000000..b8737fef72
            --- /dev/null
            +++ b/core/java/android/net/IIpSecService.aidl
            @@ -0,0 +1,24 @@
            +/*
            +** Copyright 2017, The Android Open Source Project
            +**
            +** Licensed under the Apache License, Version 2.0 (the "License");
            +** you may not use this file except in compliance with the License.
            +** You may obtain a copy of the License at
            +**
            +**     http://www.apache.org/licenses/LICENSE-2.0
            +**
            +** Unless required by applicable law or agreed to in writing, software
            +** distributed under the License is distributed on an "AS IS" BASIS,
            +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            +** See the License for the specific language governing permissions and
            +** limitations under the License.
            +*/
            +
            +package android.net;
            +
            +/**
            + * @hide
            + */
            +interface IIpSecService
            +{
            +}
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 2c544e9b9b..93a76dfbb4 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -18,8 +18,6 @@ package android.net;
             import static com.android.internal.util.Preconditions.checkNotNull;
             
             import android.annotation.SystemApi;
            -import android.content.Context;
            -import android.os.INetworkManagementService;
             import android.os.ParcelFileDescriptor;
             import android.util.AndroidException;
             import dalvik.system.CloseGuard;
            @@ -79,11 +77,10 @@ public final class IpSecManager {
                     }
                 }
             
            -    private final Context mContext;
            -    private final INetworkManagementService mService;
            +    private final IIpSecService mService;
             
                 public static final class SecurityParameterIndex implements AutoCloseable {
            -        private final Context mContext;
            +        private final IIpSecService mService;
                     private final InetAddress mDestinationAddress;
                     private final CloseGuard mCloseGuard = CloseGuard.get();
                     private int mSpi;
            @@ -93,9 +90,10 @@ public final class IpSecManager {
                         return mSpi;
                     }
             
            -        private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
            +        private SecurityParameterIndex(
            +                IIpSecService service, InetAddress destinationAddress, int spi)
                             throws ResourceUnavailableException, SpiUnavailableException {
            -            mContext = context;
            +            mService = service;
                         mDestinationAddress = destinationAddress;
                         mSpi = spi;
                         mCloseGuard.open("open");
            @@ -152,7 +150,7 @@ public final class IpSecManager {
                 public SecurityParameterIndex reserveSecurityParameterIndex(
                         InetAddress destinationAddress, int requestedSpi)
                         throws SpiUnavailableException, ResourceUnavailableException {
            -        return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
            +        return new SecurityParameterIndex(mService, destinationAddress, requestedSpi);
                 }
             
                 /**
            @@ -260,19 +258,19 @@ public final class IpSecManager {
                  */
                 public static final class UdpEncapsulationSocket implements AutoCloseable {
                     private final FileDescriptor mFd;
            -        private final Context mContext;
            +        private final IIpSecService mService;
                     private final CloseGuard mCloseGuard = CloseGuard.get();
             
            -        private UdpEncapsulationSocket(Context context, int port)
            +        private UdpEncapsulationSocket(IIpSecService service, int port)
                             throws ResourceUnavailableException {
            -            mContext = context;
            +            mService = service;
                         mCloseGuard.open("constructor");
                         // TODO: go down to the kernel and get a socket on the specified
                         mFd = new FileDescriptor();
                     }
             
            -        private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
            -            mContext = context;
            +        private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException {
            +            mService = service;
                         mCloseGuard.open("constructor");
                         // TODO: go get a random socket on a random port
                         mFd = new FileDescriptor();
            @@ -339,7 +337,7 @@ public final class IpSecManager {
                 public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
                         throws IOException, ResourceUnavailableException {
                     // Temporary code
            -        return new UdpEncapsulationSocket(mContext, port);
            +        return new UdpEncapsulationSocket(mService, port);
                 }
             
                 /**
            @@ -363,7 +361,7 @@ public final class IpSecManager {
                 public UdpEncapsulationSocket openUdpEncapsulationSocket()
                         throws IOException, ResourceUnavailableException {
                     // Temporary code
            -        return new UdpEncapsulationSocket(mContext);
            +        return new UdpEncapsulationSocket(mService);
                 }
             
                 /**
            @@ -372,8 +370,7 @@ public final class IpSecManager {
                  * @param context the application context for this manager
                  * @hide
                  */
            -    public IpSecManager(Context context, INetworkManagementService service) {
            -        mContext = checkNotNull(context, "missing context");
            +    public IpSecManager(IIpSecService service) {
                     mService = checkNotNull(service, "missing service");
                 }
             }
            diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
            new file mode 100644
            index 0000000000..994adc480f
            --- /dev/null
            +++ b/services/core/java/com/android/server/IpSecService.java
            @@ -0,0 +1,114 @@
            +/*
            + * Copyright (C) 2017 The Android Open Source Project
            + *
            + * Licensed under the Apache License, Version 2.0 (the "License");
            + * you may not use this file except in compliance with the License.
            + * You may obtain a copy of the License at
            + *
            + *      http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +
            +package com.android.server;
            +
            +import static android.Manifest.permission.DUMP;
            +
            +import android.content.Context;
            +import android.net.IIpSecService;
            +import android.net.INetd;
            +import android.net.util.NetdService;
            +import android.os.RemoteException;
            +import android.util.Log;
            +import android.util.Slog;
            +
            +import java.io.FileDescriptor;
            +import java.io.PrintWriter;
            +
            +/** @hide */
            +public class IpSecService extends IIpSecService.Stub {
            +    private static final String TAG = "IpSecService";
            +    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
            +    private static final String NETD_SERVICE_NAME = "netd";
            +
            +    /** Binder context for this service */
            +    private final Context mContext;
            +
            +    private Object mLock = new Object();
            +
            +    private static final int NETD_FETCH_TIMEOUT = 5000; //ms
            +
            +    /**
            +     * Constructs a new IpSecService instance
            +     *
            +     * @param context Binder context for this service
            +     */
            +    private IpSecService(Context context) {
            +        mContext = context;
            +    }
            +
            +    static IpSecService create(Context context) throws InterruptedException {
            +        final IpSecService service = new IpSecService(context);
            +        service.connectNativeNetdService();
            +        return service;
            +    }
            +
            +    public void systemReady() {
            +        if (isNetdAlive()) {
            +            Slog.d(TAG, "IpSecService is ready");
            +        } else {
            +            Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!");
            +        }
            +    }
            +
            +    private void connectNativeNetdService() {
            +        // Avoid blocking the system server to do this
            +        Thread t =
            +                new Thread(
            +                        new Runnable() {
            +                            @Override
            +                            public void run() {
            +                                synchronized (mLock) {
            +                                    NetdService.get(NETD_FETCH_TIMEOUT);
            +                                }
            +                            }
            +                        });
            +        t.run();
            +    }
            +
            +    INetd getNetdInstance() {
            +        final INetd netd = NetdService.getInstance();
            +        if (netd == null) {
            +            throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer();
            +        }
            +        return netd;
            +    }
            +
            +    boolean isNetdAlive() {
            +        synchronized (mLock) {
            +            final INetd netd = getNetdInstance();
            +            if (netd == null) {
            +                return false;
            +            }
            +
            +            try {
            +                return netd.isAlive();
            +            } catch (RemoteException re) {
            +                return false;
            +            }
            +        }
            +    }
            +
            +    @Override
            +    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
            +        mContext.enforceCallingOrSelfPermission(DUMP, TAG);
            +
            +        pw.println("IpSecService Log:");
            +        pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead"));
            +        pw.println();
            +    }
            +}
            
            From b9feffd1dd1b5abaf5699f2deeea99aa2da78300 Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Wed, 29 Mar 2017 10:47:59 -0700
            Subject: [PATCH 0358/1150] Change reserveSecurityParameterIndex() to take a
             remoteAddress
            
            To make the SPI reservation more semantically consistent with the
            transform creation API, and to ensure that we always create SPI
            reservations relative to a well-known remote, we should take the
            SPI request relative to a remote (rather than to a destination).
            This necessitates that we now consider direction separately, which
            is used for keying the SA-Id.
            
            Bug: 36073210
            Test: compilation
            Change-Id: I81e955c20128c1f8e04fd68eb26669561f827a78
            (cherry picked from commit 909d66e80a6d2170cbb5dee36f0e63bf0175c931)
            ---
             core/java/android/net/IpSecManager.java   | 26 ++++++++++-------------
             core/java/android/net/IpSecTransform.java |  4 ++--
             2 files changed, 13 insertions(+), 17 deletions(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 93a76dfbb4..83f4cc97b8 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -81,7 +81,7 @@ public final class IpSecManager {
             
                 public static final class SecurityParameterIndex implements AutoCloseable {
                     private final IIpSecService mService;
            -        private final InetAddress mDestinationAddress;
            +        private final InetAddress mRemoteAddress;
                     private final CloseGuard mCloseGuard = CloseGuard.get();
                     private int mSpi;
             
            @@ -91,10 +91,10 @@ public final class IpSecManager {
                     }
             
                     private SecurityParameterIndex(
            -                IIpSecService service, InetAddress destinationAddress, int spi)
            +                IIpSecService service, int direction, InetAddress remoteAddress, int spi)
                             throws ResourceUnavailableException, SpiUnavailableException {
                         mService = service;
            -            mDestinationAddress = destinationAddress;
            +            mRemoteAddress = remoteAddress;
                         mSpi = spi;
                         mCloseGuard.open("open");
                     }
            @@ -102,13 +102,9 @@ public final class IpSecManager {
                     /**
                      * Release an SPI that was previously reserved.
                      *
            -         * 

            Release an SPI for use by other users in the system. This will fail if the SPI is - * currently in use by an IpSecTransform. - * - * @param destinationAddress SPIs must be unique for each combination of SPI and destination - * address. Thus, the destinationAddress to which the SPI will communicate must be - * supplied. - * @param spi the previously reserved SPI to be freed. + *

            Release an SPI for use by other users in the system. If a SecurityParameterIndex is + * applied to an IpSecTransform, it will become unusable for future transforms but should + * still be closed to ensure system resources are released. */ @Override public void close() { @@ -134,13 +130,13 @@ public final class IpSecManager { public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** - * Reserve an SPI for traffic bound towards the specified destination address. + * Reserve an SPI for traffic bound towards the specified remote address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param destinationAddress SPIs must be unique for each combination of SPI and destination - * address. + * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated @@ -148,9 +144,9 @@ public final class IpSecManager { * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( - InetAddress destinationAddress, int requestedSpi) + int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); } /** diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index d6dd28bec3..5c0bbe6a14 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -307,7 +307,7 @@ public final class IpSecTransform implements AutoCloseable { *

            Care should be chosen when selecting an SPI to ensure that is is as unique as * possible. Random number generation is a reasonable approach to selecting an SPI. For * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will * fail to build. * *

            Unless an SPI is set for a given direction, traffic in that direction will be @@ -329,7 +329,7 @@ public final class IpSecTransform implements AutoCloseable { *

            Care should be chosen when selecting an SPI to ensure that is is as unique as * possible. Random number generation is a reasonable approach to selecting an SPI. For * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will + * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will * fail to activate. * *

            Unless an SPI is set for a given direction, traffic in that direction will be From 4ee4a82e7ddbf90d3ad573af5d104c4152b937fc Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 30 Mar 2017 11:01:37 -0700 Subject: [PATCH 0359/1150] IpSecManager and IpSecTransform API Cleanup -Remove Int-based SPI usage from the IpSecTransform.Builder This is essentially a less-safe method overload, and it is both unnecessary and difficult to implement: the cross-validation between SPI and Transform is actually useful, and the kernel requires two different mechanisms to use an unreserved vs a reserved (alloc'd) SPI: CREATESA vs UPDATESA, which makes this hard to support. API Council has questioned the value of this, and they are right: everything points to "remove this". In the future, if we find that SPI reservation is overhead, we can always add it back. -Hiding the TunnelMode builder method and application/remove methods. These will not land by the time the next API stabilizes, so better to hide them now that this is a near-certainty. Expectation is to un-hide them in the subsequent API bump. Bug: 36073210 Test: Compilation, verified nobody is calling these stubs Change-Id: Ic1a3f2cf7128633318ac175d6b56b45eb8d21cab (cherry picked from commit 48b566557d5a66d4476008b3c59b815eb78cb373) --- core/java/android/net/IpSecManager.java | 2 -- core/java/android/net/IpSecTransform.java | 30 +++-------------------- 2 files changed, 3 insertions(+), 29 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 83f4cc97b8..3fcdb7e28c 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -197,7 +197,6 @@ public final class IpSecManager { * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @hide */ - @SystemApi public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} /** @@ -242,7 +241,6 @@ public final class IpSecManager { * network * @hide */ - @SystemApi public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} /** diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 5c0bbe6a14..74d60106c0 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -305,32 +305,9 @@ public final class IpSecTransform implements AutoCloseable { * given destination address. * *

            Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. Random number generation is a reasonable approach to selecting an SPI. For - * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will - * fail to build. - * - *

            Unless an SPI is set for a given direction, traffic in that direction will be - * sent/received without any IPsec applied. - * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} - * @param spi a unique 32-bit integer to identify transformed traffic - */ - public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) { - mConfig.flow[direction].spi = spi; - return this; - } - - /** - * Set the SPI, which uniquely identifies a particular IPsec session from others. Because - * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a - * given destination address. - * - *

            Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. Random number generation is a reasonable approach to selecting an SPI. For - * outbound SPIs, they must be reserved by calling {@link - * IpSecManager#reserveSecurityParameterIndex(int, InetAddress, int)}. Otherwise, Transforms will - * fail to activate. + * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int, + * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being + * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}. * *

            Unless an SPI is set for a given direction, traffic in that direction will be * sent/received without any IPsec applied. @@ -447,7 +424,6 @@ public final class IpSecTransform implements AutoCloseable { * properties is invalid. * @hide */ - @SystemApi public IpSecTransform buildTunnelModeTransform( InetAddress localAddress, InetAddress remoteAddress) { //FIXME: argument validation here From 2af3baeddc5f43ba6602e25101a3f1593a66dd95 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 7 Mar 2017 13:23:36 -0800 Subject: [PATCH 0360/1150] Add Initial IPsec APIs to IpSecService -Plumb IpSecManager APIs to NetD -Add Resource Management to IpSecService Bug: 30984788 Test: b/34812052, b/34811227 Change-Id: Ic43965c6158f28cac53810adbf5cf50d2c54f920 (cherry picked from commit 93962f34ce21f5aac825afbcebf2f3e8c7a30910) --- core/java/android/net/IIpSecService.aidl | 22 + core/java/android/net/IpSecAlgorithm.java | 2 + core/java/android/net/IpSecConfig.java | 70 ++-- core/java/android/net/IpSecManager.java | 112 ++++- core/java/android/net/IpSecTransform.java | 141 ++++--- .../java/com/android/server/IpSecService.java | 396 +++++++++++++++++- 6 files changed, 619 insertions(+), 124 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index b8737fef72..0aa3ce66eb 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -16,9 +16,31 @@ package android.net; +import android.net.Network; +import android.net.IpSecConfig; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; + /** * @hide */ interface IIpSecService { + Bundle reserveSecurityParameterIndex( + int direction, in String remoteAddress, int requestedSpi, in IBinder binder); + + void releaseSecurityParameterIndex(int resourceId); + + Bundle openUdpEncapsulationSocket(int port, in IBinder binder); + + void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket); + + Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder); + + void deleteTransportModeTransform(int transformId); + + void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + + void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); } diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index da5cb37961..7fea4a25ca 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -164,6 +164,8 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { + case ALGO_CRYPT_AES_CBC: + return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); case ALGO_AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); case ALGO_AUTH_HMAC_SHA1: diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index b58bf421a8..13dc19f685 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -23,7 +23,7 @@ import java.net.UnknownHostException; /** @hide */ public final class IpSecConfig implements Parcelable { - private static final String TAG = IpSecConfig.class.getSimpleName(); + private static final String TAG = "IpSecConfig"; //MODE_TRANSPORT or MODE_TUNNEL int mode; @@ -43,13 +43,13 @@ public final class IpSecConfig implements Parcelable { int spi; // Encryption Algorithm - IpSecAlgorithm encryptionAlgo; + IpSecAlgorithm encryption; // Authentication Algorithm - IpSecAlgorithm authenticationAlgo; + IpSecAlgorithm authentication; } - Flow[] flow = new Flow[2]; + Flow[] flow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE @@ -57,17 +57,15 @@ public final class IpSecConfig implements Parcelable { int encapLocalPort; int encapRemotePort; - // An optional protocol to match with the selector - int selectorProto; - - // A bitmask of FEATURE_* indicating which of the fields - // of this class are valid. - long features; - // An interval, in seconds between the NattKeepalive packets int nattKeepaliveInterval; - public InetAddress getLocalIp() { + // Transport or Tunnel + public int getMode() { + return mode; + } + + public InetAddress getLocalAddress() { return localAddress; } @@ -75,19 +73,19 @@ public final class IpSecConfig implements Parcelable { return flow[direction].spi; } - public InetAddress getRemoteIp() { + public InetAddress getRemoteAddress() { return remoteAddress; } - public IpSecAlgorithm getEncryptionAlgo(int direction) { - return flow[direction].encryptionAlgo; + public IpSecAlgorithm getEncryption(int direction) { + return flow[direction].encryption; } - public IpSecAlgorithm getAuthenticationAlgo(int direction) { - return flow[direction].authenticationAlgo; + public IpSecAlgorithm getAuthentication(int direction) { + return flow[direction].authentication; } - Network getNetwork() { + public Network getNetwork() { return network; } @@ -103,18 +101,10 @@ public final class IpSecConfig implements Parcelable { return encapRemotePort; } - public int getSelectorProto() { - return selectorProto; - } - - int getNattKeepaliveInterval() { + public int getNattKeepaliveInterval() { return nattKeepaliveInterval; } - public boolean hasProperty(int featureBits) { - return (features & featureBits) == featureBits; - } - // Parcelable Methods @Override @@ -124,31 +114,25 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - out.writeLong(features); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); out.writeParcelable(network, flags); out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); + out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); out.writeInt(encapType); out.writeInt(encapLocalPort); out.writeInt(encapRemotePort); - out.writeInt(selectorProto); } // Package Private: Used by the IpSecTransform.Builder; // there should be no public constructor for this object - IpSecConfig() { - flow[IpSecTransform.DIRECTION_IN].spi = 0; - flow[IpSecTransform.DIRECTION_OUT].spi = 0; - nattKeepaliveInterval = 0; //FIXME constant - } + IpSecConfig() {} private static InetAddress readInetAddressFromParcel(Parcel in) { String addrString = in.readString(); @@ -164,24 +148,22 @@ public final class IpSecConfig implements Parcelable { } private IpSecConfig(Parcel in) { - features = in.readLong(); localAddress = readInetAddressFromParcel(in); remoteAddress = readInetAddressFromParcel(in); network = (Network) in.readParcelable(Network.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); - flow[IpSecTransform.DIRECTION_IN].encryptionAlgo = + flow[IpSecTransform.DIRECTION_IN].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_IN].authenticationAlgo = + flow[IpSecTransform.DIRECTION_IN].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); - flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo = + flow[IpSecTransform.DIRECTION_OUT].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo = + flow[IpSecTransform.DIRECTION_OUT].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); encapType = in.readInt(); encapLocalPort = in.readInt(); encapRemotePort = in.readInt(); - selectorProto = in.readInt(); } public static final Parcelable.Creator CREATOR = diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 3fcdb7e28c..6852beb065 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -17,8 +17,11 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; -import android.annotation.SystemApi; +import android.annotation.NonNull; +import android.os.Binder; +import android.os.Bundle; import android.os.ParcelFileDescriptor; +import android.os.RemoteException; import android.util.AndroidException; import dalvik.system.CloseGuard; import java.io.FileDescriptor; @@ -38,6 +41,29 @@ import java.net.Socket; public final class IpSecManager { private static final String TAG = "IpSecManager"; + /** + * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. + * + *

            No IPsec packet may contain an SPI of 0. + */ + public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + + /** @hide */ + public interface Status { + public static final int OK = 0; + public static final int RESOURCE_UNAVAILABLE = 1; + public static final int SPI_UNAVAILABLE = 2; + } + + /** @hide */ + public static final String KEY_STATUS = "status"; + /** @hide */ + public static final String KEY_RESOURCE_ID = "resourceId"; + /** @hide */ + public static final String KEY_SPI = "spi"; + /** @hide */ + public static final int INVALID_RESOURCE_ID = 0; + /** * Indicates that the combination of remote InetAddress and SPI was non-unique for a given * request. If encountered, selection of a new SPI is required before a transform may be @@ -83,22 +109,14 @@ public final class IpSecManager { private final IIpSecService mService; private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); - private int mSpi; + private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; + private int mResourceId; /** Return the underlying SPI held by this object */ public int getSpi() { return mSpi; } - private SecurityParameterIndex( - IIpSecService service, int direction, InetAddress remoteAddress, int spi) - throws ResourceUnavailableException, SpiUnavailableException { - mService = service; - mRemoteAddress = remoteAddress; - mSpi = spi; - mCloseGuard.open("open"); - } - /** * Release an SPI that was previously reserved. * @@ -108,7 +126,7 @@ public final class IpSecManager { */ @Override public void close() { - mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI + mSpi = INVALID_SECURITY_PARAMETER_INDEX; mCloseGuard.close(); } @@ -120,14 +138,52 @@ public final class IpSecManager { close(); } - } - /** - * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. - * - *

            No IPsec packet may contain an SPI of 0. - */ - public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + private SecurityParameterIndex( + @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) + throws ResourceUnavailableException, SpiUnavailableException { + mService = service; + mRemoteAddress = remoteAddress; + try { + Bundle result = + mService.reserveSecurityParameterIndex( + direction, remoteAddress.getHostAddress(), spi, new Binder()); + + if (result == null) { + throw new NullPointerException("Received null response from IpSecService"); + } + + int status = result.getInt(KEY_STATUS); + switch (status) { + case Status.OK: + break; + case Status.RESOURCE_UNAVAILABLE: + throw new ResourceUnavailableException( + "No more SPIs may be allocated by this requester."); + case Status.SPI_UNAVAILABLE: + throw new SpiUnavailableException("Requested SPI is unavailable", spi); + default: + throw new RuntimeException( + "Unknown status returned by IpSecService: " + status); + } + mSpi = result.getInt(KEY_SPI); + mResourceId = result.getInt(KEY_RESOURCE_ID); + + if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { + throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); + } + + if (mResourceId == INVALID_RESOURCE_ID) { + throw new RuntimeException( + "Invalid Resource ID returned by IpSecService: " + status); + } + + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mCloseGuard.open("open"); + } + } /** * Reserve an SPI for traffic bound towards the specified remote address. @@ -184,7 +240,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ - private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + try { + mService.applyTransportModeTransform(pfd, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to @@ -228,7 +290,13 @@ public final class IpSecManager { } /* Call down to activate a transform */ - private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {} + private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + try { + mService.removeTransportModeTransform(pfd, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } /** * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of @@ -255,7 +323,7 @@ public final class IpSecManager { private final IIpSecService mService; private final CloseGuard mCloseGuard = CloseGuard.get(); - private UdpEncapsulationSocket(IIpSecService service, int port) + private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) throws ResourceUnavailableException { mService = service; mCloseGuard.open("constructor"); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 74d60106c0..801e98c7b1 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -15,11 +15,21 @@ */ package android.net; +import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static android.net.IpSecManager.KEY_RESOURCE_ID; +import static android.net.IpSecManager.KEY_STATUS; + import android.annotation.IntDef; +import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; -import android.system.ErrnoException; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; +import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.IOException; import java.lang.annotation.Retention; @@ -86,39 +96,64 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} - /** - * Sentinel for an invalid transform (means that this transform is inactive). - * - * @hide - */ - public static final int INVALID_TRANSFORM_ID = -1; - private IpSecTransform(Context context, IpSecConfig config) { mContext = context; mConfig = config; - mTransformId = INVALID_TRANSFORM_ID; + mResourceId = INVALID_RESOURCE_ID; + } + + private IIpSecService getIpSecService() { + IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE); + if (b == null) { + throw new RemoteException("Failed to connect to IpSecService") + .rethrowAsRuntimeException(); + } + + return IIpSecService.Stub.asInterface(b); + } + + private void checkResultStatusAndThrow(int status) + throws IOException, IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException { + switch (status) { + case IpSecManager.Status.OK: + return; + // TODO: Pass Error string back from bundle so that errors can be more specific + case IpSecManager.Status.RESOURCE_UNAVAILABLE: + throw new IpSecManager.ResourceUnavailableException( + "Failed to allocate a new IpSecTransform"); + case IpSecManager.Status.SPI_UNAVAILABLE: + Log.wtf(TAG, "Attempting to use an SPI that was somehow not reserved"); + // Fall through + default: + throw new IllegalStateException( + "Failed to Create a Transform with status code " + status); + } } private IpSecTransform activate() throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { - int transformId; synchronized (this) { - //try { - transformId = INVALID_TRANSFORM_ID; - //} catch (RemoteException e) { - // throw e.rethrowFromSystemServer(); - //} + try { + IIpSecService svc = getIpSecService(); + Bundle result = svc.createTransportModeTransform(mConfig, new Binder()); + int status = result.getInt(KEY_STATUS); + checkResultStatusAndThrow(status); + mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); - if (transformId < 0) { - throw new ErrnoException("addTransform", -transformId).rethrowAsIOException(); + /* Keepalive will silently fail if not needed by the config; but, if needed and + * it fails to start, we need to bail because a transform will not be reliable + * to use if keepalive is expected to offload and fails. + */ + // FIXME: if keepalive fails, we need to fail spectacularly + startKeepalive(mContext); + Log.d(TAG, "Added Transform with Id " + mResourceId); + mCloseGuard.open("build"); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); } - - startKeepalive(mContext); // Will silently fail if not required - mTransformId = transformId; - Log.d(TAG, "Added Transform with Id " + transformId); } - mCloseGuard.open("build"); return this; } @@ -133,21 +168,27 @@ public final class IpSecTransform implements AutoCloseable { * transform is no longer needed. */ public void close() { - Log.d(TAG, "Removing Transform with Id " + mTransformId); + Log.d(TAG, "Removing Transform with Id " + mResourceId); // Always safe to attempt cleanup - if (mTransformId == INVALID_TRANSFORM_ID) { + if (mResourceId == INVALID_RESOURCE_ID) { + mCloseGuard.close(); return; } - //try { - stopKeepalive(); - //} catch (RemoteException e) { - // transform.setTransformId(transformId); - // throw e.rethrowFromSystemServer(); - //} finally { - mTransformId = INVALID_TRANSFORM_ID; - //} - mCloseGuard.close(); + try { + /* Order matters here because the keepalive is best-effort but could fail in some + * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we + * still want to clear out the transform. + */ + IIpSecService svc = getIpSecService(); + svc.deleteTransportModeTransform(mResourceId); + stopKeepalive(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); + } } @Override @@ -164,7 +205,7 @@ public final class IpSecTransform implements AutoCloseable { } private final IpSecConfig mConfig; - private int mTransformId; + private int mResourceId; private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); private ConnectivityManager.PacketKeepalive mKeepalive; @@ -200,6 +241,7 @@ public final class IpSecTransform implements AutoCloseable { /* Package */ void startKeepalive(Context c) { + // FIXME: NO_KEEPALIVE needs to be a constant if (mConfig.getNattKeepaliveInterval() == 0) { return; } @@ -208,7 +250,7 @@ public final class IpSecTransform implements AutoCloseable { (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); if (mKeepalive != null) { - Log.e(TAG, "Keepalive already started for this IpSecTransform."); + Log.wtf(TAG, "Keepalive already started for this IpSecTransform."); return; } @@ -218,10 +260,11 @@ public final class IpSecTransform implements AutoCloseable { mConfig.getNetwork(), mConfig.getNattKeepaliveInterval(), mKeepaliveCallback, - mConfig.getLocalIp(), + mConfig.getLocalAddress(), mConfig.getEncapLocalPort(), - mConfig.getRemoteIp()); + mConfig.getRemoteAddress()); try { + // FIXME: this is still a horrible way to fudge the synchronous callback mKeepaliveSyncLock.wait(2000); } catch (InterruptedException e) { } @@ -231,6 +274,11 @@ public final class IpSecTransform implements AutoCloseable { } } + /* Package */ + int getResourceId() { + return mResourceId; + } + /* Package */ void stopKeepalive() { if (mKeepalive == null) { @@ -247,16 +295,6 @@ public final class IpSecTransform implements AutoCloseable { } } - /* Package */ - void setTransformId(int transformId) { - mTransformId = transformId; - } - - /* Package */ - int getTransformId() { - return mTransformId; - } - /** * Builder object to facilitate the creation of IpSecTransform objects. * @@ -280,7 +318,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].encryptionAlgo = algo; + mConfig.flow[direction].encryption = algo; return this; } @@ -295,7 +333,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].authenticationAlgo = algo; + mConfig.flow[direction].authentication = algo; return this; } @@ -318,6 +356,8 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { + // TODO: convert to using the resource Id of the SPI. Then build() can validate + // the owner in the IpSecService mConfig.flow[direction].spi = spi.getSpi(); return this; } @@ -439,7 +479,8 @@ public final class IpSecTransform implements AutoCloseable { * * @param context current Context */ - public Builder(Context context) { + public Builder(@NonNull Context context) { + Preconditions.checkNotNull(context); mContext = context; mConfig = new IpSecConfig(); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 994adc480f..a7ce95ba0c 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -17,23 +17,40 @@ package com.android.server; import static android.Manifest.permission.DUMP; +import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static android.net.IpSecManager.KEY_RESOURCE_ID; +import static android.net.IpSecManager.KEY_SPI; +import static android.net.IpSecManager.KEY_STATUS; import android.content.Context; import android.net.IIpSecService; import android.net.INetd; +import android.net.IpSecAlgorithm; +import android.net.IpSecConfig; +import android.net.IpSecManager; +import android.net.IpSecTransform; import android.net.util.NetdService; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.util.Log; import android.util.Slog; - +import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.concurrent.atomic.AtomicInteger; /** @hide */ public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final String NETD_SERVICE_NAME = "netd"; + private static final int[] DIRECTIONS = + new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; /** Binder context for this service */ private final Context mContext; @@ -42,6 +59,159 @@ public class IpSecService extends IIpSecService.Stub { private static final int NETD_FETCH_TIMEOUT = 5000; //ms + private AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); + + private abstract class ManagedResource implements IBinder.DeathRecipient { + final int pid; + final int uid; + private IBinder mBinder; + + ManagedResource(IBinder binder) { + super(); + mBinder = binder; + pid = Binder.getCallingPid(); + uid = Binder.getCallingUid(); + + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + + /** + * When this record is no longer needed for managing system resources this function should + * unlink all references held by the record to allow efficient garbage collection. + */ + public final void release() { + //Release all the underlying system resources first + releaseResources(); + + if (mBinder != null) { + mBinder.unlinkToDeath(this, 0); + } + mBinder = null; + + //remove this record so that it can be cleaned up + nullifyRecord(); + } + + /** + * If the Binder object dies, this function is called to free the system resources that are + * being managed by this record and to subsequently release this record for garbage + * collection + */ + public final void binderDied() { + release(); + } + + /** + * Implement this method to release all object references contained in the subclass to allow + * efficient garbage collection of the record. This should remove any references to the + * record from all other locations that hold a reference as the record is no longer valid. + */ + protected abstract void nullifyRecord(); + + /** + * Implement this method to release all system resources that are being protected by this + * record. Once the resources are released, the record should be invalidated and no longer + * used by calling releaseRecord() + */ + protected abstract void releaseResources(); + }; + + private final class TransformRecord extends ManagedResource { + private IpSecConfig mConfig; + private int mResourceId; + + TransformRecord(IpSecConfig config, int resourceId, IBinder binder) { + super(binder); + mConfig = config; + mResourceId = resourceId; + } + + public IpSecConfig getConfig() { + return mConfig; + } + + @Override + protected void releaseResources() { + for (int direction : DIRECTIONS) { + try { + getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, + direction, + (mConfig.getLocalAddress() != null) + ? mConfig.getLocalAddress().getHostAddress() + : "", + (mConfig.getRemoteAddress() != null) + ? mConfig.getRemoteAddress().getHostAddress() + : "", + mConfig.getSpi(direction)); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); + } + } + } + + @Override + protected void nullifyRecord() { + mConfig = null; + mResourceId = INVALID_RESOURCE_ID; + } + } + + private final class SpiRecord extends ManagedResource { + private final int mDirection; + private final String mLocalAddress; + private final String mRemoteAddress; + private final IBinder mBinder; + private int mSpi; + private int mResourceId; + + SpiRecord( + int resourceId, + int direction, + String localAddress, + String remoteAddress, + int spi, + IBinder binder) { + super(binder); + mResourceId = resourceId; + mDirection = direction; + mLocalAddress = localAddress; + mRemoteAddress = remoteAddress; + mSpi = spi; + mBinder = binder; + } + + protected void releaseResources() { + try { + getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); + } + } + + protected void nullifyRecord() { + mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + mResourceId = INVALID_RESOURCE_ID; + } + } + + @GuardedBy("mSpiRecords") + private final SparseArray mSpiRecords = new SparseArray<>(); + + @GuardedBy("mTransformRecords") + private final SparseArray mTransformRecords = new SparseArray<>(); + /** * Constructs a new IpSecService instance * @@ -80,22 +250,21 @@ public class IpSecService extends IIpSecService.Stub { t.run(); } - INetd getNetdInstance() { + INetd getNetdInstance() throws RemoteException { final INetd netd = NetdService.getInstance(); if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance").rethrowFromSystemServer(); + throw new RemoteException("Failed to Get Netd Instance"); } return netd; } boolean isNetdAlive() { synchronized (mLock) { - final INetd netd = getNetdInstance(); - if (netd == null) { - return false; - } - try { + final INetd netd = getNetdInstance(); + if (netd == null) { + return false; + } return netd.isAlive(); } catch (RemoteException re) { return false; @@ -103,6 +272,217 @@ public class IpSecService extends IIpSecService.Stub { } } + @Override + /** Get a new SPI and maintain the reservation in the system server */ + public Bundle reserveSecurityParameterIndex( + int direction, String remoteAddress, int requestedSpi, IBinder binder) + throws RemoteException { + int resourceId = mNextResourceId.getAndIncrement(); + + int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + String localAddress = ""; + Bundle retBundle = new Bundle(3); + try { + spi = + getNetdInstance() + .ipSecAllocateSpi( + resourceId, + direction, + localAddress, + remoteAddress, + requestedSpi); + Log.d(TAG, "Allocated SPI " + spi); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + retBundle.putInt(KEY_SPI, spi); + synchronized (mSpiRecords) { + mSpiRecords.put( + resourceId, + new SpiRecord( + resourceId, direction, localAddress, remoteAddress, spi, binder)); + } + } catch (ServiceSpecificException e) { + // TODO: Add appropriate checks when other ServiceSpecificException types are supported + retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + retBundle.putInt(KEY_SPI, spi); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return retBundle; + } + + /** Release a previously allocated SPI that has been registered with the system server */ + @Override + public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {} + + /** + * Open a socket via the system server and bind it to the specified port (random if port=0). + * This will return a PFD to the user that represent a bound UDP socket. The system server will + * cache the socket and a record of its owner so that it can and must be freed when no longer + * needed. + */ + @Override + public Bundle openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException { + return null; + } + + /** close a socket that has been been allocated by and registered with the system server */ + @Override + public void closeUdpEncapsulationSocket(ParcelFileDescriptor socket) {} + + /** + * Create a transport mode transform, which represent two security associations (one in each + * direction) in the kernel. The transform will be cached by the system server and must be freed + * when no longer needed. It is possible to free one, deleting the SA from underneath sockets + * that are using it, which will result in all of those sockets becoming unable to send or + * receive data. + */ + @Override + public Bundle createTransportModeTransform(IpSecConfig c, IBinder binder) + throws RemoteException { + // TODO: Basic input validation here since it's coming over the Binder + int resourceId = mNextResourceId.getAndIncrement(); + for (int direction : DIRECTIONS) { + IpSecAlgorithm auth = c.getAuthentication(direction); + IpSecAlgorithm crypt = c.getEncryption(direction); + try { + int result = + getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + (c.getNetwork() != null) + ? c.getNetwork().getNetworkHandle() + : 0, + c.getSpi(direction), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : null, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : null, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + c.getEncapType(), + c.getEncapLocalPort(), + c.getEncapRemotePort()); + if (result != c.getSpi(direction)) { + // TODO: cleanup the first SA if creation of second SA fails + Bundle retBundle = new Bundle(2); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); + retBundle.putInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); + return retBundle; + } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + synchronized (mTransformRecords) { + mTransformRecords.put(resourceId, new TransformRecord(c, resourceId, binder)); + } + + Bundle retBundle = new Bundle(2); + retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); + retBundle.putInt(KEY_RESOURCE_ID, resourceId); + return retBundle; + } + + /** + * Delete a transport mode transform that was previously allocated by + registered with the + * system server. If this is called on an inactive (or non-existent) transform, it will not + * return an error. It's safe to de-allocate transforms that may have already been deleted for + * other reasons. + */ + @Override + public void deleteTransportModeTransform(int resourceId) throws RemoteException { + synchronized (mTransformRecords) { + TransformRecord record; + // We want to non-destructively get so that we can check credentials before removing + // this from the records. + record = mTransformRecords.get(resourceId); + + if (record == null) { + throw new IllegalArgumentException( + "Transform " + resourceId + " is not available to be deleted"); + } + + if (record.pid != Binder.getCallingPid() || record.uid != Binder.getCallingUid()) { + throw new SecurityException("Only the owner of an IpSec Transform may delete it!"); + } + + // TODO: if releaseResources() throws RemoteException, we can try again to clean up on + // binder death. Need to make sure that path is actually functional. + record.releaseResources(); + mTransformRecords.remove(resourceId); + record.nullifyRecord(); + } + } + + /** + * Apply an active transport mode transform to a socket, which will apply the IPsec security + * association as a correspondent policy to the provided socket + */ + @Override + public void applyTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + throws RemoteException { + + synchronized (mTransformRecords) { + TransformRecord info; + // FIXME: this code should be factored out into a security check + getter + info = mTransformRecords.get(resourceId); + + if (info == null) { + throw new IllegalArgumentException("Transform " + resourceId + " is not active"); + } + + // TODO: make this a function. + if (info.pid != getCallingPid() || info.uid != getCallingUid()) { + throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); + } + + IpSecConfig c = info.getConfig(); + try { + for (int direction : DIRECTIONS) { + getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + c.getSpi(direction)); + } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + } + /** + * Remove a transport mode transform from a socket, applying the default (empty) policy. This + * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of + * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not + * used: reserved for future improved input validation. + */ + @Override + public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + throws RemoteException { + try { + getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); From 0540679eb48f6e590a30943cfaae41370349d0c1 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Apr 2017 18:16:28 -0700 Subject: [PATCH 0361/1150] IpSecManager and IpSecAlgorithm API Tweaks -Add a reserveSecurityParamterIndex() function that allows the system to select an SPI. -Disallow INVALID_SECURITY_PARAMETER_INDEX from being passed as an explicit SPI request. -Remove the ALGO_ prefix from constants in IpSecAlgorithm Bug: 36073210 Test: Updated CTS tests still pass on bullhead Change-Id: Ic94809996076b0718f153f550b82192fe7048a2e --- core/java/android/net/IpSecAlgorithm.java | 34 +++++++++++------------ core/java/android/net/IpSecManager.java | 31 ++++++++++++++++++++- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7fea4a25ca..ce7894fb3b 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -32,7 +32,7 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid lengths for this key are {128, 192, 256}. */ - public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + public static final String CRYPT_AES_CBC = "cbc(aes)"; /** * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new @@ -40,7 +40,7 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ - public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; + public static final String AUTH_HMAC_MD5 = "hmac(md5)"; /** * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in @@ -48,35 +48,35 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. */ - public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; + public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; /** * SHA256 HMAC Authentication/Integrity Algorithm. * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. */ - public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; + public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; /** * SHA384 HMAC Authentication/Integrity Algorithm. * *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ - public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; + public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; /** * SHA512 HMAC Authentication/Integrity Algorithm * *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ - public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; + public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; /** @hide */ @StringDef({ - ALGO_CRYPT_AES_CBC, - ALGO_AUTH_HMAC_MD5, - ALGO_AUTH_HMAC_SHA1, - ALGO_AUTH_HMAC_SHA256, - ALGO_AUTH_HMAC_SHA512 + CRYPT_AES_CBC, + AUTH_HMAC_MD5, + AUTH_HMAC_SHA1, + AUTH_HMAC_SHA256, + AUTH_HMAC_SHA512 }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -164,17 +164,17 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { - case ALGO_CRYPT_AES_CBC: + case CRYPT_AES_CBC: return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); - case ALGO_AUTH_HMAC_MD5: + case AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); - case ALGO_AUTH_HMAC_SHA1: + case AUTH_HMAC_SHA1: return (truncLenBits >= 96 && truncLenBits <= 160); - case ALGO_AUTH_HMAC_SHA256: + case AUTH_HMAC_SHA256: return (truncLenBits >= 96 && truncLenBits <= 256); - case ALGO_AUTH_HMAC_SHA384: + case AUTH_HMAC_SHA384: return (truncLenBits >= 192 && truncLenBits <= 384); - case ALGO_AUTH_HMAC_SHA512: + case AUTH_HMAC_SHA512: return (truncLenBits >= 256 && truncLenBits <= 512); default: return false; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 6852beb065..4bfeb096df 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -193,15 +193,44 @@ public final class IpSecManager { * * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ + public SecurityParameterIndex reserveSecurityParameterIndex( + int direction, InetAddress remoteAddress) + throws ResourceUnavailableException { + try { + return new SecurityParameterIndex( + mService, + direction, + remoteAddress, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (SpiUnavailableException unlikely) { + throw new ResourceUnavailableException("No SPIs available"); + } + } + + /** + * Reserve an SPI for traffic bound towards the specified remote address. + * + *

            If successful, this SPI is guaranteed available until released by a call to {@link + * SecurityParameterIndex#close()}. + * + * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @return the reserved SecurityParameterIndex + * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated + * for this user + */ public SecurityParameterIndex reserveSecurityParameterIndex( int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { + if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { + throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); + } return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); } From 0072e19c8e334a7945a2ccc9f0402ea1c643b25d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Apr 2017 17:46:00 -0700 Subject: [PATCH 0362/1150] Add FileDescriptor Versions of applyTransportModeTransform() Because there is no way using the Java sockets API to actually get a socket of AF_INET on mode machines, it is necessary to provide a way to apply transforms to sockets made using the native wrapper API, which uses POSIX APIs and will create a socket that is AF_INET. Bug: 36073210 Test: b/34811227 Change-Id: I28ac7cc4f36045ce523a54111e5be975b0331356 --- core/java/android/net/IpSecManager.java | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4bfeb096df..f8702e2e00 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -277,6 +277,23 @@ public final class IpSecManager { } } + /** + * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec + * encapsulation of the traffic flowing between the socket and the remote InetAddress of that + * transform. For security reasons, attempts to send traffic to any IP address other than the + * address associated with that transform will throw an IOException. In addition, if the + * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to + * send() or receive() until the transform is removed from the socket by calling {@link + * #removeTransportModeTransform(Socket, IpSecTransform)}; + * + * @param socket a socket file descriptor + * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + */ + public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + throws IOException { + applyTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to @@ -318,6 +335,20 @@ public final class IpSecManager { removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); } + /** + * Remove a transform from a given stream socket. Once removed, traffic on the socket will not + * be encypted. This allows sockets that have been used for IPsec to be reclaimed for + * communication in the clear in the event socket reuse is desired. This operation will succeed + * regardless of the underlying state of a transform. If a transform is removed, communication + * on all sockets to which that transform was applied will fail until this method is called. + * + * @param socket a socket file descriptor that previously had a transform applied to it. + * @param transform the IPsec Transform that was previously applied to the given socket + */ + public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) { + removeTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + /* Call down to activate a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { From 0560678b89cf5f24a30de87d5650abb76333725d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Apr 2017 18:16:28 -0700 Subject: [PATCH 0363/1150] IpSecManager and IpSecAlgorithm API Tweaks -Add a reserveSecurityParamterIndex() function that allows the system to select an SPI. -Disallow INVALID_SECURITY_PARAMETER_INDEX from being passed as an explicit SPI request. -Remove the ALGO_ prefix from constants in IpSecAlgorithm Bug: 36073210 Test: Updated CTS tests still pass on bullhead Change-Id: Ic94809996076b0718f153f550b82192fe7048a2e --- core/java/android/net/IpSecAlgorithm.java | 34 +++++++++++------------ core/java/android/net/IpSecManager.java | 31 ++++++++++++++++++++- 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7fea4a25ca..ce7894fb3b 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -32,7 +32,7 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid lengths for this key are {128, 192, 256}. */ - public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)"; + public static final String CRYPT_AES_CBC = "cbc(aes)"; /** * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new @@ -40,7 +40,7 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ - public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)"; + public static final String AUTH_HMAC_MD5 = "hmac(md5)"; /** * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in @@ -48,35 +48,35 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. */ - public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)"; + public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; /** * SHA256 HMAC Authentication/Integrity Algorithm. * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. */ - public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)"; + public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; /** * SHA384 HMAC Authentication/Integrity Algorithm. * *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ - public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)"; + public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; /** * SHA512 HMAC Authentication/Integrity Algorithm * *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ - public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)"; + public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; /** @hide */ @StringDef({ - ALGO_CRYPT_AES_CBC, - ALGO_AUTH_HMAC_MD5, - ALGO_AUTH_HMAC_SHA1, - ALGO_AUTH_HMAC_SHA256, - ALGO_AUTH_HMAC_SHA512 + CRYPT_AES_CBC, + AUTH_HMAC_MD5, + AUTH_HMAC_SHA1, + AUTH_HMAC_SHA256, + AUTH_HMAC_SHA512 }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -164,17 +164,17 @@ public final class IpSecAlgorithm implements Parcelable { private static boolean isTruncationLengthValid(String algo, int truncLenBits) { switch (algo) { - case ALGO_CRYPT_AES_CBC: + case CRYPT_AES_CBC: return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); - case ALGO_AUTH_HMAC_MD5: + case AUTH_HMAC_MD5: return (truncLenBits >= 96 && truncLenBits <= 128); - case ALGO_AUTH_HMAC_SHA1: + case AUTH_HMAC_SHA1: return (truncLenBits >= 96 && truncLenBits <= 160); - case ALGO_AUTH_HMAC_SHA256: + case AUTH_HMAC_SHA256: return (truncLenBits >= 96 && truncLenBits <= 256); - case ALGO_AUTH_HMAC_SHA384: + case AUTH_HMAC_SHA384: return (truncLenBits >= 192 && truncLenBits <= 384); - case ALGO_AUTH_HMAC_SHA512: + case AUTH_HMAC_SHA512: return (truncLenBits >= 256 && truncLenBits <= 512); default: return false; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 6852beb065..4bfeb096df 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -193,15 +193,44 @@ public final class IpSecManager { * * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ + public SecurityParameterIndex reserveSecurityParameterIndex( + int direction, InetAddress remoteAddress) + throws ResourceUnavailableException { + try { + return new SecurityParameterIndex( + mService, + direction, + remoteAddress, + IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (SpiUnavailableException unlikely) { + throw new ResourceUnavailableException("No SPIs available"); + } + } + + /** + * Reserve an SPI for traffic bound towards the specified remote address. + * + *

            If successful, this SPI is guaranteed available until released by a call to {@link + * SecurityParameterIndex#close()}. + * + * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @return the reserved SecurityParameterIndex + * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated + * for this user + */ public SecurityParameterIndex reserveSecurityParameterIndex( int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { + if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { + throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); + } return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); } From 04a11e02a90733be8ceb24f8c39624a3df7775f6 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Apr 2017 17:46:00 -0700 Subject: [PATCH 0364/1150] Add FileDescriptor Versions of applyTransportModeTransform() Because there is no way using the Java sockets API to actually get a socket of AF_INET on mode machines, it is necessary to provide a way to apply transforms to sockets made using the native wrapper API, which uses POSIX APIs and will create a socket that is AF_INET. Bug: 36073210 Test: b/34811227 Change-Id: I28ac7cc4f36045ce523a54111e5be975b0331356 --- core/java/android/net/IpSecManager.java | 31 +++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4bfeb096df..f8702e2e00 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -277,6 +277,23 @@ public final class IpSecManager { } } + /** + * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec + * encapsulation of the traffic flowing between the socket and the remote InetAddress of that + * transform. For security reasons, attempts to send traffic to any IP address other than the + * address associated with that transform will throw an IOException. In addition, if the + * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to + * send() or receive() until the transform is removed from the socket by calling {@link + * #removeTransportModeTransform(Socket, IpSecTransform)}; + * + * @param socket a socket file descriptor + * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + */ + public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + throws IOException { + applyTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + /** * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to @@ -318,6 +335,20 @@ public final class IpSecManager { removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); } + /** + * Remove a transform from a given stream socket. Once removed, traffic on the socket will not + * be encypted. This allows sockets that have been used for IPsec to be reclaimed for + * communication in the clear in the event socket reuse is desired. This operation will succeed + * regardless of the underlying state of a transform. If a transform is removed, communication + * on all sockets to which that transform was applied will fail until this method is called. + * + * @param socket a socket file descriptor that previously had a transform applied to it. + * @param transform the IPsec Transform that was previously applied to the given socket + */ + public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) { + removeTransportModeTransform(new ParcelFileDescriptor(socket), transform); + } + /* Call down to activate a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { From f56c5ebe819146795db993042ec86109bdeb6b11 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 5 Apr 2017 14:06:11 +0900 Subject: [PATCH 0365/1150] Nsdmanager/NsdService: add logging This patch adds basic logging to NsdManager and NsdService, and improves the facilities for pretty printing the event ids defined in NsdManager. It also includes a few minor cleanups: - adding 'final' on effectively final instance variables of NsdManager and NsdService. - similarly, adding 'static' on effectively static class fields. - regrouping instance variables together. Test: no functional changes Bug: 33074219 (cherry picked from commit 2183ba9b5f8eb54c74cd198a7506b21319794e99) Merged-In: I360d539e73cc8e4b45d4e0d20b2e345455fdb10c Change-Id: Id917f3a2085d17f277850af36a2cf859e3614a0f --- core/java/android/net/nsd/NsdManager.java | 49 ++++++-- .../java/com/android/server/NsdService.java | 107 +++++++++--------- 2 files changed, 94 insertions(+), 62 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 33d12a3a3f..1dde3cad23 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -45,7 +45,7 @@ import com.android.internal.util.Protocol; * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * *

            The API is asynchronous and responses to requests from an application are on listener - * callbacks on a seperate thread. + * callbacks on a seperate internal thread. * *

            There are three main operations the API supports - registration, discovery and resolution. *

            @@ -119,8 +119,8 @@ import com.android.internal.util.Protocol;
              * {@see NsdServiceInfo}
              */
             public final class NsdManager {
            -    private static final String TAG = "NsdManager";
            -    INsdManager mService;
            +    private static final String TAG = NsdManager.class.getSimpleName();
            +    private static final boolean DBG = false;
             
                 /**
                  * Broadcast intent action to indicate whether network service discovery is
            @@ -130,8 +130,7 @@ public final class NsdManager {
                  * @see #EXTRA_NSD_STATE
                  */
                 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
            -    public static final String ACTION_NSD_STATE_CHANGED =
            -        "android.net.nsd.STATE_CHANGED";
            +    public static final String ACTION_NSD_STATE_CHANGED = "android.net.nsd.STATE_CHANGED";
             
                 /**
                  * The lookup key for an int that indicates whether network service discovery is enabled
            @@ -208,13 +207,47 @@ public final class NsdManager {
                 /** Dns based service discovery protocol */
                 public static final int PROTOCOL_DNS_SD = 0x0001;
             
            -    private Context mContext;
            +    private static final SparseArray EVENT_NAMES = new SparseArray<>();
            +    static {
            +        EVENT_NAMES.put(DISCOVER_SERVICES, "DISCOVER_SERVICES");
            +        EVENT_NAMES.put(DISCOVER_SERVICES_STARTED, "DISCOVER_SERVICES_STARTED");
            +        EVENT_NAMES.put(DISCOVER_SERVICES_FAILED, "DISCOVER_SERVICES_FAILED");
            +        EVENT_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
            +        EVENT_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
            +        EVENT_NAMES.put(STOP_DISCOVERY, "STOP_DISCOVERY");
            +        EVENT_NAMES.put(STOP_DISCOVERY_FAILED, "STOP_DISCOVERY_FAILED");
            +        EVENT_NAMES.put(STOP_DISCOVERY_SUCCEEDED, "STOP_DISCOVERY_SUCCEEDED");
            +        EVENT_NAMES.put(REGISTER_SERVICE, "REGISTER_SERVICE");
            +        EVENT_NAMES.put(REGISTER_SERVICE_FAILED, "REGISTER_SERVICE_FAILED");
            +        EVENT_NAMES.put(REGISTER_SERVICE_SUCCEEDED, "REGISTER_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE, "UNREGISTER_SERVICE");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE_FAILED, "UNREGISTER_SERVICE_FAILED");
            +        EVENT_NAMES.put(UNREGISTER_SERVICE_SUCCEEDED, "UNREGISTER_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(RESOLVE_SERVICE, "RESOLVE_SERVICE");
            +        EVENT_NAMES.put(RESOLVE_SERVICE_FAILED, "RESOLVE_SERVICE_FAILED");
            +        EVENT_NAMES.put(RESOLVE_SERVICE_SUCCEEDED, "RESOLVE_SERVICE_SUCCEEDED");
            +        EVENT_NAMES.put(ENABLE, "ENABLE");
            +        EVENT_NAMES.put(DISABLE, "DISABLE");
            +        EVENT_NAMES.put(NATIVE_DAEMON_EVENT, "NATIVE_DAEMON_EVENT");
            +    }
            +
            +    /** @hide */
            +    public static String nameOf(int event) {
            +        String name = EVENT_NAMES.get(event);
            +        if (name == null) {
            +            return Integer.toString(event);
            +        }
            +        return name;
            +    }
            +
            +    private final INsdManager mService;
            +    private final Context mContext;
             
                 private static final int INVALID_LISTENER_KEY = 0;
                 private static final int BUSY_LISTENER_KEY = -1;
                 private int mListenerKey = 1;
                 private final SparseArray mListenerMap = new SparseArray();
            -    private final SparseArray mServiceMap = new SparseArray();
            +    private final SparseArray mServiceMap = new SparseArray<>();
                 private final Object mMapLock = new Object();
             
                 private final AsyncChannel mAsyncChannel = new AsyncChannel();
            @@ -300,6 +333,7 @@ public final class NsdManager {
             
                     @Override
                     public void handleMessage(Message message) {
            +            if (DBG) Log.d(TAG, "received " + nameOf(message.what));
                         switch (message.what) {
                             case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                                 mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
            @@ -377,7 +411,6 @@ public final class NsdManager {
             
                 // if the listener is already in the map, reject it.  Otherwise, add it and
                 // return its key.
            -
                 private int putListener(Object listener, NsdServiceInfo s) {
                     if (listener == null) return INVALID_LISTENER_KEY;
                     int key;
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index 8ae95d5ada..43b9f8b2ce 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -57,46 +57,27 @@ public class NsdService extends INsdManager.Stub {
                 private static final String TAG = "NsdService";
                 private static final String MDNS_TAG = "mDnsConnector";
             
            -    private static final boolean DBG = false;
            +    private static final boolean DBG = true;
             
            -    private Context mContext;
            -    private ContentResolver mContentResolver;
            -    private NsdStateMachine mNsdStateMachine;
            +    private final Context mContext;
            +    private final ContentResolver mContentResolver;
            +    private final NsdStateMachine mNsdStateMachine;
            +    private final NativeDaemonConnector mNativeConnector;
            +    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
             
                 /**
                  * Clients receiving asynchronous messages
                  */
            -    private HashMap mClients = new HashMap();
            +    private final HashMap mClients = new HashMap<>();
             
                 /* A map from unique id to client info */
            -    private SparseArray mIdToClientInfoMap= new SparseArray();
            +    private final SparseArray mIdToClientInfoMap= new SparseArray<>();
             
            -    private AsyncChannel mReplyChannel = new AsyncChannel();
            +    private final AsyncChannel mReplyChannel = new AsyncChannel();
             
            -    private int INVALID_ID = 0;
            +    private static final int INVALID_ID = 0;
                 private int mUniqueId = 1;
             
            -    private static final int BASE = Protocol.BASE_NSD_MANAGER;
            -    private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
            -    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
            -
            -    static {
            -        sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
            -        sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
            -        sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
            -        sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
            -        sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
            -    }
            -
            -    private static String cmdToString(int cmd) {
            -        cmd -= BASE;
            -        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
            -            return sCmdToString[cmd];
            -        } else {
            -            return null;
            -        }
            -    }
            -
                 private class NsdStateMachine extends StateMachine {
             
                     private final DefaultState mDefaultState = new DefaultState();
            @@ -105,7 +86,7 @@ public class NsdService extends INsdManager.Stub {
             
                     @Override
                     protected String getWhatToString(int what) {
            -            return cmdToString(what);
            +            return NsdManager.nameOf(what);
                     }
             
                     /**
            @@ -114,13 +95,13 @@ public class NsdService extends INsdManager.Stub {
                     private void registerForNsdSetting() {
                         ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
                             @Override
            -                    public void onChange(boolean selfChange) {
            -                        if (isNsdEnabled()) {
            -                            mNsdStateMachine.sendMessage(NsdManager.ENABLE);
            -                        } else {
            -                            mNsdStateMachine.sendMessage(NsdManager.DISABLE);
            -                        }
            +                public void onChange(boolean selfChange) {
            +                    if (isNsdEnabled()) {
            +                        mNsdStateMachine.sendMessage(NsdManager.ENABLE);
            +                    } else {
            +                        mNsdStateMachine.sendMessage(NsdManager.DISABLE);
                                 }
            +                }
                         };
             
                         mContext.getContentResolver().registerContentObserver(
            @@ -412,7 +393,8 @@ public class NsdService extends INsdManager.Stub {
                             int id = Integer.parseInt(cooked[1]);
                             ClientInfo clientInfo = mIdToClientInfoMap.get(id);
                             if (clientInfo == null) {
            -                    Slog.e(TAG, "Unique id with no client mapping: " + id);
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
                                 handled = false;
                                 return handled;
                             }
            @@ -423,42 +405,43 @@ public class NsdService extends INsdManager.Stub {
                                 // This can happen because of race conditions. For example,
                                 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
                                 // and we may get in this situation.
            -                    Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.d(TAG, String.format(
            +                            "Notification %s for listener id %d that is no longer active",
            +                            name, id));
                                 handled = false;
                                 return handled;
                             }
            -
            +                if (DBG) {
            +                    String name = NativeResponseCode.nameOf(code);
            +                    Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
            +                }
                             switch (code) {
                                 case NativeResponseCode.SERVICE_FOUND:
                                     /* NNN uniqueId serviceName regType domain */
            -                        if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                                     clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
                                             clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_LOST:
                                     /* NNN uniqueId serviceName regType domain */
            -                        if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
                                     clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
                                             clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
                                     /* NNN uniqueId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
                                             NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
                                 case NativeResponseCode.SERVICE_REGISTERED:
                                     /* NNN regId serviceName regType */
            -                        if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
                                     servInfo = new NsdServiceInfo(cooked[2], null);
                                     clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
                                             id, clientId, servInfo);
                                     break;
                                 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
                                     /* NNN regId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
                                            NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
            @@ -470,7 +453,6 @@ public class NsdService extends INsdManager.Stub {
                                     break;
                                 case NativeResponseCode.SERVICE_RESOLVED:
                                     /* NNN resolveId fullName hostName port txtlen txtdata */
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
                                     int index = 0;
                                     while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
                                         if (cooked[2].charAt(index) == '\\') {
            @@ -507,7 +489,6 @@ public class NsdService extends INsdManager.Stub {
                                     break;
                                 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
                                     /* NNN resolveId errorCode */
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
                                     stopResolveService(id);
                                     removeRequestMap(clientId, id, clientInfo);
                                     clientInfo.mResolvedService = null;
            @@ -519,13 +500,11 @@ public class NsdService extends INsdManager.Stub {
                                     stopGetAddrInfo(id);
                                     removeRequestMap(clientId, id, clientInfo);
                                     clientInfo.mResolvedService = null;
            -                        if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
                                     clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
                                             NsdManager.FAILURE_INTERNAL_ERROR, clientId);
                                     break;
                                 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
                                     /* NNN resolveId hostname ttl addr */
            -                        if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
                                     try {
                                         clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
                                         clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
            @@ -571,9 +550,6 @@ public class NsdService extends INsdManager.Stub {
                     return sb.toString();
                 }
             
            -    private NativeDaemonConnector mNativeConnector;
            -    private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
            -
                 private NsdService(Context context) {
                     mContext = context;
                     mContentResolver = context.getContentResolver();
            @@ -634,7 +610,7 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 /* These should be in sync with system/netd/server/ResponseCode.h */
            -    class NativeResponseCode {
            +    static final class NativeResponseCode {
                     public static final int SERVICE_DISCOVERY_FAILED    =   602;
                     public static final int SERVICE_FOUND               =   603;
                     public static final int SERVICE_LOST                =   604;
            @@ -650,6 +626,29 @@ public class NsdService extends INsdManager.Stub {
             
                     public static final int SERVICE_GET_ADDR_FAILED     =   611;
                     public static final int SERVICE_GET_ADDR_SUCCESS    =   612;
            +
            +        private static final SparseArray CODE_NAMES = new SparseArray<>();
            +        static {
            +            CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
            +            CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
            +            CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
            +            CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
            +            CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
            +            CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
            +            CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
            +            CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
            +            CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
            +            CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
            +            CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
            +        }
            +
            +        static String nameOf(int code) {
            +            String name = CODE_NAMES.get(code);
            +            if (name == null) {
            +                return Integer.toString(code);
            +            }
            +            return name;
            +        }
                 }
             
                 private class NativeEvent {
            @@ -863,10 +862,10 @@ public class NsdService extends INsdManager.Stub {
                     private NsdServiceInfo mResolvedService;
             
                     /* A map from client id to unique id sent to mDns */
            -        private SparseArray mClientIds = new SparseArray();
            +        private final SparseArray mClientIds = new SparseArray<>();
             
                     /* A map from client id to the type of the request we had received */
            -        private SparseArray mClientRequests = new SparseArray();
            +        private final SparseArray mClientRequests = new SparseArray<>();
             
                     private ClientInfo(AsyncChannel c, Messenger m) {
                         mChannel = c;
            
            From a64b019f94c2ac528903358e5c2bac402a927d00 Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Mon, 17 Apr 2017 17:11:58 -0700
            Subject: [PATCH 0366/1150] Consistenly Throw IOExceptions from IpSecManager
            
            Bug: 36073210
            Test: api-update
            Change-Id: Ia3825e85b09b6330f1326a26cf9e1cadf9dacf71
            ---
             core/java/android/net/IpSecManager.java | 11 +++++++----
             1 file changed, 7 insertions(+), 4 deletions(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index f8702e2e00..1a55b37665 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -317,7 +317,8 @@ public final class IpSecManager {
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
                 }
             
            @@ -331,7 +332,8 @@ public final class IpSecManager {
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
                 }
             
            @@ -345,7 +347,8 @@ public final class IpSecManager {
                  * @param socket a socket file descriptor that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);
                 }
             
            @@ -419,7 +422,7 @@ public final class IpSecManager {
                      *
                      * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
                      */
            -        public void close() {
            +        public void close() throws IOException {
                         // TODO: Go close the socket
                         mCloseGuard.close();
                     }
            
            From 4b909c85f6a4e062fff5b0b595c9dcbe72c4c45c Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Mon, 17 Apr 2017 19:34:33 -0700
            Subject: [PATCH 0367/1150] Hide Socket+DatagramSocket IpSecTransform methods
            
            These methods do not currently work for IPv4 sockets,
            so they need to be hidden until the underlying kernel
            code can be made to work properly in a dual-stack
            environment.
            
            Bug: 36073210
            Test: compilation
            Change-Id: Idce367f638a42da374a7f1dc5ebb8931c9555e06
            ---
             core/java/android/net/IpSecManager.java | 6 +++++-
             1 file changed, 5 insertions(+), 1 deletion(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 1a55b37665..375b7eeb01 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -245,6 +245,7 @@ public final class IpSecManager {
                  *
                  * @param socket a stream socket
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            +     * @hide
                  */
                 public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
                         throws IOException {
            @@ -262,6 +263,7 @@ public final class IpSecManager {
                  *
                  * @param socket a datagram socket
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            +     * @hide
                  */
                 public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
                         throws IOException {
            @@ -284,7 +286,7 @@ public final class IpSecManager {
                  * address associated with that transform will throw an IOException. In addition, if the
                  * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
                  * send() or receive() until the transform is removed from the socket by calling {@link
            -     * #removeTransportModeTransform(Socket, IpSecTransform)};
            +     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
                  *
                  * @param socket a socket file descriptor
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            @@ -316,6 +318,7 @@ public final class IpSecManager {
                  *
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
            +     * @hide
                  */
                 public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
                         throws IOException {
            @@ -331,6 +334,7 @@ public final class IpSecManager {
                  *
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
            +     * @hide
                  */
                 public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
                         throws IOException {
            
            From 1bcfebf971796a0914b3972df737ae015dd06fc8 Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Mon, 17 Apr 2017 17:11:58 -0700
            Subject: [PATCH 0368/1150] Consistenly Throw IOExceptions from IpSecManager
            
            Bug: 36073210
            Test: api-update
            Change-Id: Ia3825e85b09b6330f1326a26cf9e1cadf9dacf71
            Merged-In: Ia3825e85b09b6330f1326a26cf9e1cadf9dacf71
            (cherry picked from commit c2fd6cfdc9dce33d57a3c2780e0527dd4b1bfeb9)
            ---
             core/java/android/net/IpSecManager.java | 11 +++++++----
             1 file changed, 7 insertions(+), 4 deletions(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index f8702e2e00..1a55b37665 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -317,7 +317,8 @@ public final class IpSecManager {
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
                 }
             
            @@ -331,7 +332,8 @@ public final class IpSecManager {
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
                 }
             
            @@ -345,7 +347,8 @@ public final class IpSecManager {
                  * @param socket a socket file descriptor that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
                  */
            -    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) {
            +    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
            +            throws IOException {
                     removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);
                 }
             
            @@ -419,7 +422,7 @@ public final class IpSecManager {
                      *
                      * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
                      */
            -        public void close() {
            +        public void close() throws IOException {
                         // TODO: Go close the socket
                         mCloseGuard.close();
                     }
            
            From 238b78c2aa8fece83ec7f8f4897a9de55604ed9e Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Mon, 17 Apr 2017 19:34:33 -0700
            Subject: [PATCH 0369/1150] Hide Socket+DatagramSocket IpSecTransform methods
            
            These methods do not currently work for IPv4 sockets,
            so they need to be hidden until the underlying kernel
            code can be made to work properly in a dual-stack
            environment.
            
            Bug: 36073210
            Test: compilation
            Merged-In: Idce367f638a42da374a7f1dc5ebb8931c9555e06
            Change-Id: Idce367f638a42da374a7f1dc5ebb8931c9555e06
            (cherry picked from commit da18b028f85e9a2c969c636aea6abf7f4bac3922)
            ---
             core/java/android/net/IpSecManager.java | 6 +++++-
             1 file changed, 5 insertions(+), 1 deletion(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 1a55b37665..375b7eeb01 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -245,6 +245,7 @@ public final class IpSecManager {
                  *
                  * @param socket a stream socket
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            +     * @hide
                  */
                 public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
                         throws IOException {
            @@ -262,6 +263,7 @@ public final class IpSecManager {
                  *
                  * @param socket a datagram socket
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            +     * @hide
                  */
                 public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
                         throws IOException {
            @@ -284,7 +286,7 @@ public final class IpSecManager {
                  * address associated with that transform will throw an IOException. In addition, if the
                  * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
                  * send() or receive() until the transform is removed from the socket by calling {@link
            -     * #removeTransportModeTransform(Socket, IpSecTransform)};
            +     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
                  *
                  * @param socket a socket file descriptor
                  * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
            @@ -316,6 +318,7 @@ public final class IpSecManager {
                  *
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
            +     * @hide
                  */
                 public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
                         throws IOException {
            @@ -331,6 +334,7 @@ public final class IpSecManager {
                  *
                  * @param socket a socket that previously had a transform applied to it.
                  * @param transform the IPsec Transform that was previously applied to the given socket
            +     * @hide
                  */
                 public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
                         throws IOException {
            
            From 7d4b344b193030e3b5a4bafef9c3289bd5335a84 Mon Sep 17 00:00:00 2001
            From: Hugo Benichi 
            Date: Wed, 5 Apr 2017 14:43:29 +0900
            Subject: [PATCH 0370/1150] NsdService: minor cleanups
            
            Minor cleanups in switches of processMessage and handleNativeEvent.
            
            Test: no functional changes
            Bug: 33074219
            
            (cherry picked from commit 23dba85fff01a9f51beea8ce811fc98b582f8e71)
            
            Merged-In: I9ad4ce812c0d2c02a671a7a871ad427e4ce29b4a
            Change-Id: Ic029cc9fa007d8c485f64f4afcbd4dc10da1ae29
            ---
             .../java/com/android/server/NsdService.java   | 28 +++++++------------
             1 file changed, 10 insertions(+), 18 deletions(-)
            
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index 43b9f8b2ce..bb530fb8c1 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -253,20 +253,17 @@ public class NsdService extends INsdManager.Stub {
                         public boolean processMessage(Message msg) {
                             ClientInfo clientInfo;
                             NsdServiceInfo servInfo;
            -                boolean result = HANDLED;
                             int id;
                             switch (msg.what) {
            -                  case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
            +                    case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                                     //First client
                                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
                                             mClients.size() == 0) {
                                         startMDnsDaemon();
                                     }
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                                 case NsdManager.DISABLE:
                                     //TODO: cleanup clients
                                     transitionTo(mDisabledState);
            @@ -377,26 +374,23 @@ public class NsdService extends INsdManager.Stub {
                                 case NsdManager.NATIVE_DAEMON_EVENT:
                                     NativeEvent event = (NativeEvent) msg.obj;
                                     if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
            -                            result = NOT_HANDLED;
            +                            return NOT_HANDLED;
                                     }
                                     break;
                                 default:
            -                        result = NOT_HANDLED;
            -                        break;
            +                        return NOT_HANDLED;
                             }
            -                return result;
            +                return HANDLED;
                         }
             
                         private boolean handleNativeEvent(int code, String raw, String[] cooked) {
            -                boolean handled = true;
                             NsdServiceInfo servInfo;
                             int id = Integer.parseInt(cooked[1]);
                             ClientInfo clientInfo = mIdToClientInfoMap.get(id);
                             if (clientInfo == null) {
                                 String name = NativeResponseCode.nameOf(code);
                                 Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
            -                    handled = false;
            -                    return handled;
            +                    return false;
                             }
             
                             /* This goes in response as msg.arg2 */
            @@ -409,8 +403,7 @@ public class NsdService extends INsdManager.Stub {
                                 Slog.d(TAG, String.format(
                                         "Notification %s for listener id %d that is no longer active",
                                         name, id));
            -                    handled = false;
            -                    return handled;
            +                    return false;
                             }
                             if (DBG) {
                                 String name = NativeResponseCode.nameOf(code);
            @@ -518,10 +511,9 @@ public class NsdService extends INsdManager.Stub {
                                     clientInfo.mResolvedService = null;
                                     break;
                                 default:
            -                        handled = false;
            -                        break;
            +                        return false;
                             }
            -                return handled;
            +                return true;
                         }
                    }
                 }
            
            From 0b1540e40df85ea3c2c3c45ed8cdcb763c6a263d Mon Sep 17 00:00:00 2001
            From: Hugo Benichi 
            Date: Mon, 17 Apr 2017 15:27:52 +0900
            Subject: [PATCH 0371/1150] NsdManager: add unit tests
            
            This prepares some refactoring and the addition of a timeout to
            resolveService.
            
            Test: new tests pass
            Bug: 37013369, 33298084
            Change-Id: Ie8277bd5983278507bfa70495b4ce7d13895b24b
            ---
             core/java/android/net/nsd/NsdManager.java | 4 +++-
             1 file changed, 3 insertions(+), 1 deletion(-)
            
            diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
            index 1dde3cad23..83c469103f 100644
            --- a/core/java/android/net/nsd/NsdManager.java
            +++ b/core/java/android/net/nsd/NsdManager.java
            @@ -31,6 +31,7 @@ import android.util.SparseArray;
             
             import java.util.concurrent.CountDownLatch;
             
            +import com.android.internal.annotations.VisibleForTesting;
             import com.android.internal.util.AsyncChannel;
             import com.android.internal.util.Protocol;
             
            @@ -326,7 +327,8 @@ public final class NsdManager {
                     public void onServiceResolved(NsdServiceInfo serviceInfo);
                 }
             
            -    private class ServiceHandler extends Handler {
            +    @VisibleForTesting
            +    class ServiceHandler extends Handler {
                     ServiceHandler(Looper looper) {
                         super(looper);
                     }
            
            From 803a2f073f571e46087958f1e77b29211b929010 Mon Sep 17 00:00:00 2001
            From: Hugo Benichi 
            Date: Mon, 24 Apr 2017 11:35:06 +0900
            Subject: [PATCH 0372/1150] NsdService: bootstrap unit tests
            
            Test: new tests part of $ runtest frameworks-net
            Bug: 37013369, 33298084
            Change-Id: Ief45f838268380b4b2a128390fbf34d55a3b922b
            ---
             .../java/com/android/server/NsdService.java   | 60 ++++++++++++++-----
             1 file changed, 45 insertions(+), 15 deletions(-)
            
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index a691af9c01..e37aa6362e 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -26,6 +26,8 @@ import android.net.nsd.DnsSdTxtRecord;
             import android.net.nsd.INsdManager;
             import android.net.nsd.NsdManager;
             import android.os.Binder;
            +import android.os.HandlerThread;
            +import android.os.Handler;
             import android.os.Message;
             import android.os.Messenger;
             import android.os.UserHandle;
            @@ -40,6 +42,7 @@ import java.net.InetAddress;
             import java.util.HashMap;
             import java.util.concurrent.CountDownLatch;
             
            +import com.android.internal.annotations.VisibleForTesting;
             import com.android.internal.util.AsyncChannel;
             import com.android.internal.util.Protocol;
             import com.android.internal.util.State;
            @@ -59,7 +62,7 @@ public class NsdService extends INsdManager.Stub {
                 private static final boolean DBG = true;
             
                 private final Context mContext;
            -    private final ContentResolver mContentResolver;
            +    private final NsdSettings mNsdSettings;
                 private final NsdStateMachine mNsdStateMachine;
                 private final NativeDaemonConnector mNativeConnector;
                 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
            @@ -108,8 +111,8 @@ public class NsdService extends INsdManager.Stub {
                                 false, contentObserver);
                     }
             
            -        NsdStateMachine(String name) {
            -            super(name);
            +        NsdStateMachine(String name, Handler handler) {
            +            super(name, handler);
                         addState(mDefaultState);
                             addState(mDisabledState, mDefaultState);
                             addState(mEnabledState, mDefaultState);
            @@ -541,14 +544,15 @@ public class NsdService extends INsdManager.Stub {
                     return sb.toString();
                 }
             
            -    private NsdService(Context context) {
            -        mContext = context;
            -        mContentResolver = context.getContentResolver();
            +    @VisibleForTesting
            +    NsdService(Context ctx, NsdSettings settings, Handler handler) {
            +        mContext = ctx;
            +        mNsdSettings = settings;
             
            -        mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
            -                MDNS_TAG, 25, null);
            +        NativeCallbackReceiver callback = new NativeCallbackReceiver();
            +        mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
             
            -        mNsdStateMachine = new NsdStateMachine(TAG);
            +        mNsdStateMachine = new NsdStateMachine(TAG, handler);
                     mNsdStateMachine.start();
             
                     Thread th = new Thread(mNativeConnector, MDNS_TAG);
            @@ -556,21 +560,24 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 public static NsdService create(Context context) throws InterruptedException {
            -        NsdService service = new NsdService(context);
            +        NsdSettings settings = NsdSettings.makeDefault(context);
            +        HandlerThread thread = new HandlerThread(TAG);
            +        thread.start();
            +        Handler handler = new Handler(thread.getLooper());
            +        NsdService service = new NsdService(context, settings, handler);
                     service.mNativeDaemonConnected.await();
                     return service;
                 }
             
                 public Messenger getMessenger() {
            -        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
            -            "NsdService");
            +        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
                     return new Messenger(mNsdStateMachine.getHandler());
                 }
             
                 public void setEnabled(boolean enable) {
                     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
                             "NsdService");
            -        Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
            +        mNsdSettings.putEnabledStatus(enable);
                     if (enable) {
                         mNsdStateMachine.sendMessage(NsdManager.ENABLE);
                     } else {
            @@ -590,8 +597,10 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 private boolean isNsdEnabled() {
            -        boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
            -        if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
            +        boolean ret = mNsdSettings.isEnabled();
            +        if (DBG) {
            +            Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
            +        }
                     return ret;
                 }
             
            @@ -927,4 +936,25 @@ public class NsdService extends INsdManager.Stub {
                         return -1;
                     }
                 }
            +
            +    @VisibleForTesting
            +    public interface NsdSettings {
            +        boolean isEnabled();
            +        void putEnabledStatus(boolean isEnabled);
            +
            +        static NsdSettings makeDefault(Context context) {
            +            ContentResolver resolver = context.getContentResolver();
            +            return new NsdSettings() {
            +                @Override
            +                public boolean isEnabled() {
            +                    return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
            +                }
            +
            +                @Override
            +                public void putEnabledStatus(boolean isEnabled) {
            +                    Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
            +                }
            +            };
            +        }
            +    }
             }
            
            From faf8a9191762444f659164ce633bdfec1ab8de62 Mon Sep 17 00:00:00 2001
            From: Nathan Harold 
            Date: Tue, 25 Apr 2017 14:21:52 -0700
            Subject: [PATCH 0373/1150] Hide IpSecManager, IpSecTransform, and
             IpSecAlgorithm
            
            These classes, originally planned to be part of the
            public API, are not ready for public consumption.
            They are planned to be un-hidden in a future release.
            
            Bug: 37681043
            Test: make update-api and make
            Merged-In: I8caccd3f8455341cb56a2256354eacbadedff047
            Change-Id: I8caccd3f8455341cb56a2256354eacbadedff047
            (cherry picked from commit e38565fc74ee19e27175782be3cf2f0dffefd3a6)
            ---
             core/java/android/net/IpSecAlgorithm.java | 2 ++
             core/java/android/net/IpSecManager.java   | 2 ++
             core/java/android/net/IpSecTransform.java | 2 ++
             3 files changed, 6 insertions(+)
            
            diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
            index ce7894fb3b..48b095d9b7 100644
            --- a/core/java/android/net/IpSecAlgorithm.java
            +++ b/core/java/android/net/IpSecAlgorithm.java
            @@ -24,6 +24,8 @@ import java.lang.annotation.RetentionPolicy;
             /**
              * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
              * RFC 4301.
            + *
            + * @hide
              */
             public final class IpSecAlgorithm implements Parcelable {
             
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 375b7eeb01..114e46e54f 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -37,6 +37,8 @@ import java.net.Socket;
              * 

            An IpSecManager may be obtained by calling {@link * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} + * + * @hide */ public final class IpSecManager { private static final String TAG = "IpSecManager"; diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 801e98c7b1..639d1f2689 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -45,6 +45,8 @@ import java.net.InetAddress; * *

            An IpSecTransform may either represent a tunnel mode transform that operates on a wide array * of traffic or may represent a transport mode transform operating on a Socket or Sockets. + * + * @hide */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; From 185f2ccd1c3d50b956677e6fc1c87f9d162a7727 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 25 Apr 2017 14:21:52 -0700 Subject: [PATCH 0374/1150] Hide IpSecManager, IpSecTransform, and IpSecAlgorithm These classes, originally planned to be part of the public API, are not ready for public consumption. They are planned to be un-hidden in a future release. Bug: 37681043 Test: make update-api and make Change-Id: I8caccd3f8455341cb56a2256354eacbadedff047 --- core/java/android/net/IpSecAlgorithm.java | 2 ++ core/java/android/net/IpSecManager.java | 2 ++ core/java/android/net/IpSecTransform.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index ce7894fb3b..48b095d9b7 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -24,6 +24,8 @@ import java.lang.annotation.RetentionPolicy; /** * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to * RFC 4301. + * + * @hide */ public final class IpSecAlgorithm implements Parcelable { diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 375b7eeb01..114e46e54f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -37,6 +37,8 @@ import java.net.Socket; *

            An IpSecManager may be obtained by calling {@link * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} + * + * @hide */ public final class IpSecManager { private static final String TAG = "IpSecManager"; diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 801e98c7b1..639d1f2689 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -45,6 +45,8 @@ import java.net.InetAddress; * *

            An IpSecTransform may either represent a tunnel mode transform that operates on a wide array * of traffic or may represent a transport mode transform operating on a Socket or Sockets. + * + * @hide */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; From 6d7064499876180e4929cfa1885ae48d3863c806 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 24 Apr 2017 16:19:58 +0900 Subject: [PATCH 0375/1150] NsdService: disentangle NativeDaemonConnector from ctor This patch disentangles the creation of NativeDaemonConnector from the creation of NsdService by introducing a wrapper type DaemonConnection. This allows to mock this dependency in unit tests. Test: enhanced previously introduced new tests. Bug: 37013369, 33298084 Change-Id: I894b7cddfc509f86d0134d214c88c063b81b5e0a --- .../java/com/android/server/NsdService.java | 187 ++++++++---------- 1 file changed, 81 insertions(+), 106 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index e37aa6362e..55bca648d5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -39,6 +39,7 @@ import android.util.SparseArray; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; +import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -64,8 +65,8 @@ public class NsdService extends INsdManager.Stub { private final Context mContext; private final NsdSettings mNsdSettings; private final NsdStateMachine mNsdStateMachine; - private final NativeDaemonConnector mNativeConnector; - private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1); + private final DaemonConnection mDaemon; + private final NativeCallbackReceiver mDaemonCallback; /** * Clients receiving asynchronous messages @@ -545,18 +546,13 @@ public class NsdService extends INsdManager.Stub { } @VisibleForTesting - NsdService(Context ctx, NsdSettings settings, Handler handler) { + NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) { mContext = ctx; mNsdSettings = settings; - - NativeCallbackReceiver callback = new NativeCallbackReceiver(); - mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); - mNsdStateMachine = new NsdStateMachine(TAG, handler); mNsdStateMachine.start(); - - Thread th = new Thread(mNativeConnector, MDNS_TAG); - th.start(); + mDaemonCallback = new NativeCallbackReceiver(); + mDaemon = fn.get(mDaemonCallback); } public static NsdService create(Context context) throws InterruptedException { @@ -564,8 +560,8 @@ public class NsdService extends INsdManager.Stub { HandlerThread thread = new HandlerThread(TAG); thread.start(); Handler handler = new Handler(thread.getLooper()); - NsdService service = new NsdService(context, settings, handler); - service.mNativeDaemonConnected.await(); + NsdService service = new NsdService(context, settings, handler, DaemonConnection::new); + service.mDaemonCallback.awaitConnection(); return service; } @@ -664,14 +660,23 @@ public class NsdService extends INsdManager.Stub { } class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks { - public void onDaemonConnected() { - mNativeDaemonConnected.countDown(); + private final CountDownLatch connected = new CountDownLatch(1); + + public void awaitConnection() throws InterruptedException { + connected.await(); } + @Override + public void onDaemonConnected() { + connected.countDown(); + } + + @Override public boolean onCheckHoldWakeLock(int code) { return false; } + @Override public boolean onEvent(int code, String raw, String[] cooked) { // TODO: NDC translates a message to a callback, we could enhance NDC to // directly interact with a state machine through messages @@ -681,132 +686,102 @@ public class NsdService extends INsdManager.Stub { } } - private boolean startMDnsDaemon() { - if (DBG) Slog.d(TAG, "startMDnsDaemon"); - try { - mNativeConnector.execute("mdnssd", "start-service"); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to start daemon" + e); - return false; + interface DaemonConnectionSupplier { + DaemonConnection get(NativeCallbackReceiver callback); + } + + @VisibleForTesting + public static class DaemonConnection { + final NativeDaemonConnector mNativeConnector; + + DaemonConnection(NativeCallbackReceiver callback) { + mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); + new Thread(mNativeConnector, MDNS_TAG).start(); } - return true; + + public boolean execute(Object... args) { + if (DBG) { + Slog.d(TAG, "mdnssd " + Arrays.toString(args)); + } + try { + mNativeConnector.execute("mdnssd", args); + } catch (NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e); + return false; + } + return true; + } + + public boolean execute(Command cmd) { + if (DBG) { + Slog.d(TAG, cmd.toString()); + } + try { + mNativeConnector.execute(cmd); + } catch (NativeDaemonConnectorException e) { + Slog.e(TAG, "Failed to execute " + cmd, e); + return false; + } + return true; + } + } + + private boolean startMDnsDaemon() { + return mDaemon.execute("start-service"); } private boolean stopMDnsDaemon() { - if (DBG) Slog.d(TAG, "stopMDnsDaemon"); - try { - mNativeConnector.execute("mdnssd", "stop-service"); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to start daemon" + e); - return false; - } - return true; + return mDaemon.execute("stop-service"); } private boolean registerService(int regId, NsdServiceInfo service) { - if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service); - try { - Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(), - service.getServiceType(), service.getPort(), - Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT) - .replace("\n", "")); - - mNativeConnector.execute(cmd); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute registerService " + e); - return false; + if (DBG) { + Slog.d(TAG, "registerService: " + regId + " " + service); } - return true; + String name = service.getServiceName(); + String type = service.getServiceType(); + int port = service.getPort(); + byte[] textRecord = service.getTxtRecord(); + String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", ""); + Command cmd = new Command("mdnssd", "register", regId, name, type, port, record); + return mDaemon.execute(cmd); } private boolean unregisterService(int regId) { - if (DBG) Slog.d(TAG, "unregisterService: " + regId); - try { - mNativeConnector.execute("mdnssd", "stop-register", regId); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute unregisterService " + e); - return false; - } - return true; + return mDaemon.execute("stop-register", regId); } private boolean updateService(int regId, DnsSdTxtRecord t) { - if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t); - try { - if (t == null) return false; - mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData()); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to updateServices " + e); + if (t == null) { return false; } - return true; + return mDaemon.execute("update", regId, t.size(), t.getRawData()); } private boolean discoverServices(int discoveryId, String serviceType) { - if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType); - try { - mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to discoverServices " + e); - return false; - } - return true; + return mDaemon.execute("discover", discoveryId, serviceType); } private boolean stopServiceDiscovery(int discoveryId) { - if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId); - try { - mNativeConnector.execute("mdnssd", "stop-discover", discoveryId); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to stopServiceDiscovery " + e); - return false; - } - return true; + return mDaemon.execute("stop-discover", discoveryId); } private boolean resolveService(int resolveId, NsdServiceInfo service) { - if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service); - try { - mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(), - service.getServiceType(), "local."); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to resolveService " + e); - return false; - } - return true; + String name = service.getServiceName(); + String type = service.getServiceType(); + return mDaemon.execute("resolve", resolveId, name, type, "local."); } private boolean stopResolveService(int resolveId) { - if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId); - try { - mNativeConnector.execute("mdnssd", "stop-resolve", resolveId); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to stop resolve " + e); - return false; - } - return true; + return mDaemon.execute("stop-resolve", resolveId); } private boolean getAddrInfo(int resolveId, String hostname) { - if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId); - try { - mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to getAddrInfo " + e); - return false; - } - return true; + return mDaemon.execute("getaddrinfo", resolveId, hostname); } private boolean stopGetAddrInfo(int resolveId) { - if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId); - try { - mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId); - } catch(NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to stopGetAddrInfo " + e); - return false; - } - return true; + return mDaemon.execute("stop-getaddrinfo", resolveId); } @Override From 3ec710f6f03eb1edd05c0a48a992f79a6ac7f925 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 28 Apr 2017 11:01:22 +0900 Subject: [PATCH 0376/1150] NsdManager: unit test coverage for servive registration This patch adds test coverage for NsdManager#registerService() and NsdManager#unregisterService(). This test shows a potential defect in the api: if unregisterService() fails, the associated listener is always unregistered from NsdManager. If the service initially registered is still registered, this potentially make it impossible to unregister. Test: added new unit test Bug: 37013369, 33298084 Change-Id: Ia089b6d2f2a349907a8b29d9a3acd7f59e177887 --- core/java/android/net/nsd/NsdManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 83c469103f..4c33c36dc1 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -393,6 +393,8 @@ public final class NsdManager { ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: + // TODO: do not unregister listener until service is unregistered, or provide + // alternative way for unregistering ? removeListener(message.arg2); ((RegistrationListener) listener).onServiceUnregistered(ns); break; From 287730e764d00542e61562562de57a2e52e74d47 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 28 Apr 2017 13:29:21 +0900 Subject: [PATCH 0377/1150] NsdManager: add test coverage for discoverServices() Test: added new tests Bug: 37013369, 33298084 Change-Id: If6c1113ee1bd4690db90abd5a61c3e229c827aec --- core/java/android/net/nsd/NsdManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 4c33c36dc1..3fd9f19364 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -372,6 +372,8 @@ public final class NsdManager { ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); break; case STOP_DISCOVERY_FAILED: + // TODO: failure to stop discovery should be internal and retried internally, as + // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED removeListener(message.arg2); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); From f2c64f87259679c44ef151b08cccab43ca5d4342 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 2 May 2017 13:36:28 +0900 Subject: [PATCH 0378/1150] NsdManager: remove duplicated argument validation This patch simplifies argument validation in NsdManager public api and regroup duplicated validation into common methods. This makes stack traces more actionable as now specific errors will cause the api to throw exception from specific methods, whereas before IllegalArgumentException would be thrown from inside the same api method for different reasons. This patch also includes a couple of other small cleanups. Test: $ runtest -x frameworks/base/tests/net/../NsdManagerTest.java Bug: 37013369 Change-Id: Iaad13e13976e9bf8f508d7188f823f8184ac414b --- core/java/android/net/nsd/NsdManager.java | 176 +++++++++------------- 1 file changed, 73 insertions(+), 103 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 3fd9f19364..13648d2c76 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,10 @@ package android.net.nsd; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkStringNotEmpty; + import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; @@ -241,12 +245,12 @@ public final class NsdManager { return name; } + private static int FIRST_LISTENER_KEY = 1; + private final INsdManager mService; private final Context mContext; - private static final int INVALID_LISTENER_KEY = 0; - private static final int BUSY_LISTENER_KEY = -1; - private int mListenerKey = 1; + private int mListenerKey = FIRST_LISTENER_KEY; private final SparseArray mListenerMap = new SparseArray(); private final SparseArray mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); @@ -304,7 +308,6 @@ public final class NsdManager { public void onServiceFound(NsdServiceInfo serviceInfo); public void onServiceLost(NsdServiceInfo serviceInfo); - } /** Interface for callback invocation for service registration */ @@ -335,8 +338,9 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - if (DBG) Log.d(TAG, "received " + nameOf(message.what)); - switch (message.what) { + final int what = message.what; + final int key = message.arg2; + switch (what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); return; @@ -349,19 +353,26 @@ public final class NsdManager { default: break; } - Object listener = getListener(message.arg2); + final Object listener; + final NsdServiceInfo ns; + synchronized (mMapLock) { + listener = mListenerMap.get(key); + ns = mServiceMap.get(key); + } if (listener == null) { Log.d(TAG, "Stale key " + message.arg2); return; } - NsdServiceInfo ns = getNsdService(message.arg2); - switch (message.what) { + if (DBG) { + Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); + } + switch (what) { case DISCOVER_SERVICES_STARTED: String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); break; case DISCOVER_SERVICES_FAILED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; @@ -374,16 +385,16 @@ public final class NsdManager { case STOP_DISCOVERY_FAILED: // TODO: failure to stop discovery should be internal and retried internally, as // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: @@ -391,7 +402,7 @@ public final class NsdManager { (NsdServiceInfo) message.obj); break; case UNREGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: @@ -401,11 +412,11 @@ public final class NsdManager { ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); break; default: @@ -415,40 +426,27 @@ public final class NsdManager { } } - // if the listener is already in the map, reject it. Otherwise, add it and - // return its key. + private int nextListenerKey() { + // Ensure mListenerKey >= FIRST_LISTENER_KEY; + mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); + return mListenerKey; + } + + // Assert that the listener is not in the map, then add it and returns its key private int putListener(Object listener, NsdServiceInfo s) { - if (listener == null) return INVALID_LISTENER_KEY; - int key; + checkListener(listener); + final int key; synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return BUSY_LISTENER_KEY; - } - do { - key = mListenerKey++; - } while (key == INVALID_LISTENER_KEY); + checkArgument(valueIndex == -1, "listener already in use"); + key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); } return key; } - private Object getListener(int key) { - if (key == INVALID_LISTENER_KEY) return null; - synchronized (mMapLock) { - return mListenerMap.get(key); - } - } - - private NsdServiceInfo getNsdService(int key) { - synchronized (mMapLock) { - return mServiceMap.get(key); - } - } - private void removeListener(int key) { - if (key == INVALID_LISTENER_KEY) return; synchronized (mMapLock) { mListenerMap.remove(key); mServiceMap.remove(key); @@ -456,16 +454,15 @@ public final class NsdManager { } private int getListenerKey(Object listener) { + checkListener(listener); synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return mListenerMap.keyAt(valueIndex); - } + checkArgument(valueIndex != -1, "listener not registered"); + return mListenerMap.keyAt(valueIndex); } - return INVALID_LISTENER_KEY; } - private String getNsdServiceInfoType(NsdServiceInfo s) { + private static String getNsdServiceInfoType(NsdServiceInfo s) { if (s == null) return "?"; return s.getServiceType(); } @@ -475,7 +472,9 @@ public final class NsdManager { */ private void init() { final Messenger messenger = getMessenger(); - if (messenger == null) throw new RuntimeException("Failed to initialize"); + if (messenger == null) { + fatal("Failed to obtain service Messenger"); + } HandlerThread t = new HandlerThread("NsdManager"); t.start(); mHandler = new ServiceHandler(t.getLooper()); @@ -483,10 +482,15 @@ public final class NsdManager { try { mConnected.await(); } catch (InterruptedException e) { - Log.e(TAG, "interrupted wait at init"); + fatal("Interrupted wait at init"); } } + private static void fatal(String msg) { + Log.e(TAG, msg); + throw new RuntimeException(msg); + } + /** * Register a service to be discovered by other services. * @@ -506,23 +510,10 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkArgument(serviceInfo.getPort() > 0, "Invalid port number"); + checkServiceInfo(serviceInfo); + checkProtocol(protocolType); int key = putListener(listener, serviceInfo); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); } @@ -541,12 +532,6 @@ public final class NsdManager { */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("listener not registered"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); } @@ -579,25 +564,13 @@ public final class NsdManager { * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkStringNotEmpty(serviceType, "Service type cannot be empty"); + checkProtocol(protocolType); NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); int key = putListener(listener, s); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); } @@ -619,12 +592,6 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("service discovery not active on listener"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); } @@ -638,19 +605,8 @@ public final class NsdManager { * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - + checkServiceInfo(serviceInfo); int key = putListener(listener, serviceInfo); - - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); } @@ -664,10 +620,10 @@ public final class NsdManager { } /** - * Get a reference to NetworkService handler. This is used to establish + * Get a reference to NsdService handler. This is used to establish * an AsyncChannel communication with the service * - * @return Messenger pointing to the NetworkService handler + * @return Messenger pointing to the NsdService handler */ private Messenger getMessenger() { try { @@ -676,4 +632,18 @@ public final class NsdManager { throw e.rethrowFromSystemServer(); } } + + private static void checkListener(Object listener) { + checkNotNull(listener, "listener cannot be null"); + } + + private static void checkProtocol(int protocolType) { + checkArgument(protocolType == PROTOCOL_DNS_SD, "Unsupported protocol"); + } + + private static void checkServiceInfo(NsdServiceInfo serviceInfo) { + checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); + checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty"); + checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); + } } From 4dd4db77209ab2ef302a3a2a4892b05aadd26ec6 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 28 Apr 2017 15:31:10 +0900 Subject: [PATCH 0379/1150] NsdService: test coverage for client requests. Adding coverage for: - NsdManager client disconnection - in-flight request GC Test: new test passes Bug: 37013369, 33298084 Change-Id: I92039f297cf99352bbf4196797933d89c0b819ff --- core/java/android/net/nsd/NsdManager.java | 8 +++++ .../java/com/android/server/NsdService.java | 35 ++++++------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 13648d2c76..27ca6e2e51 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -273,6 +273,14 @@ public final class NsdManager { init(); } + /** + * @hide + */ + @VisibleForTesting + public void disconnect() { + mAsyncChannel.disconnect(); + } + /** * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, * {@link RegistrationListener#onUnregistrationFailed}, diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 55bca648d5..efbad450af 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -48,7 +48,6 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.NativeDaemonConnector.Command; /** * Network Service Discovery Service handles remote service discovery operation requests by @@ -161,7 +160,7 @@ public class NsdService extends INsdManager.Stub { } //Last client if (mClients.size() == 0) { - stopMDnsDaemon(); + mDaemon.stop(); } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: @@ -221,14 +220,14 @@ public class NsdService extends INsdManager.Stub { public void enter() { sendNsdStateChangeBroadcast(true); if (mClients.size() > 0) { - startMDnsDaemon(); + mDaemon.start(); } } @Override public void exit() { if (mClients.size() > 0) { - stopMDnsDaemon(); + mDaemon.stop(); } } @@ -262,7 +261,7 @@ public class NsdService extends INsdManager.Stub { //First client if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && mClients.size() == 0) { - startMDnsDaemon(); + mDaemon.start(); } return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: @@ -712,26 +711,13 @@ public class NsdService extends INsdManager.Stub { return true; } - public boolean execute(Command cmd) { - if (DBG) { - Slog.d(TAG, cmd.toString()); - } - try { - mNativeConnector.execute(cmd); - } catch (NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute " + cmd, e); - return false; - } - return true; + public void start() { + execute("start-service"); } - } - private boolean startMDnsDaemon() { - return mDaemon.execute("start-service"); - } - - private boolean stopMDnsDaemon() { - return mDaemon.execute("stop-service"); + public void stop() { + execute("stop-service"); + } } private boolean registerService(int regId, NsdServiceInfo service) { @@ -743,8 +729,7 @@ public class NsdService extends INsdManager.Stub { int port = service.getPort(); byte[] textRecord = service.getTxtRecord(); String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", ""); - Command cmd = new Command("mdnssd", "register", regId, name, type, port, record); - return mDaemon.execute(cmd); + return mDaemon.execute("register", regId, name, type, port, record); } private boolean unregisterService(int regId) { From d2552aee119299bf66d694960c72a00141642ef5 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 11 Apr 2017 14:42:47 +0900 Subject: [PATCH 0380/1150] NsdService: simple cleanups This patch replace some SparseArray with SparseIntArray, and simplify a value lookup function by using indexOfValue(). Test: TODO Bug: 37013369, 33298084 Change-Id: I4872f8baa2bb2ff456c7f848d3afe2e7bcc9892e --- .../java/com/android/server/NsdService.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index efbad450af..965835c4b2 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -35,6 +35,7 @@ import android.provider.Settings; import android.util.Base64; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -246,8 +247,8 @@ public class NsdService extends INsdManager.Stub { } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { - clientInfo.mClientIds.remove(clientId); - clientInfo.mClientRequests.remove(clientId); + clientInfo.mClientIds.delete(clientId); + clientInfo.mClientRequests.delete(clientId); mIdToClientInfoMap.remove(globalId); } @@ -300,7 +301,7 @@ public class NsdService extends INsdManager.Stub { clientInfo = mClients.get(msg.replyTo); try { - id = clientInfo.mClientIds.get(msg.arg2).intValue(); + id = clientInfo.mClientIds.get(msg.arg2); } catch (NullPointerException e) { replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -338,7 +339,7 @@ public class NsdService extends INsdManager.Stub { if (DBG) Slog.d(TAG, "unregister service"); clientInfo = mClients.get(msg.replyTo); try { - id = clientInfo.mClientIds.get(msg.arg2).intValue(); + id = clientInfo.mClientIds.get(msg.arg2); } catch (NullPointerException e) { replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -828,10 +829,10 @@ public class NsdService extends INsdManager.Stub { private NsdServiceInfo mResolvedService; /* A map from client id to unique id sent to mDns */ - private final SparseArray mClientIds = new SparseArray<>(); + private final SparseIntArray mClientIds = new SparseIntArray(); /* A map from client id to the type of the request we had received */ - private final SparseArray mClientRequests = new SparseArray<>(); + private final SparseIntArray mClientRequests = new SparseIntArray(); private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; @@ -858,6 +859,7 @@ public class NsdService extends INsdManager.Stub { // and send cancellations to the daemon. private void expungeAllRequests() { int globalId, clientId, i; + // TODO: to keep handler responsive, do not clean all requests for that client at once. for (i = 0; i < mClientIds.size(); i++) { clientId = mClientIds.keyAt(i); globalId = mClientIds.valueAt(i); @@ -885,15 +887,11 @@ public class NsdService extends INsdManager.Stub { // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, // return the corresponding listener id. mDnsClient id is also called a global id. private int getClientId(final int globalId) { - // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals) - // while also coercing the int primitives to Integer objects. - for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) { - int mDnsId = mClientIds.valueAt(i); - if (globalId == mDnsId) { - return mClientIds.keyAt(i); - } + int idx = mClientIds.indexOfValue(globalId); + if (idx < 0) { + return idx; } - return -1; + return mClientIds.keyAt(idx); } } From 912db99ddb3eb71fc4c8bf15bf72e0ca61af5efb Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 24 Apr 2017 16:41:03 +0900 Subject: [PATCH 0381/1150] NsdService: more cleanups This patch does some simple refactoring around management of nsd service enabled status. Test: TODO Bug: 37013369, 33298084 Change-Id: If1b124459a814cd0e821f683ccd568e30a698d2e --- .../java/com/android/server/NsdService.java | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 965835c4b2..2158f60089 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -99,11 +99,7 @@ public class NsdService extends INsdManager.Stub { ContentObserver contentObserver = new ContentObserver(this.getHandler()) { @Override public void onChange(boolean selfChange) { - if (isNsdEnabled()) { - mNsdStateMachine.sendMessage(NsdManager.ENABLE); - } else { - mNsdStateMachine.sendMessage(NsdManager.DISABLE); - } + notifyEnabled(isNsdEnabled()); } }; @@ -117,11 +113,8 @@ public class NsdService extends INsdManager.Stub { addState(mDefaultState); addState(mDisabledState, mDefaultState); addState(mEnabledState, mDefaultState); - if (isNsdEnabled()) { - setInitialState(mEnabledState); - } else { - setInitialState(mDisabledState); - } + State initialState = isNsdEnabled() ? mEnabledState : mDisabledState; + setInitialState(initialState); setLogRecSize(25); registerForNsdSetting(); } @@ -570,25 +563,22 @@ public class NsdService extends INsdManager.Stub { return new Messenger(mNsdStateMachine.getHandler()); } - public void setEnabled(boolean enable) { + public void setEnabled(boolean isEnabled) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL, "NsdService"); - mNsdSettings.putEnabledStatus(enable); - if (enable) { - mNsdStateMachine.sendMessage(NsdManager.ENABLE); - } else { - mNsdStateMachine.sendMessage(NsdManager.DISABLE); - } + mNsdSettings.putEnabledStatus(isEnabled); + notifyEnabled(isEnabled); } - private void sendNsdStateChangeBroadcast(boolean enabled) { + private void notifyEnabled(boolean isEnabled) { + mNsdStateMachine.sendMessage(isEnabled ? NsdManager.ENABLE : NsdManager.DISABLE); + } + + private void sendNsdStateChangeBroadcast(boolean isEnabled) { final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (enabled) { - intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED); - } else { - intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED); - } + int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED; + intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState); mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } From 6d58a32565ac32c05e2c46a7ea934424ce596dbf Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 7 Apr 2017 15:20:56 +0900 Subject: [PATCH 0382/1150] NetworkStatsFactory: fix double accounting on IPv6 only networks For 464xlat scenarios on IPv6 networks, the clatd interface setup introduces double counting of apps ipv4 traffic. NetworkStatsFactory was accounting for this on the tx path, but not on the rx path. Also it did not accounted for the 20 bytes added by the IPv6 header. This patch subtract correctly the rx and tx traffic from the root uid on the underlying interface, and also adds correctly the 20 bytes cost per packet on the stacked interface for 464xlat traffic. Test: added several new unit tests, based on synthetic data and real data also. Bug: 33681750 Change-Id: I2675643b220acbc6110179fa937d4c313b6f5e32 --- .../internal/net/NetworkStatsFactory.java | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 506114bd01..2fb3532c8f 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -50,6 +50,11 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; + private static final String CLATD_INTERFACE_PREFIX = "v4-"; + // Delta between IPv4 header (20b) and IPv6 header (40b). + // Used for correct stats accounting on clatd interfaces. + private static final int IPV4V6_HEADER_DELTA = 20; + /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ @@ -57,6 +62,7 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; + // TODO: to improve testability and avoid global state, do not use a static variable. @GuardedBy("sStackedIfaces") private static final ArrayMap sStackedIfaces = new ArrayMap<>(); @@ -124,9 +130,7 @@ public class NetworkStatsFactory { stats.addValues(entry); reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing stats", e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); @@ -171,9 +175,7 @@ public class NetworkStatsFactory { stats.addValues(entry); reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing stats", e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); @@ -188,26 +190,32 @@ public class NetworkStatsFactory { public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, NetworkStats lastStats) throws IOException { - final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, - lastStats); + final NetworkStats stats = + readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); + NetworkStats.Entry entry = null; // for recycling synchronized (sStackedIfaces) { - // Sigh, xt_qtaguid ends up double-counting tx traffic going through - // clatd interfaces, so we need to subtract it here. + // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 + // packet on the stacked interface, and once as translated to an IPv6 packet on the + // base interface. For correct stats accounting on the base interface, every 464xlat + // packet needs to be subtracted from the root UID on the base interface both for tx + // and rx traffic (http://b/12249687, http:/b/33681750). final int size = sStackedIfaces.size(); for (int i = 0; i < size; i++) { final String stackedIface = sStackedIfaces.keyAt(i); final String baseIface = sStackedIfaces.valueAt(i); + if (!stackedIface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; + } - // Count up the tx traffic and subtract from root UID on the - // base interface. - NetworkStats.Entry adjust = new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, - 0L, 0L); - NetworkStats.Entry entry = null; + NetworkStats.Entry adjust = + new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); for (int j = 0; j < stats.size(); j++) { entry = stats.getValues(j, entry); if (Objects.equals(entry.iface, stackedIface)) { - adjust.txBytes -= entry.txBytes; + adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets -= entry.rxPackets; adjust.txPackets -= entry.txPackets; } } @@ -215,19 +223,20 @@ public class NetworkStatsFactory { } } - // Double sigh, all rx traffic on clat needs to be tweaked to - // account for the dropped IPv6 header size post-unwrap. - NetworkStats.Entry entry = null; + // For 464xlat traffic, xt_qtaguid only counts the bytes of the inner IPv4 packet sent on + // the stacked interface with prefix "v4-" and drops the IPv6 header size after unwrapping. + // To account correctly for on-the-wire traffic, add the 20 additional bytes difference + // for all packets (http://b/12249687, http:/b/33681750). for (int i = 0; i < stats.size(); i++) { entry = stats.getValues(i, entry); - if (entry.iface != null && entry.iface.startsWith("clat")) { - // Delta between IPv4 header (20b) and IPv6 header (40b) - entry.rxBytes = entry.rxPackets * 20; - entry.rxPackets = 0; - entry.txBytes = 0; - entry.txPackets = 0; - stats.combineValues(entry); + if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; } + entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA; + entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA; + entry.rxPackets = 0; + entry.txPackets = 0; + stats.combineValues(entry); } return stats; @@ -305,9 +314,7 @@ public class NetworkStatsFactory { reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing idx " + idx, e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); From 5efd907d853717d2a96c55867b3b79d1634d7e1c Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 27 Apr 2017 14:52:53 +0900 Subject: [PATCH 0383/1150] NetworkStatsFactory: no double looping on stats + stacked interfaces This patch uses the associative structure of the stacked/base interface collection to avoid the two nested for loops over stacked/base interfaces and all stats entries when correcting 464xlat traffic stats. Consequently the list of stats entries is iterated only once. Test: runtest -x frameworks/base/../NetworkStatsFactoryTest.java Bug: 33681750 Change-Id: I84ae997fb693b909f431764697627b9957131732 --- .../internal/net/NetworkStatsFactory.java | 63 +++++++++---------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 2fb3532c8f..3d3e148fb3 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -192,46 +192,43 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - NetworkStats.Entry entry = null; // for recycling - + final ArrayMap stackedIfaces; synchronized (sStackedIfaces) { - // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - // packet on the stacked interface, and once as translated to an IPv6 packet on the - // base interface. For correct stats accounting on the base interface, every 464xlat - // packet needs to be subtracted from the root UID on the base interface both for tx - // and rx traffic (http://b/12249687, http:/b/33681750). - final int size = sStackedIfaces.size(); - for (int i = 0; i < size; i++) { - final String stackedIface = sStackedIfaces.keyAt(i); - final String baseIface = sStackedIfaces.valueAt(i); - if (!stackedIface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - - NetworkStats.Entry adjust = - new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int j = 0; j < stats.size(); j++) { - entry = stats.getValues(j, entry); - if (Objects.equals(entry.iface, stackedIface)) { - adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets -= entry.rxPackets; - adjust.txPackets -= entry.txPackets; - } - } - stats.combineValues(adjust); - } + stackedIfaces = new ArrayMap<>(sStackedIfaces); } + // Total 464xlat traffic to subtract from uid 0 on all base interfaces. + final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - // For 464xlat traffic, xt_qtaguid only counts the bytes of the inner IPv4 packet sent on - // the stacked interface with prefix "v4-" and drops the IPv6 header size after unwrapping. - // To account correctly for on-the-wire traffic, add the 20 additional bytes difference - // for all packets (http://b/12249687, http:/b/33681750). + NetworkStats.Entry entry = null; // For recycling + + // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 + // packet on the stacked interface, and once as translated to an IPv6 packet on the + // base interface. For correct stats accounting on the base interface, every 464xlat + // packet needs to be subtracted from the root UID on the base interface both for tx + // and rx traffic (http://b/12249687, http:/b/33681750). for (int i = 0; i < stats.size(); i++) { entry = stats.getValues(i, entry); if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; } + final String baseIface = stackedIfaces.get(entry.iface); + if (baseIface == null) { + continue; + } + + NetworkStats.Entry adjust = + new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); + // Subtract any 464lat traffic seen for the root UID on the current base interface. + adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets -= entry.rxPackets; + adjust.txPackets -= entry.txPackets; + adjustments.combineValues(adjust); + + // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent + // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes + // difference for all packets (http://b/12249687, http:/b/33681750). entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA; entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA; entry.rxPackets = 0; @@ -239,6 +236,8 @@ public class NetworkStatsFactory { stats.combineValues(entry); } + stats.combineAllValues(adjustments); + return stats; } From 410ab36029c6f3e1262da1ffccfdc4d944c230b8 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 7 Apr 2017 15:20:56 +0900 Subject: [PATCH 0384/1150] NetworkStatsFactory: fix double accounting on IPv6 only networks For 464xlat scenarios on IPv6 networks, the clatd interface setup introduces double counting of apps ipv4 traffic. NetworkStatsFactory was accounting for this on the tx path, but not on the rx path. Also it did not accounted for the 20 bytes added by the IPv6 header. This patch subtract correctly the rx and tx traffic from the root uid on the underlying interface, and also adds correctly the 20 bytes cost per packet on the stacked interface for 464xlat traffic. Test: added several new unit tests, based on synthetic data and real data also. Bug: 33681750 Change-Id: I4867fe181938d94b5594b3d88896a3c4e01d895c Merged-In: I2675643b220acbc6110179fa937d4c313b6f5e32 (cherry picked from commit e1bb3a14d1ee1aba2f92e5bccf659774699eaffe) --- .../internal/net/NetworkStatsFactory.java | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 506114bd01..2fb3532c8f 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -50,6 +50,11 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; + private static final String CLATD_INTERFACE_PREFIX = "v4-"; + // Delta between IPv4 header (20b) and IPv6 header (40b). + // Used for correct stats accounting on clatd interfaces. + private static final int IPV4V6_HEADER_DELTA = 20; + /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ @@ -57,6 +62,7 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; + // TODO: to improve testability and avoid global state, do not use a static variable. @GuardedBy("sStackedIfaces") private static final ArrayMap sStackedIfaces = new ArrayMap<>(); @@ -124,9 +130,7 @@ public class NetworkStatsFactory { stats.addValues(entry); reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing stats", e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); @@ -171,9 +175,7 @@ public class NetworkStatsFactory { stats.addValues(entry); reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing stats", e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); @@ -188,26 +190,32 @@ public class NetworkStatsFactory { public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, NetworkStats lastStats) throws IOException { - final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, - lastStats); + final NetworkStats stats = + readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); + NetworkStats.Entry entry = null; // for recycling synchronized (sStackedIfaces) { - // Sigh, xt_qtaguid ends up double-counting tx traffic going through - // clatd interfaces, so we need to subtract it here. + // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 + // packet on the stacked interface, and once as translated to an IPv6 packet on the + // base interface. For correct stats accounting on the base interface, every 464xlat + // packet needs to be subtracted from the root UID on the base interface both for tx + // and rx traffic (http://b/12249687, http:/b/33681750). final int size = sStackedIfaces.size(); for (int i = 0; i < size; i++) { final String stackedIface = sStackedIfaces.keyAt(i); final String baseIface = sStackedIfaces.valueAt(i); + if (!stackedIface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; + } - // Count up the tx traffic and subtract from root UID on the - // base interface. - NetworkStats.Entry adjust = new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, - 0L, 0L); - NetworkStats.Entry entry = null; + NetworkStats.Entry adjust = + new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); for (int j = 0; j < stats.size(); j++) { entry = stats.getValues(j, entry); if (Objects.equals(entry.iface, stackedIface)) { - adjust.txBytes -= entry.txBytes; + adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets -= entry.rxPackets; adjust.txPackets -= entry.txPackets; } } @@ -215,19 +223,20 @@ public class NetworkStatsFactory { } } - // Double sigh, all rx traffic on clat needs to be tweaked to - // account for the dropped IPv6 header size post-unwrap. - NetworkStats.Entry entry = null; + // For 464xlat traffic, xt_qtaguid only counts the bytes of the inner IPv4 packet sent on + // the stacked interface with prefix "v4-" and drops the IPv6 header size after unwrapping. + // To account correctly for on-the-wire traffic, add the 20 additional bytes difference + // for all packets (http://b/12249687, http:/b/33681750). for (int i = 0; i < stats.size(); i++) { entry = stats.getValues(i, entry); - if (entry.iface != null && entry.iface.startsWith("clat")) { - // Delta between IPv4 header (20b) and IPv6 header (40b) - entry.rxBytes = entry.rxPackets * 20; - entry.rxPackets = 0; - entry.txBytes = 0; - entry.txPackets = 0; - stats.combineValues(entry); + if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; } + entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA; + entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA; + entry.rxPackets = 0; + entry.txPackets = 0; + stats.combineValues(entry); } return stats; @@ -305,9 +314,7 @@ public class NetworkStatsFactory { reader.finishLine(); } - } catch (NullPointerException e) { - throw new ProtocolException("problem parsing idx " + idx, e); - } catch (NumberFormatException e) { + } catch (NullPointerException|NumberFormatException e) { throw new ProtocolException("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); From bad59112f567c005db79030d2a8d17816328c3dc Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Mon, 15 May 2017 16:34:52 -0700 Subject: [PATCH 0385/1150] Be resilient to restoring unintelligible network templates Some OEMs have introduced incompatible network bookkeeping. We now detect and ignore those network definitions at restore time. In addition, we now * log when an undefined network match type is used to construct a NetworkTemplate instance, and * quietly refuse to match such a NetworkTemplate against any known network identifier, rather than crashing the inquiring app. Bug 38151335 Test: manual Change-Id: I565b6f6b87df1f13a8c0c01ae6049bda270b1e48 --- core/java/android/net/NetworkTemplate.java | 43 +++++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index caf79829db..0d2fcd0740 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -18,8 +18,8 @@ package android.net; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; -import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; @@ -34,8 +34,8 @@ import static android.telephony.TelephonyManager.getNetworkClass; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; +import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.ByteArrayOutputStream; @@ -52,14 +52,18 @@ import java.util.Objects; * @hide */ public class NetworkTemplate implements Parcelable { + private static final String TAG = "NetworkTemplate"; + /** * Current Version of the Backup Serializer. */ private static final int BACKUP_VERSION = 1; public static final int MATCH_MOBILE_ALL = 1; + /** @deprecated don't use this any more */ @Deprecated public static final int MATCH_MOBILE_3G_LOWER = 2; + /** @deprecated don't use this any more */ @Deprecated public static final int MATCH_MOBILE_4G = 3; public static final int MATCH_WIFI = 4; @@ -69,9 +73,26 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + private static boolean isKnownMatchRule(final int rule) { + switch (rule) { + case MATCH_MOBILE_ALL: + case MATCH_MOBILE_3G_LOWER: + case MATCH_MOBILE_4G: + case MATCH_WIFI: + case MATCH_ETHERNET: + case MATCH_MOBILE_WILDCARD: + case MATCH_WIFI_WILDCARD: + case MATCH_BLUETOOTH: + case MATCH_PROXY: + return true; + + default: + return false; + } + } + private static boolean sForceAllNetworkTypes = false; - @VisibleForTesting public static void forceAllNetworkTypes() { sForceAllNetworkTypes = true; } @@ -180,6 +201,11 @@ public class NetworkTemplate implements Parcelable { mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; + + if (!isKnownMatchRule(matchRule)) { + Log.e(TAG, "Unknown network template rule " + matchRule + + " will not match any identity."); + } } private NetworkTemplate(Parcel in) { @@ -294,7 +320,9 @@ public class NetworkTemplate implements Parcelable { case MATCH_PROXY: return matchesProxy(ident); default: - throw new IllegalArgumentException("unknown network template"); + // We have no idea what kind of network template we are, so we + // just claim not to match anything. + return false; } } @@ -428,7 +456,7 @@ public class NetworkTemplate implements Parcelable { case MATCH_PROXY: return "PROXY"; default: - return "UNKNOWN"; + return "UNKNOWN(" + matchRule + ")"; } } @@ -496,6 +524,11 @@ public class NetworkTemplate implements Parcelable { String subscriberId = BackupUtils.readString(in); String networkId = BackupUtils.readString(in); + if (!isKnownMatchRule(matchRule)) { + throw new BackupUtils.BadVersionException( + "Restored network template contains unknown match rule " + matchRule); + } + return new NetworkTemplate(matchRule, subscriberId, networkId); } } From a086cac905f913aa4689942ea49c3752aa37b652 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Fri, 28 Apr 2017 15:31:10 +0900 Subject: [PATCH 0386/1150] NsdService: test coverage for client requests. Adding coverage for: - NsdManager client disconnection - in-flight request GC Test: new test passes Bug: 37013369, 33298084 Bug: 38503832 (cherry picked from commit 4dd4db77209ab2ef302a3a2a4892b05aadd26ec6) Change-Id: I02aca772d88306acae09db739ced7a2b1119b72b --- core/java/android/net/nsd/NsdManager.java | 8 +++++ .../java/com/android/server/NsdService.java | 35 ++++++------------- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 3fd9f19364..22bda77195 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -269,6 +269,14 @@ public final class NsdManager { init(); } + /** + * @hide + */ + @VisibleForTesting + public void disconnect() { + mAsyncChannel.disconnect(); + } + /** * Failures are passed with {@link RegistrationListener#onRegistrationFailed}, * {@link RegistrationListener#onUnregistrationFailed}, diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index d762214fad..4bccfa5408 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -49,7 +49,6 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.server.NativeDaemonConnector.Command; /** * Network Service Discovery Service handles remote service discovery operation requests by @@ -155,7 +154,7 @@ public class NsdService extends INsdManager.Stub { } //Last client if (mClients.size() == 0) { - stopMDnsDaemon(); + mDaemon.stop(); } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: @@ -215,14 +214,14 @@ public class NsdService extends INsdManager.Stub { public void enter() { sendNsdStateChangeBroadcast(true); if (mClients.size() > 0) { - startMDnsDaemon(); + mDaemon.start(); } } @Override public void exit() { if (mClients.size() > 0) { - stopMDnsDaemon(); + mDaemon.stop(); } } @@ -256,7 +255,7 @@ public class NsdService extends INsdManager.Stub { //First client if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && mClients.size() == 0) { - startMDnsDaemon(); + mDaemon.start(); } return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: @@ -703,26 +702,13 @@ public class NsdService extends INsdManager.Stub { return true; } - public boolean execute(Command cmd) { - if (DBG) { - Slog.d(TAG, cmd.toString()); - } - try { - mNativeConnector.execute(cmd); - } catch (NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute " + cmd, e); - return false; - } - return true; + public void start() { + execute("start-service"); } - } - private boolean startMDnsDaemon() { - return mDaemon.execute("start-service"); - } - - private boolean stopMDnsDaemon() { - return mDaemon.execute("stop-service"); + public void stop() { + execute("stop-service"); + } } private boolean registerService(int regId, NsdServiceInfo service) { @@ -734,8 +720,7 @@ public class NsdService extends INsdManager.Stub { int port = service.getPort(); byte[] textRecord = service.getTxtRecord(); String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", ""); - Command cmd = new Command("mdnssd", "register", regId, name, type, port, record); - return mDaemon.execute(cmd); + return mDaemon.execute("register", regId, name, type, port, record); } private boolean unregisterService(int regId) { From a81f4156e6f5d8e117dd8050503ccab5c45b9d0e Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 11 Apr 2017 14:42:47 +0900 Subject: [PATCH 0387/1150] NsdService: simple cleanups This patch replace some SparseArray with SparseIntArray, and simplify a value lookup function by using indexOfValue(). Test: TODO Bug: 37013369, 33298084 Bug: 38503832 (cherry picked from commit d2552aee119299bf66d694960c72a00141642ef5) Change-Id: Ifbe4f01bad8964e6f3a6e9633415959ab5feb0af --- .../java/com/android/server/NsdService.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 4bccfa5408..0ffac077d0 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -35,6 +35,7 @@ import android.provider.Settings; import android.util.Base64; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseIntArray; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -240,8 +241,8 @@ public class NsdService extends INsdManager.Stub { } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { - clientInfo.mClientIds.remove(clientId); - clientInfo.mClientRequests.remove(clientId); + clientInfo.mClientIds.delete(clientId); + clientInfo.mClientRequests.delete(clientId); mIdToClientInfoMap.remove(globalId); } @@ -294,7 +295,7 @@ public class NsdService extends INsdManager.Stub { clientInfo = mClients.get(msg.replyTo); try { - id = clientInfo.mClientIds.get(msg.arg2).intValue(); + id = clientInfo.mClientIds.get(msg.arg2); } catch (NullPointerException e) { replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -332,7 +333,7 @@ public class NsdService extends INsdManager.Stub { if (DBG) Slog.d(TAG, "unregister service"); clientInfo = mClients.get(msg.replyTo); try { - id = clientInfo.mClientIds.get(msg.arg2).intValue(); + id = clientInfo.mClientIds.get(msg.arg2); } catch (NullPointerException e) { replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); @@ -813,10 +814,10 @@ public class NsdService extends INsdManager.Stub { private NsdServiceInfo mResolvedService; /* A map from client id to unique id sent to mDns */ - private final SparseArray mClientIds = new SparseArray<>(); + private final SparseIntArray mClientIds = new SparseIntArray(); /* A map from client id to the type of the request we had received */ - private final SparseArray mClientRequests = new SparseArray<>(); + private final SparseIntArray mClientRequests = new SparseIntArray(); private ClientInfo(AsyncChannel c, Messenger m) { mChannel = c; @@ -843,6 +844,7 @@ public class NsdService extends INsdManager.Stub { // and send cancellations to the daemon. private void expungeAllRequests() { int globalId, clientId, i; + // TODO: to keep handler responsive, do not clean all requests for that client at once. for (i = 0; i < mClientIds.size(); i++) { clientId = mClientIds.keyAt(i); globalId = mClientIds.valueAt(i); @@ -870,15 +872,11 @@ public class NsdService extends INsdManager.Stub { // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, // return the corresponding listener id. mDnsClient id is also called a global id. private int getClientId(final int globalId) { - // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals) - // while also coercing the int primitives to Integer objects. - for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) { - int mDnsId = mClientIds.valueAt(i); - if (globalId == mDnsId) { - return mClientIds.keyAt(i); - } + int idx = mClientIds.indexOfValue(globalId); + if (idx < 0) { + return idx; } - return -1; + return mClientIds.keyAt(idx); } } From 298ac9487eb68a61b0cadfb291aac7c368de2308 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 24 May 2017 15:39:39 +0900 Subject: [PATCH 0388/1150] NsdServiceInfo: move test to tests/net This patch also - adds a license plate to NsdServiceInfoTest - fixes some formatting and style issues package name uses of canonical junit asserts - update NsdServiceInfoTest to not use the deprecated AndroidTestCase Bug: 62044295 Bug: 32561414 Test: $ runtest frameworks-net passes Change-Id: Ie5ebb00172aef4eec19e6ecd2b41c4467901b93d --- core/java/android/net/nsd/NsdServiceInfo.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 7b845be749..bccaf60e69 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Map; - /** * A class representing service information for network service discovery * {@see NsdManager} @@ -43,7 +42,7 @@ public final class NsdServiceInfo implements Parcelable { private String mServiceType; - private final ArrayMap mTxtRecord = new ArrayMap(); + private final ArrayMap mTxtRecord = new ArrayMap<>(); private InetAddress mHost; From f60833507e30522afc99010a0fc9c9c38c92618a Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Thu, 25 May 2017 13:49:32 +0900 Subject: [PATCH 0389/1150] NsdService: do not use ContentResolver directly This patch changes NsdService to call registerContentObserver in the ContentResolver class indirectly through NsdSettings. This allows to easily intercept it and mock it in unit tests, and solves test failures on the internal master branch where registerContentObserver uses final or static methods that cannot be worked around. Bug: 32561414 Bug: 62044295 Test: runtest -x frameworks/base/tests/net/../NsdServiceTest.java Change-Id: If4deb106de551746babb70196b20f21ece478850 --- .../java/com/android/server/NsdService.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 2158f60089..5f6bd59453 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Intent; import android.content.pm.PackageManager; import android.database.ContentObserver; +import android.net.Uri; import android.net.nsd.NsdServiceInfo; import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; @@ -96,16 +97,15 @@ public class NsdService extends INsdManager.Stub { * Observes the NSD on/off setting, and takes action when changed. */ private void registerForNsdSetting() { - ContentObserver contentObserver = new ContentObserver(this.getHandler()) { + final ContentObserver contentObserver = new ContentObserver(this.getHandler()) { @Override public void onChange(boolean selfChange) { notifyEnabled(isNsdEnabled()); } }; - mContext.getContentResolver().registerContentObserver( - Settings.Global.getUriFor(Settings.Global.NSD_ON), - false, contentObserver); + final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON); + mNsdSettings.registerContentObserver(uri, contentObserver); } NsdStateMachine(String name, Handler handler) { @@ -885,13 +885,18 @@ public class NsdService extends INsdManager.Stub { } } + /** + * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to + * override, or have side effects on global state in unit tests. + */ @VisibleForTesting public interface NsdSettings { boolean isEnabled(); void putEnabledStatus(boolean isEnabled); + void registerContentObserver(Uri uri, ContentObserver observer); static NsdSettings makeDefault(Context context) { - ContentResolver resolver = context.getContentResolver(); + final ContentResolver resolver = context.getContentResolver(); return new NsdSettings() { @Override public boolean isEnabled() { @@ -902,6 +907,11 @@ public class NsdService extends INsdManager.Stub { public void putEnabledStatus(boolean isEnabled) { Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0); } + + @Override + public void registerContentObserver(Uri uri, ContentObserver observer) { + resolver.registerContentObserver(uri, false, observer); + } }; } } From fe07698782fcde17fff5d7be45ee7b2a36b8a43c Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 26 May 2017 16:08:22 -0700 Subject: [PATCH 0390/1150] Added video calling data usage per-uid support Now the VT call data usage will be counted under current dialer's data usage as well as the total device data usage. Test: Manual bug: 37671326 Change-Id: I8351e9ae17c84210f7ca6c319d3bddcbb0043341 --- .../server/net/NetworkStatsService.java | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e746355097..ab685ca28b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -18,7 +18,6 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; -import static android.Manifest.permission.DUMP; import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; @@ -31,7 +30,6 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; @@ -58,14 +56,13 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.util.Preconditions.checkArgument; + import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.app.AlarmManager; -import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -1041,7 +1038,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats xtSnapshot = getNetworkStatsXtAndVt(); + final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1367,7 +1364,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Return snapshot of current UID statistics, including any - * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. + * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} + * values. */ private NetworkStats getNetworkStatsUidDetail() throws RemoteException { final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); @@ -1375,43 +1373,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(); uidSnapshot.combineAllValues(tetherSnapshot); + + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + + // fold video calling data usage stats into uid snapshot + final NetworkStats vtStats = telephonyManager.getVtDataUsage(true); + if (vtStats != null) { + uidSnapshot.combineAllValues(vtStats); + } uidSnapshot.combineAllValues(mUidOperations); return uidSnapshot; } /** - * Return snapshot of current XT plus VT statistics. + * Return snapshot of current XT statistics with video calling data usage statistics. */ - private NetworkStats getNetworkStatsXtAndVt() throws RemoteException { + private NetworkStats getNetworkStatsXt() throws RemoteException { final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); - TelephonyManager tm = (TelephonyManager) mContext.getSystemService( + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); - long usage = tm.getVtDataUsage(); - - if (LOGV) Slog.d(TAG, "VT call data usage = " + usage); - - final NetworkStats vtSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 1); - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.iface = VT_INTERFACE; - entry.uid = -1; - entry.set = TAG_ALL; - entry.tag = TAG_NONE; - - // Since modem only tell us the total usage instead of each usage for RX and TX, - // we need to split it up (though it might not quite accurate). At - // least we can make sure the data usage report to the user will still be accurate. - entry.rxBytes = usage / 2; - entry.rxPackets = 0; - entry.txBytes = usage - entry.rxBytes; - entry.txPackets = 0; - vtSnapshot.combineValues(entry); - - // Merge VT int XT - xtSnapshot.combineAllValues(vtSnapshot); + // Merge video calling data usage into XT + final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(false); + if (vtSnapshot != null) { + xtSnapshot.combineAllValues(vtSnapshot); + } return xtSnapshot; } From 955599c5477dbe85aade5275dbab4081c54cb934 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Fri, 26 May 2017 16:08:22 -0700 Subject: [PATCH 0391/1150] Added video calling data usage per-uid support Now the VT call data usage will be counted under current dialer's data usage as well as the total device data usage. Test: Manual bug: 37671326 Merged-In: I8351e9ae17c84210f7ca6c319d3bddcbb0043341 Change-Id: I8351e9ae17c84210f7ca6c319d3bddcbb0043341 --- .../server/net/NetworkStatsService.java | 52 ++++++++----------- 1 file changed, 21 insertions(+), 31 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 060dd73d11..4152070dc6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -31,7 +31,6 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; @@ -58,14 +57,13 @@ import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.util.Preconditions.checkArgument; + import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.app.AlarmManager; -import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -1031,7 +1029,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); - final NetworkStats xtSnapshot = getNetworkStatsXtAndVt(); + final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1323,7 +1321,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Return snapshot of current UID statistics, including any - * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values. + * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} + * values. */ private NetworkStats getNetworkStatsUidDetail() throws RemoteException { final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); @@ -1331,43 +1330,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(); uidSnapshot.combineAllValues(tetherSnapshot); + + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + + // fold video calling data usage stats into uid snapshot + final NetworkStats vtStats = telephonyManager.getVtDataUsage(true); + if (vtStats != null) { + uidSnapshot.combineAllValues(vtStats); + } uidSnapshot.combineAllValues(mUidOperations); return uidSnapshot; } /** - * Return snapshot of current XT plus VT statistics. + * Return snapshot of current XT statistics with video calling data usage statistics. */ - private NetworkStats getNetworkStatsXtAndVt() throws RemoteException { + private NetworkStats getNetworkStatsXt() throws RemoteException { final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); - TelephonyManager tm = (TelephonyManager) mContext.getSystemService( + final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); - long usage = tm.getVtDataUsage(); - - if (LOGV) Slog.d(TAG, "VT call data usage = " + usage); - - final NetworkStats vtSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), 1); - - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.iface = VT_INTERFACE; - entry.uid = -1; - entry.set = TAG_ALL; - entry.tag = TAG_NONE; - - // Since modem only tell us the total usage instead of each usage for RX and TX, - // we need to split it up (though it might not quite accurate). At - // least we can make sure the data usage report to the user will still be accurate. - entry.rxBytes = usage / 2; - entry.rxPackets = 0; - entry.txBytes = usage - entry.rxBytes; - entry.txPackets = 0; - vtSnapshot.combineValues(entry); - - // Merge VT int XT - xtSnapshot.combineAllValues(vtSnapshot); + // Merge video calling data usage into XT + final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(false); + if (vtSnapshot != null) { + xtSnapshot.combineAllValues(vtSnapshot); + } return xtSnapshot; } From 8086539071db713d014fc864bfbd279b206ac457 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 4 Apr 2017 19:37:48 -0700 Subject: [PATCH 0392/1150] Add UDP Encap Socket Support to IpSecManager -Implement the UdpEncapsulationSocket -Convert all ManagedResources to use resourceIds -Rework ManagedResource to track resourceIds Bug: 30984788 Test: cts - IpSecManagerTest#testUdpEncapsulation() Change-Id: I7b1099c487051a8d951c1485791c4b6cef2deb1d --- core/java/android/net/IIpSecService.aidl | 11 +- core/java/android/net/IpSecConfig.java | 24 +- core/java/android/net/IpSecManager.java | 145 +++-- core/java/android/net/IpSecSpiResponse.aidl | 20 + core/java/android/net/IpSecSpiResponse.java | 78 +++ core/java/android/net/IpSecTransform.java | 39 +- .../android/net/IpSecTransformResponse.aidl | 20 + .../android/net/IpSecTransformResponse.java | 73 +++ .../android/net/IpSecUdpEncapResponse.aidl | 20 + .../android/net/IpSecUdpEncapResponse.java | 96 +++ .../java/com/android/server/IpSecService.java | 547 +++++++++++++----- 11 files changed, 834 insertions(+), 239 deletions(-) create mode 100644 core/java/android/net/IpSecSpiResponse.aidl create mode 100644 core/java/android/net/IpSecSpiResponse.java create mode 100644 core/java/android/net/IpSecTransformResponse.aidl create mode 100644 core/java/android/net/IpSecTransformResponse.java create mode 100644 core/java/android/net/IpSecUdpEncapResponse.aidl create mode 100644 core/java/android/net/IpSecUdpEncapResponse.java diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 0aa3ce66eb..0b1ea98f2e 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -18,6 +18,9 @@ package android.net; import android.net.Network; import android.net.IpSecConfig; +import android.net.IpSecUdpEncapResponse; +import android.net.IpSecSpiResponse; +import android.net.IpSecTransformResponse; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -27,16 +30,16 @@ import android.os.ParcelFileDescriptor; */ interface IIpSecService { - Bundle reserveSecurityParameterIndex( + IpSecSpiResponse reserveSecurityParameterIndex( int direction, in String remoteAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); - Bundle openUdpEncapsulationSocket(int port, in IBinder binder); + IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, in IBinder binder); - void closeUdpEncapsulationSocket(in ParcelFileDescriptor socket); + void closeUdpEncapsulationSocket(int resourceId); - Bundle createTransportModeTransform(in IpSecConfig c, in IBinder binder); + IpSecTransformResponse createTransportModeTransform(in IpSecConfig c, in IBinder binder); void deleteTransportModeTransform(int transformId); diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 13dc19f685..8b80f2ba50 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -40,7 +40,7 @@ public final class IpSecConfig implements Parcelable { // Minimum requirements for identifying a transform // SPI identifying the IPsec flow in packet processing // and a remote IP address - int spi; + int spiResourceId; // Encryption Algorithm IpSecAlgorithm encryption; @@ -54,7 +54,7 @@ public final class IpSecConfig implements Parcelable { // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE int encapType; - int encapLocalPort; + int encapLocalPortResourceId; int encapRemotePort; // An interval, in seconds between the NattKeepalive packets @@ -69,8 +69,8 @@ public final class IpSecConfig implements Parcelable { return localAddress; } - public int getSpi(int direction) { - return flow[direction].spi; + public int getSpiResourceId(int direction) { + return flow[direction].spiResourceId; } public InetAddress getRemoteAddress() { @@ -93,8 +93,8 @@ public final class IpSecConfig implements Parcelable { return encapType; } - public int getEncapLocalPort() { - return encapLocalPort; + public int getEncapLocalResourceId() { + return encapLocalPortResourceId; } public int getEncapRemotePort() { @@ -119,14 +119,14 @@ public final class IpSecConfig implements Parcelable { // TODO: Use a byte array or other better method for storing IPs that can also include scope out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); out.writeParcelable(network, flags); - out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi); + out.writeInt(flow[IpSecTransform.DIRECTION_IN].spiResourceId); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); - out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi); + out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spiResourceId); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); out.writeInt(encapType); - out.writeInt(encapLocalPort); + out.writeInt(encapLocalPortResourceId); out.writeInt(encapRemotePort); } @@ -151,18 +151,18 @@ public final class IpSecConfig implements Parcelable { localAddress = readInetAddressFromParcel(in); remoteAddress = readInetAddressFromParcel(in); network = (Network) in.readParcelable(Network.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_IN].spi = in.readInt(); + flow[IpSecTransform.DIRECTION_IN].spiResourceId = in.readInt(); flow[IpSecTransform.DIRECTION_IN].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_IN].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt(); + flow[IpSecTransform.DIRECTION_OUT].spiResourceId = in.readInt(); flow[IpSecTransform.DIRECTION_OUT].encryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); flow[IpSecTransform.DIRECTION_OUT].authentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); encapType = in.readInt(); - encapLocalPort = in.readInt(); + encapLocalPortResourceId = in.readInt(); encapRemotePort = in.readInt(); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 114e46e54f..0240cf1509 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,10 +19,10 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.os.Binder; -import android.os.Bundle; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.AndroidException; +import android.util.Log; import dalvik.system.CloseGuard; import java.io.FileDescriptor; import java.io.IOException; @@ -57,12 +57,6 @@ public final class IpSecManager { public static final int SPI_UNAVAILABLE = 2; } - /** @hide */ - public static final String KEY_STATUS = "status"; - /** @hide */ - public static final String KEY_RESOURCE_ID = "resourceId"; - /** @hide */ - public static final String KEY_SPI = "spi"; /** @hide */ public static final int INVALID_RESOURCE_ID = 0; @@ -128,7 +122,11 @@ public final class IpSecManager { */ @Override public void close() { - mSpi = INVALID_SECURITY_PARAMETER_INDEX; + try { + mService.releaseSecurityParameterIndex(mResourceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } mCloseGuard.close(); } @@ -147,7 +145,7 @@ public final class IpSecManager { mService = service; mRemoteAddress = remoteAddress; try { - Bundle result = + IpSecSpiResponse result = mService.reserveSecurityParameterIndex( direction, remoteAddress.getHostAddress(), spi, new Binder()); @@ -155,7 +153,7 @@ public final class IpSecManager { throw new NullPointerException("Received null response from IpSecService"); } - int status = result.getInt(KEY_STATUS); + int status = result.status; switch (status) { case Status.OK: break; @@ -168,8 +166,8 @@ public final class IpSecManager { throw new RuntimeException( "Unknown status returned by IpSecService: " + status); } - mSpi = result.getInt(KEY_SPI); - mResourceId = result.getInt(KEY_RESOURCE_ID); + mSpi = result.spi; + mResourceId = result.resourceId; if (mSpi == INVALID_SECURITY_PARAMETER_INDEX) { throw new RuntimeException("Invalid SPI returned by IpSecService: " + status); @@ -185,6 +183,11 @@ public final class IpSecManager { } mCloseGuard.open("open"); } + + /** @hide */ + int getResourceId() { + return mResourceId; + } } /** @@ -201,8 +204,7 @@ public final class IpSecManager { * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( - int direction, InetAddress remoteAddress) - throws ResourceUnavailableException { + int direction, InetAddress remoteAddress) throws ResourceUnavailableException { try { return new SecurityParameterIndex( mService, @@ -251,7 +253,9 @@ public final class IpSecManager { */ public void applyTransportModeTransform(Socket socket, IpSecTransform transform) throws IOException { - applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { + applyTransportModeTransform(pfd, transform); + } } /** @@ -269,15 +273,8 @@ public final class IpSecManager { */ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) throws IOException { - applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); - } - - /* Call down to activate a transform */ - private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { - try { - mService.applyTransportModeTransform(pfd, transform.getResourceId()); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { + applyTransportModeTransform(pfd, transform); } } @@ -295,7 +292,22 @@ public final class IpSecManager { */ public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) throws IOException { - applyTransportModeTransform(new ParcelFileDescriptor(socket), transform); + // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() + // constructor takes control and closes the user's FD when we exit the method + // This is behaviorally the same as the other versions, but the PFD constructor does not + // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup(). + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { + applyTransportModeTransform(pfd, transform); + } + } + + /* Call down to activate a transform */ + private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + try { + mService.applyTransportModeTransform(pfd, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -324,7 +336,9 @@ public final class IpSecManager { */ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) throws IOException { - removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { + removeTransportModeTransform(pfd, transform); + } } /** @@ -340,7 +354,9 @@ public final class IpSecManager { */ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) throws IOException { - removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { + removeTransportModeTransform(pfd, transform); + } } /** @@ -355,7 +371,9 @@ public final class IpSecManager { */ public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) throws IOException { - removeTransportModeTransform(new ParcelFileDescriptor(socket), transform); + try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { + removeTransportModeTransform(pfd, transform); + } } /* Call down to activate a transform */ @@ -388,33 +406,48 @@ public final class IpSecManager { * FileDescriptor. Instead, disposing of this socket requires a call to close(). */ public static final class UdpEncapsulationSocket implements AutoCloseable { - private final FileDescriptor mFd; + private final ParcelFileDescriptor mPfd; private final IIpSecService mService; + private final int mResourceId; + private final int mPort; private final CloseGuard mCloseGuard = CloseGuard.get(); private UdpEncapsulationSocket(@NonNull IIpSecService service, int port) - throws ResourceUnavailableException { + throws ResourceUnavailableException, IOException { mService = service; + try { + IpSecUdpEncapResponse result = + mService.openUdpEncapsulationSocket(port, new Binder()); + switch (result.status) { + case Status.OK: + break; + case Status.RESOURCE_UNAVAILABLE: + throw new ResourceUnavailableException( + "No more Sockets may be allocated by this requester."); + default: + throw new RuntimeException( + "Unknown status returned by IpSecService: " + result.status); + } + mResourceId = result.resourceId; + mPort = result.port; + mPfd = result.fileDescriptor; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } mCloseGuard.open("constructor"); - // TODO: go down to the kernel and get a socket on the specified - mFd = new FileDescriptor(); - } - - private UdpEncapsulationSocket(IIpSecService service) throws ResourceUnavailableException { - mService = service; - mCloseGuard.open("constructor"); - // TODO: go get a random socket on a random port - mFd = new FileDescriptor(); } /** Access the inner UDP Encapsulation Socket */ public FileDescriptor getSocket() { - return mFd; + if (mPfd == null) { + return null; + } + return mPfd.getFileDescriptor(); } /** Retrieve the port number of the inner encapsulation socket */ public int getPort() { - return 0; // TODO get the port number from the Socket; + return mPort; } @Override @@ -429,7 +462,18 @@ public final class IpSecManager { * @param fd a file descriptor previously returned as a UDP Encapsulation socket. */ public void close() throws IOException { - // TODO: Go close the socket + try { + mService.closeUdpEncapsulationSocket(mResourceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + try { + mPfd.close(); + } catch (IOException e) { + Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); + throw e; + } mCloseGuard.close(); } @@ -438,9 +482,13 @@ public final class IpSecManager { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); } - close(); } + + /** @hide */ + int getResourceId() { + return mResourceId; + } }; /** @@ -467,7 +515,13 @@ public final class IpSecManager { // socket. public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) throws IOException, ResourceUnavailableException { - // Temporary code + /* + * Most range checking is done in the service, but this version of the constructor expects + * a valid port number, and zero cannot be checked after being passed to the service. + */ + if (port == 0) { + throw new IllegalArgumentException("Specified port must be a valid port number!"); + } return new UdpEncapsulationSocket(mService, port); } @@ -491,8 +545,7 @@ public final class IpSecManager { // socket. public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { - // Temporary code - return new UdpEncapsulationSocket(mService); + return new UdpEncapsulationSocket(mService, 0); } /** diff --git a/core/java/android/net/IpSecSpiResponse.aidl b/core/java/android/net/IpSecSpiResponse.aidl new file mode 100644 index 0000000000..6484a0013c --- /dev/null +++ b/core/java/android/net/IpSecSpiResponse.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable IpSecSpiResponse; diff --git a/core/java/android/net/IpSecSpiResponse.java b/core/java/android/net/IpSecSpiResponse.java new file mode 100644 index 0000000000..71dfa03ac1 --- /dev/null +++ b/core/java/android/net/IpSecSpiResponse.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class is used to return an SPI and corresponding status from the IpSecService to an + * IpSecManager.SecurityParameterIndex. + * + * @hide + */ +public final class IpSecSpiResponse implements Parcelable { + private static final String TAG = "IpSecSpiResponse"; + + public final int resourceId; + public final int status; + public final int spi; + // Parcelable Methods + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(status); + out.writeInt(resourceId); + out.writeInt(spi); + } + + public IpSecSpiResponse(int inStatus, int inResourceId, int inSpi) { + status = inStatus; + resourceId = inResourceId; + spi = inSpi; + } + + public IpSecSpiResponse(int inStatus) { + if (inStatus == IpSecManager.Status.OK) { + throw new IllegalArgumentException("Valid status implies other args must be provided"); + } + status = inStatus; + resourceId = IpSecManager.INVALID_RESOURCE_ID; + spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + } + + private IpSecSpiResponse(Parcel in) { + status = in.readInt(); + resourceId = in.readInt(); + spi = in.readInt(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecSpiResponse createFromParcel(Parcel in) { + return new IpSecSpiResponse(in); + } + + public IpSecSpiResponse[] newArray(int size) { + return new IpSecSpiResponse[size]; + } + }; +} diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 639d1f2689..e65f534f3d 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -16,15 +16,12 @@ package android.net; import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static android.net.IpSecManager.KEY_RESOURCE_ID; -import static android.net.IpSecManager.KEY_STATUS; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -77,24 +74,24 @@ public final class IpSecTransform implements AutoCloseable { /** @hide */ public static final int ENCAP_NONE = 0; - /** - * IpSec traffic will be encapsulated within UDP as per RFC3498. - * - * @hide - */ - public static final int ENCAP_ESPINUDP = 1; - /** * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP. * * @hide */ - public static final int ENCAP_ESPINUDP_NONIKE = 2; + public static final int ENCAP_ESPINUDP_NON_IKE = 1; + + /** + * IpSec traffic will be encapsulated within UDP as per RFC3498. + * + * @hide + */ + public static final int ENCAP_ESPINUDP = 2; /** @hide */ - @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE}) + @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NON_IKE}) @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} @@ -139,10 +136,11 @@ public final class IpSecTransform implements AutoCloseable { synchronized (this) { try { IIpSecService svc = getIpSecService(); - Bundle result = svc.createTransportModeTransform(mConfig, new Binder()); - int status = result.getInt(KEY_STATUS); + IpSecTransformResponse result = + svc.createTransportModeTransform(mConfig, new Binder()); + int status = result.status; checkResultStatusAndThrow(status); - mResourceId = result.getInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); + mResourceId = result.resourceId; /* Keepalive will silently fail if not needed by the config; but, if needed and * it fails to start, we need to bail because a transform will not be reliable @@ -263,7 +261,10 @@ public final class IpSecTransform implements AutoCloseable { mConfig.getNattKeepaliveInterval(), mKeepaliveCallback, mConfig.getLocalAddress(), - mConfig.getEncapLocalPort(), + 0x1234, /* FIXME: get the real port number again, + which we need to retrieve from the provided + EncapsulationSocket, and which isn't currently + stashed in IpSecConfig */ mConfig.getRemoteAddress()); try { // FIXME: this is still a horrible way to fudge the synchronous callback @@ -360,7 +361,7 @@ public final class IpSecTransform implements AutoCloseable { @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { // TODO: convert to using the resource Id of the SPI. Then build() can validate // the owner in the IpSecService - mConfig.flow[direction].spi = spi.getSpi(); + mConfig.flow[direction].spiResourceId = spi.getResourceId(); return this; } @@ -394,7 +395,7 @@ public final class IpSecTransform implements AutoCloseable { IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { // TODO: check encap type is valid. mConfig.encapType = ENCAP_ESPINUDP; - mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket + mConfig.encapLocalPortResourceId = localSocket.getResourceId(); mConfig.encapRemotePort = remotePort; return this; } diff --git a/core/java/android/net/IpSecTransformResponse.aidl b/core/java/android/net/IpSecTransformResponse.aidl new file mode 100644 index 0000000000..546230d5b8 --- /dev/null +++ b/core/java/android/net/IpSecTransformResponse.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable IpSecTransformResponse; diff --git a/core/java/android/net/IpSecTransformResponse.java b/core/java/android/net/IpSecTransformResponse.java new file mode 100644 index 0000000000..cfc176227f --- /dev/null +++ b/core/java/android/net/IpSecTransformResponse.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class is used to return an IpSecTransform resource Id and and corresponding status from the + * IpSecService to an IpSecTransform object. + * + * @hide + */ +public final class IpSecTransformResponse implements Parcelable { + private static final String TAG = "IpSecTransformResponse"; + + public final int resourceId; + public final int status; + // Parcelable Methods + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(status); + out.writeInt(resourceId); + } + + public IpSecTransformResponse(int inStatus) { + if (inStatus == IpSecManager.Status.OK) { + throw new IllegalArgumentException("Valid status implies other args must be provided"); + } + status = inStatus; + resourceId = IpSecManager.INVALID_RESOURCE_ID; + } + + public IpSecTransformResponse(int inStatus, int inResourceId) { + status = inStatus; + resourceId = inResourceId; + } + + private IpSecTransformResponse(Parcel in) { + status = in.readInt(); + resourceId = in.readInt(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecTransformResponse createFromParcel(Parcel in) { + return new IpSecTransformResponse(in); + } + + public IpSecTransformResponse[] newArray(int size) { + return new IpSecTransformResponse[size]; + } + }; +} diff --git a/core/java/android/net/IpSecUdpEncapResponse.aidl b/core/java/android/net/IpSecUdpEncapResponse.aidl new file mode 100644 index 0000000000..5e451f3651 --- /dev/null +++ b/core/java/android/net/IpSecUdpEncapResponse.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable IpSecUdpEncapResponse; diff --git a/core/java/android/net/IpSecUdpEncapResponse.java b/core/java/android/net/IpSecUdpEncapResponse.java new file mode 100644 index 0000000000..4679267cf9 --- /dev/null +++ b/core/java/android/net/IpSecUdpEncapResponse.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.os.Parcel; +import android.os.ParcelFileDescriptor; +import android.os.Parcelable; +import java.io.FileDescriptor; +import java.io.IOException; + +/** + * This class is used to return a UDP Socket and corresponding status from the IpSecService to an + * IpSecManager.UdpEncapsulationSocket. + * + * @hide + */ +public final class IpSecUdpEncapResponse implements Parcelable { + private static final String TAG = "IpSecUdpEncapResponse"; + + public final int resourceId; + public final int port; + public final int status; + // There is a weird asymmetry with FileDescriptor: you can write a FileDescriptor + // but you read a ParcelFileDescriptor. To circumvent this, when we receive a FD + // from the user, we immediately create a ParcelFileDescriptor DUP, which we invalidate + // on writeParcel() by setting the flag to do close-on-write. + // TODO: tests to ensure this doesn't leak + public final ParcelFileDescriptor fileDescriptor; + + // Parcelable Methods + + @Override + public int describeContents() { + return (fileDescriptor != null) ? Parcelable.CONTENTS_FILE_DESCRIPTOR : 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(status); + out.writeInt(resourceId); + out.writeInt(port); + out.writeParcelable(fileDescriptor, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + } + + public IpSecUdpEncapResponse(int inStatus) { + if (inStatus == IpSecManager.Status.OK) { + throw new IllegalArgumentException("Valid status implies other args must be provided"); + } + status = inStatus; + resourceId = IpSecManager.INVALID_RESOURCE_ID; + port = -1; + fileDescriptor = null; // yes I know it's redundant, but readability + } + + public IpSecUdpEncapResponse(int inStatus, int inResourceId, int inPort, FileDescriptor inFd) + throws IOException { + if (inStatus == IpSecManager.Status.OK && inFd == null) { + throw new IllegalArgumentException("Valid status implies FD must be non-null"); + } + status = inStatus; + resourceId = inResourceId; + port = inPort; + fileDescriptor = (status == IpSecManager.Status.OK) ? ParcelFileDescriptor.dup(inFd) : null; + } + + private IpSecUdpEncapResponse(Parcel in) { + status = in.readInt(); + resourceId = in.readInt(); + port = in.readInt(); + fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecUdpEncapResponse createFromParcel(Parcel in) { + return new IpSecUdpEncapResponse(in); + } + + public IpSecUdpEncapResponse[] newArray(int size) { + return new IpSecUdpEncapResponse[size]; + } + }; +} diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a7ce95ba0c..ec275cc6f7 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -18,9 +18,10 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static android.net.IpSecManager.KEY_RESOURCE_ID; -import static android.net.IpSecManager.KEY_SPI; -import static android.net.IpSecManager.KEY_STATUS; +import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.IPPROTO_UDP; +import static android.system.OsConstants.SOCK_DGRAM; +import static com.android.internal.util.Preconditions.checkNotNull; import android.content.Context; import android.net.IIpSecService; @@ -28,47 +29,92 @@ import android.net.INetd; import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; +import android.net.IpSecSpiResponse; import android.net.IpSecTransform; +import android.net.IpSecTransformResponse; +import android.net.IpSecUdpEncapResponse; import android.net.util.NetdService; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.system.Os; +import android.system.OsConstants; import android.util.Log; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import java.io.FileDescriptor; +import java.io.IOException; import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; import java.util.concurrent.atomic.AtomicInteger; +import libcore.io.IoUtils; /** @hide */ public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); + private static final String NETD_SERVICE_NAME = "netd"; private static final int[] DIRECTIONS = new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; - /** Binder context for this service */ + private static final int NETD_FETCH_TIMEOUT = 5000; //ms + private static final int MAX_PORT_BIND_ATTEMPTS = 10; + private static final InetAddress INADDR_ANY; + + static { + try { + INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); + } catch (UnknownHostException e) { + throw new RuntimeException(e); + } + } + + static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved + static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer + + /* Binder context for this service */ private final Context mContext; - private Object mLock = new Object(); + /** Should be a never-repeating global ID for resources */ + private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); - private static final int NETD_FETCH_TIMEOUT = 5000; //ms + @GuardedBy("this") + private final ManagedResourceArray mSpiRecords = new ManagedResourceArray<>(); - private AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); + @GuardedBy("this") + private final ManagedResourceArray mTransformRecords = + new ManagedResourceArray<>(); + @GuardedBy("this") + private final ManagedResourceArray mUdpSocketRecords = + new ManagedResourceArray<>(); + + /** + * The ManagedResource class provides a facility to cleanly and reliably release system + * resources. It relies on two things: an IBinder that allows ManagedResource to automatically + * clean up in the event that the Binder dies and a user-provided resourceId that should + * uniquely identify the managed resource. To use this class, the user should implement the + * releaseResources() method that is responsible for releasing system resources when invoked. + */ private abstract class ManagedResource implements IBinder.DeathRecipient { final int pid; final int uid; private IBinder mBinder; + protected int mResourceId; - ManagedResource(IBinder binder) { + private AtomicInteger mReferenceCount = new AtomicInteger(0); + + ManagedResource(int resourceId, IBinder binder) { super(); mBinder = binder; + mResourceId = resourceId; pid = Binder.getCallingPid(); uid = Binder.getCallingUid(); @@ -79,21 +125,53 @@ public class IpSecService extends IIpSecService.Stub { } } + public void addReference() { + mReferenceCount.incrementAndGet(); + } + + public void removeReference() { + if (mReferenceCount.decrementAndGet() < 0) { + Log.wtf(TAG, "Programming error: negative reference count"); + } + } + + public boolean isReferenced() { + return (mReferenceCount.get() > 0); + } + + public void checkOwnerOrSystemAndThrow() { + if (uid != Binder.getCallingUid() + && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { + throw new SecurityException("Only the owner may access managed resources!"); + } + } + /** * When this record is no longer needed for managing system resources this function should - * unlink all references held by the record to allow efficient garbage collection. + * clean up all system resources and nullify the record. This function shall perform all + * necessary cleanup of the resources managed by this record. + * + *

            NOTE: this function verifies ownership before allowing resources to be freed. */ - public final void release() { - //Release all the underlying system resources first - releaseResources(); + public final void release() throws RemoteException { + synchronized (IpSecService.this) { + if (isReferenced()) { + throw new IllegalStateException( + "Cannot release a resource that has active references!"); + } - if (mBinder != null) { - mBinder.unlinkToDeath(this, 0); + if (mResourceId == INVALID_RESOURCE_ID) { + return; + } + + releaseResources(); + if (mBinder != null) { + mBinder.unlinkToDeath(this, 0); + } + mBinder = null; + + mResourceId = INVALID_RESOURCE_ID; } - mBinder = null; - - //remove this record so that it can be cleaned up - nullifyRecord(); } /** @@ -102,41 +180,85 @@ public class IpSecService extends IIpSecService.Stub { * collection */ public final void binderDied() { - release(); + try { + release(); + } catch (Exception e) { + Log.e(TAG, "Failed to release resource: " + e); + } } - /** - * Implement this method to release all object references contained in the subclass to allow - * efficient garbage collection of the record. This should remove any references to the - * record from all other locations that hold a reference as the record is no longer valid. - */ - protected abstract void nullifyRecord(); - /** * Implement this method to release all system resources that are being protected by this * record. Once the resources are released, the record should be invalidated and no longer - * used by calling releaseRecord() + * used by calling release(). This should NEVER be called directly. + * + *

            Calls to this are always guarded by IpSecService#this */ - protected abstract void releaseResources(); + protected abstract void releaseResources() throws RemoteException; }; - private final class TransformRecord extends ManagedResource { - private IpSecConfig mConfig; - private int mResourceId; + /** + * Minimal wrapper around SparseArray that performs ownership + * validation on element accesses. + */ + private class ManagedResourceArray { + SparseArray mArray = new SparseArray<>(); - TransformRecord(IpSecConfig config, int resourceId, IBinder binder) { - super(binder); + T get(int key) { + T val = mArray.get(key); + val.checkOwnerOrSystemAndThrow(); + return val; + } + + void put(int key, T obj) { + checkNotNull(obj, "Null resources cannot be added"); + mArray.put(key, obj); + } + + void remove(int key) { + mArray.remove(key); + } + } + + private final class TransformRecord extends ManagedResource { + private final IpSecConfig mConfig; + private final SpiRecord[] mSpis; + private final UdpSocketRecord mSocket; + + TransformRecord( + int resourceId, + IBinder binder, + IpSecConfig config, + SpiRecord[] spis, + UdpSocketRecord socket) { + super(resourceId, binder); mConfig = config; - mResourceId = resourceId; + mSpis = spis; + mSocket = socket; + + for (int direction : DIRECTIONS) { + mSpis[direction].addReference(); + mSpis[direction].setOwnedByTransform(); + } + + if (mSocket != null) { + mSocket.addReference(); + } } public IpSecConfig getConfig() { return mConfig; } + public SpiRecord getSpiRecord(int direction) { + return mSpis[direction]; + } + + /** always guarded by IpSecService#this */ @Override protected void releaseResources() { for (int direction : DIRECTIONS) { + int spi = mSpis[direction].getSpi(); try { getNetdInstance() .ipSecDeleteSecurityAssociation( @@ -148,19 +270,21 @@ public class IpSecService extends IIpSecService.Stub { (mConfig.getRemoteAddress() != null) ? mConfig.getRemoteAddress().getHostAddress() : "", - mConfig.getSpi(direction)); + spi); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } catch (RemoteException e) { Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); } } - } - @Override - protected void nullifyRecord() { - mConfig = null; - mResourceId = INVALID_RESOURCE_ID; + for (int direction : DIRECTIONS) { + mSpis[direction].removeReference(); + } + + if (mSocket != null) { + mSocket.removeReference(); + } } } @@ -168,27 +292,37 @@ public class IpSecService extends IIpSecService.Stub { private final int mDirection; private final String mLocalAddress; private final String mRemoteAddress; - private final IBinder mBinder; private int mSpi; - private int mResourceId; + + private boolean mOwnedByTransform = false; SpiRecord( int resourceId, + IBinder binder, int direction, String localAddress, String remoteAddress, - int spi, - IBinder binder) { - super(binder); - mResourceId = resourceId; + int spi) { + super(resourceId, binder); mDirection = direction; mLocalAddress = localAddress; mRemoteAddress = remoteAddress; mSpi = spi; - mBinder = binder; } + /** always guarded by IpSecService#this */ + @Override protected void releaseResources() { + if (mOwnedByTransform) { + Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); + // Because SPIs are "handed off" to transform, objects, they should never be + // freed from the SpiRecord once used in a transform. (They refer to the same SA, + // thus ownership and responsibility for freeing these resources passes to the + // Transform object). Thus, we should let the user free them without penalty once + // they are applied in a Transform object. + return; + } + try { getNetdInstance() .ipSecDeleteSecurityAssociation( @@ -198,19 +332,50 @@ public class IpSecService extends IIpSecService.Stub { } catch (RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); } + + mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; } - protected void nullifyRecord() { - mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - mResourceId = INVALID_RESOURCE_ID; + public int getSpi() { + return mSpi; + } + + public void setOwnedByTransform() { + if (mOwnedByTransform) { + // Programming error + new IllegalStateException("Cannot own an SPI twice!"); + } + + mOwnedByTransform = true; } } - @GuardedBy("mSpiRecords") - private final SparseArray mSpiRecords = new SparseArray<>(); + private final class UdpSocketRecord extends ManagedResource { + private FileDescriptor mSocket; + private final int mPort; - @GuardedBy("mTransformRecords") - private final SparseArray mTransformRecords = new SparseArray<>(); + UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) { + super(resourceId, binder); + mSocket = socket; + mPort = port; + } + + /** always guarded by IpSecService#this */ + @Override + protected void releaseResources() { + Log.d(TAG, "Closing port " + mPort); + IoUtils.closeQuietly(mSocket); + mSocket = null; + } + + public int getPort() { + return mPort; + } + + public FileDescriptor getSocket() { + return mSocket; + } + } /** * Constructs a new IpSecService instance @@ -242,7 +407,7 @@ public class IpSecService extends IIpSecService.Stub { new Runnable() { @Override public void run() { - synchronized (mLock) { + synchronized (IpSecService.this) { NetdService.get(NETD_FETCH_TIMEOUT); } } @@ -258,30 +423,27 @@ public class IpSecService extends IIpSecService.Stub { return netd; } - boolean isNetdAlive() { - synchronized (mLock) { - try { - final INetd netd = getNetdInstance(); - if (netd == null) { - return false; - } - return netd.isAlive(); - } catch (RemoteException re) { + synchronized boolean isNetdAlive() { + try { + final INetd netd = getNetdInstance(); + if (netd == null) { return false; } + return netd.isAlive(); + } catch (RemoteException re) { + return false; } } @Override /** Get a new SPI and maintain the reservation in the system server */ - public Bundle reserveSecurityParameterIndex( + public synchronized IpSecSpiResponse reserveSecurityParameterIndex( int direction, String remoteAddress, int requestedSpi, IBinder binder) throws RemoteException { int resourceId = mNextResourceId.getAndIncrement(); int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; String localAddress = ""; - Bundle retBundle = new Bundle(3); try { spi = getNetdInstance() @@ -292,29 +454,78 @@ public class IpSecService extends IIpSecService.Stub { remoteAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); - retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); - retBundle.putInt(KEY_RESOURCE_ID, resourceId); - retBundle.putInt(KEY_SPI, spi); - synchronized (mSpiRecords) { - mSpiRecords.put( - resourceId, - new SpiRecord( - resourceId, direction, localAddress, remoteAddress, spi, binder)); - } + mSpiRecords.put( + resourceId, + new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi)); } catch (ServiceSpecificException e) { // TODO: Add appropriate checks when other ServiceSpecificException types are supported - retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); - retBundle.putInt(KEY_RESOURCE_ID, resourceId); - retBundle.putInt(KEY_SPI, spi); + return new IpSecSpiResponse( + IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - return retBundle; + return new IpSecSpiResponse(IpSecManager.Status.OK, resourceId, spi); + } + + /* This method should only be called from Binder threads. Do not call this from + * within the system server as it will crash the system on failure. + */ + private synchronized void releaseManagedResource( + ManagedResourceArray resArray, int resourceId, String typeName) + throws RemoteException { + // We want to non-destructively get so that we can check credentials before removing + // this from the records. + T record = resArray.get(resourceId); + + if (record == null) { + throw new IllegalArgumentException( + typeName + " " + resourceId + " is not available to be deleted"); + } + + record.release(); + resArray.remove(resourceId); } /** Release a previously allocated SPI that has been registered with the system server */ @Override - public void releaseSecurityParameterIndex(int resourceId) throws RemoteException {} + public void releaseSecurityParameterIndex(int resourceId) throws RemoteException { + releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex"); + } + + /** + * This function finds and forcibly binds to a random system port, ensuring that the port cannot + * be unbound. + * + *

            A socket cannot be un-bound from a port if it was bound to that port by number. To select + * a random open port and then bind by number, this function creates a temp socket, binds to a + * random port (specifying 0), gets that port number, and then uses is to bind the user's UDP + * Encapsulation Socket forcibly, so that it cannot be un-bound by the user with the returned + * FileHandle. + * + *

            The loop in this function handles the inherent race window between un-binding to a port + * and re-binding, during which the system could *technically* hand that port out to someone + * else. + */ + private void bindToRandomPort(FileDescriptor sockFd) throws IOException { + for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { + try { + FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + Os.bind(probeSocket, INADDR_ANY, 0); + int port = ((InetSocketAddress) Os.getsockname(probeSocket)).getPort(); + Os.close(probeSocket); + Log.v(TAG, "Binding to port " + port); + Os.bind(sockFd, INADDR_ANY, port); + return; + } catch (ErrnoException e) { + // Someone miraculously claimed the port just after we closed probeSocket. + if (e.errno == OsConstants.EADDRINUSE) { + continue; + } + throw e.rethrowAsIOException(); + } + } + throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); + } /** * Open a socket via the system server and bind it to the specified port (random if port=0). @@ -323,13 +534,47 @@ public class IpSecService extends IIpSecService.Stub { * needed. */ @Override - public Bundle openUdpEncapsulationSocket(int port, IBinder binder) throws RemoteException { - return null; + public synchronized IpSecUdpEncapResponse openUdpEncapsulationSocket(int port, IBinder binder) + throws RemoteException { + if (port != 0 && (port < FREE_PORT_MIN || port > PORT_MAX)) { + throw new IllegalArgumentException( + "Specified port number must be a valid non-reserved UDP port"); + } + int resourceId = mNextResourceId.getAndIncrement(); + FileDescriptor sockFd = null; + try { + sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + + if (port != 0) { + Log.v(TAG, "Binding to port " + port); + Os.bind(sockFd, INADDR_ANY, port); + } else { + bindToRandomPort(sockFd); + } + // This code is common to both the unspecified and specified port cases + Os.setsockoptInt( + sockFd, + OsConstants.IPPROTO_UDP, + OsConstants.UDP_ENCAP, + OsConstants.UDP_ENCAP_ESPINUDP); + + mUdpSocketRecords.put( + resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port)); + return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd); + } catch (IOException | ErrnoException e) { + IoUtils.closeQuietly(sockFd); + } + // If we make it to here, then something has gone wrong and we couldn't open a socket. + // The only reasonable condition that would cause that is resource unavailable. + return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } /** close a socket that has been been allocated by and registered with the system server */ @Override - public void closeUdpEncapsulationSocket(ParcelFileDescriptor socket) {} + public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { + + releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); + } /** * Create a transport mode transform, which represent two security associations (one in each @@ -339,13 +584,26 @@ public class IpSecService extends IIpSecService.Stub { * receive data. */ @Override - public Bundle createTransportModeTransform(IpSecConfig c, IBinder binder) - throws RemoteException { - // TODO: Basic input validation here since it's coming over the Binder + public synchronized IpSecTransformResponse createTransportModeTransform( + IpSecConfig c, IBinder binder) throws RemoteException { int resourceId = mNextResourceId.getAndIncrement(); + SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; + // TODO: Basic input validation here since it's coming over the Binder + int encapType, encapLocalPort = 0, encapRemotePort = 0; + UdpSocketRecord socketRecord = null; + encapType = c.getEncapType(); + if (encapType != IpSecTransform.ENCAP_NONE) { + socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId()); + encapLocalPort = socketRecord.getPort(); + encapRemotePort = c.getEncapRemotePort(); + } + for (int direction : DIRECTIONS) { IpSecAlgorithm auth = c.getAuthentication(direction); IpSecAlgorithm crypt = c.getEncryption(direction); + + spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); + int spi = spis[direction].getSpi(); try { int result = getNetdInstance() @@ -362,35 +620,29 @@ public class IpSecService extends IIpSecService.Stub { (c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, - c.getSpi(direction), + spi, (auth != null) ? auth.getName() : "", (auth != null) ? auth.getKey() : null, (auth != null) ? auth.getTruncationLengthBits() : 0, (crypt != null) ? crypt.getName() : "", (crypt != null) ? crypt.getKey() : null, (crypt != null) ? crypt.getTruncationLengthBits() : 0, - c.getEncapType(), - c.getEncapLocalPort(), - c.getEncapRemotePort()); - if (result != c.getSpi(direction)) { + encapType, + encapLocalPort, + encapRemotePort); + if (result != spi) { // TODO: cleanup the first SA if creation of second SA fails - Bundle retBundle = new Bundle(2); - retBundle.putInt(KEY_STATUS, IpSecManager.Status.SPI_UNAVAILABLE); - retBundle.putInt(KEY_RESOURCE_ID, INVALID_RESOURCE_ID); - return retBundle; + return new IpSecTransformResponse( + IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID); } } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } } - synchronized (mTransformRecords) { - mTransformRecords.put(resourceId, new TransformRecord(c, resourceId, binder)); - } - - Bundle retBundle = new Bundle(2); - retBundle.putInt(KEY_STATUS, IpSecManager.Status.OK); - retBundle.putInt(KEY_RESOURCE_ID, resourceId); - return retBundle; + // Both SAs were created successfully, time to construct a record and lock it away + mTransformRecords.put( + resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord)); + return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); } /** @@ -401,27 +653,7 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public void deleteTransportModeTransform(int resourceId) throws RemoteException { - synchronized (mTransformRecords) { - TransformRecord record; - // We want to non-destructively get so that we can check credentials before removing - // this from the records. - record = mTransformRecords.get(resourceId); - - if (record == null) { - throw new IllegalArgumentException( - "Transform " + resourceId + " is not available to be deleted"); - } - - if (record.pid != Binder.getCallingPid() || record.uid != Binder.getCallingUid()) { - throw new SecurityException("Only the owner of an IpSec Transform may delete it!"); - } - - // TODO: if releaseResources() throws RemoteException, we can try again to clean up on - // binder death. Need to make sure that path is actually functional. - record.releaseResources(); - mTransformRecords.remove(resourceId); - record.nullifyRecord(); - } + releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform"); } /** @@ -429,44 +661,43 @@ public class IpSecService extends IIpSecService.Stub { * association as a correspondent policy to the provided socket */ @Override - public void applyTransportModeTransform(ParcelFileDescriptor socket, int resourceId) - throws RemoteException { + public synchronized void applyTransportModeTransform( + ParcelFileDescriptor socket, int resourceId) throws RemoteException { + // Synchronize liberally here because we are using ManagedResources in this block + TransformRecord info; + // FIXME: this code should be factored out into a security check + getter + info = mTransformRecords.get(resourceId); - synchronized (mTransformRecords) { - TransformRecord info; - // FIXME: this code should be factored out into a security check + getter - info = mTransformRecords.get(resourceId); + if (info == null) { + throw new IllegalArgumentException("Transform " + resourceId + " is not active"); + } - if (info == null) { - throw new IllegalArgumentException("Transform " + resourceId + " is not active"); - } + // TODO: make this a function. + if (info.pid != getCallingPid() || info.uid != getCallingUid()) { + throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); + } - // TODO: make this a function. - if (info.pid != getCallingPid() || info.uid != getCallingUid()) { - throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); - } - - IpSecConfig c = info.getConfig(); - try { - for (int direction : DIRECTIONS) { - getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - (c.getLocalAddress() != null) - ? c.getLocalAddress().getHostAddress() - : "", - (c.getRemoteAddress() != null) - ? c.getRemoteAddress().getHostAddress() - : "", - c.getSpi(direction)); - } - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception + IpSecConfig c = info.getConfig(); + try { + for (int direction : DIRECTIONS) { + getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + info.getSpiRecord(direction).getSpi()); } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception } } + /** * Remove a transport mode transform from a socket, applying the default (empty) policy. This * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of @@ -486,7 +717,7 @@ public class IpSecService extends IIpSecService.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); - + // TODO: Add dump code to print out a log of all the resources being tracked pw.println("IpSecService Log:"); pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); From 0a47018b06e0fce8230e47b8d475ef7f7bc7f5e5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 2 Jun 2017 17:36:26 -0600 Subject: [PATCH 0393/1150] Annotate @SystemApi with required permissions. Most @SystemApi methods should be protected with system (or higher) permissions, so annotate common methods with @RequiresPermission to make automatic verification easier. Verification is really only relevant when calling into system services (where permissions checking can happen on the other side of a Binder call), so annotate managers with the new @SystemService annotation, which is now automatically documented. This is purely a docs change; no logic changes are being made. Test: make -j32 update-api && make -j32 offline-sdk-docs Bug: 62263906 Change-Id: I2554227202d84465676aa4ab0dd336b5c45fc651 --- core/java/android/app/usage/NetworkStatsManager.java | 2 ++ core/java/android/net/EthernetManager.java | 2 ++ core/java/android/net/IpSecManager.java | 7 +++---- core/java/android/net/TrafficStats.java | 3 +++ core/java/android/net/nsd/NsdManager.java | 5 ++--- 5 files changed, 12 insertions(+), 7 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 6cd4e92383..ef262e0460 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -19,6 +19,7 @@ package android.app.usage; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; +import android.annotation.SystemService; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; @@ -82,6 +83,7 @@ import android.util.Log; * the above permission, even to access an app's own data usage, and carrier-privileged apps were * not included. */ +@SystemService(Context.NETWORK_STATS_SERVICE) public class NetworkStatsManager { private static final String TAG = "NetworkStatsManager"; private static final boolean DBG = false; diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 664b7b4089..31a30968cb 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.SystemService; import android.content.Context; import android.net.IEthernetManager; import android.net.IEthernetServiceListener; @@ -31,6 +32,7 @@ import java.util.ArrayList; * * @hide */ +@SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; private static final int MSG_AVAILABILITY_CHANGED = 1000; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 114e46e54f..e3cda5e7d8 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -18,6 +18,8 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; +import android.annotation.SystemService; +import android.content.Context; import android.os.Binder; import android.os.Bundle; import android.os.ParcelFileDescriptor; @@ -34,12 +36,9 @@ import java.net.Socket; * This class contains methods for managing IPsec sessions, which will perform kernel-space * encryption and decryption of socket or Network traffic. * - *

            An IpSecManager may be obtained by calling {@link - * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link - * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} - * * @hide */ +@SystemService(Context.IPSEC_SERVICE) public final class IpSecManager { private static final String TAG = "IpSecManager"; diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index fc66395bcd..f9346165df 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; @@ -243,6 +244,7 @@ public class TrafficStats { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } @@ -255,6 +257,7 @@ public class TrafficStats { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 1dde3cad23..2d480a18d5 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -17,6 +17,7 @@ package android.net.nsd; import android.annotation.SdkConstant; +import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Handler; @@ -113,11 +114,9 @@ import com.android.internal.util.Protocol; * http://www.iana.org/form/ports-service. Existing services can be found at * http://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xml * - * Get an instance of this class by calling {@link android.content.Context#getSystemService(String) - * Context.getSystemService(Context.NSD_SERVICE)}. - * * {@see NsdServiceInfo} */ +@SystemService(Context.NSD_SERVICE) public final class NsdManager { private static final String TAG = NsdManager.class.getSimpleName(); private static final boolean DBG = false; From febebd856dac3c7f64d371c2711ae25d075f7641 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 25 May 2017 11:06:40 -0700 Subject: [PATCH 0394/1150] [P2P] Add binder to service calls Bug: 33040182 Test: unit tests, run-time behavior Change-Id: Ic383efc858bb4454d99c98ab24365c63ad3e7f54 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index 8b1cfaee81..bfdd45d9f9 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -25,8 +25,9 @@ import android.os.Messenger; */ interface IWifiP2pManager { - Messenger getMessenger(); + Messenger getMessenger(in IBinder binder); Messenger getP2pStateMachineMessenger(); + oneway void close(in IBinder binder); void setMiracastMode(int mode); void checkConfigureWifiDisplayPermission(); } From bdd5ab8874368c559048a8b51d59aa03e4095851 Mon Sep 17 00:00:00 2001 From: ludi Date: Sat, 20 May 2017 14:15:09 -0700 Subject: [PATCH 0395/1150] Remove return value of ipSecAddSecurityAssociation Bug:38350493 Test: runtest frameworks-net Change-Id: I48f8462d94e8c4e95d6766c1ce7f24b8a596b743 --- .../java/com/android/server/IpSecService.java | 55 +++++++++---------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ec275cc6f7..5350f42267 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -605,38 +605,33 @@ public class IpSecService extends IIpSecService.Stub { spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); try { - int result = - getNetdInstance() - .ipSecAddSecurityAssociation( - resourceId, - c.getMode(), - direction, - (c.getLocalAddress() != null) - ? c.getLocalAddress().getHostAddress() - : "", - (c.getRemoteAddress() != null) - ? c.getRemoteAddress().getHostAddress() - : "", - (c.getNetwork() != null) - ? c.getNetwork().getNetworkHandle() - : 0, - spi, - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : null, - (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", - (crypt != null) ? crypt.getKey() : null, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort); - if (result != spi) { - // TODO: cleanup the first SA if creation of second SA fails - return new IpSecTransformResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID); - } + getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + direction, + (c.getLocalAddress() != null) + ? c.getLocalAddress().getHostAddress() + : "", + (c.getRemoteAddress() != null) + ? c.getRemoteAddress().getHostAddress() + : "", + (c.getNetwork() != null) + ? c.getNetwork().getNetworkHandle() + : 0, + spi, + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : null, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : null, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception + return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } } // Both SAs were created successfully, time to construct a record and lock it away From 38fd65b25bf2dad8f02f1418f37d73ba69619862 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 26 Jun 2017 19:50:41 -0600 Subject: [PATCH 0396/1150] Allocate well-known tag for app store updates. This way an app store can shift blame for update-related network traffic onto the app that is being updated. Using a well-known tag makes it easy for developers to identify that they didn't explicitly request the traffic at runtime, similar to how backup/restore traffic is handled. Bug: 38282350 Test: builds, boots Change-Id: I003dd7c9615d4ab318250f1e44fa5d195ac94d23 --- core/java/android/net/TrafficStats.java | 44 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 15 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index f9346165df..19857076a0 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -109,25 +109,26 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; - /** @hide */ - public static final int TAG_SYSTEM_DHCP = 0xFFFFFF05; - /** @hide */ - public static final int TAG_SYSTEM_NTP = 0xFFFFFF06; - /** @hide */ - public static final int TAG_SYSTEM_PROBE = 0xFFFFFF07; - /** @hide */ - public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF08; - /** @hide */ - public static final int TAG_SYSTEM_GPS = 0xFFFFFF09; - /** @hide */ - public static final int TAG_SYSTEM_PAC = 0xFFFFFF0A; - /** - * Sockets that are strictly local on device; never hits network. + * Default tag value for code or resources downloaded by an app store on + * behalf of the app, such as app updates. * * @hide */ - public static final int TAG_SYSTEM_LOCAL = 0xFFFFFFAA; + public static final int TAG_SYSTEM_CODE = 0xFFFFFF05; + + /** @hide */ + public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; + /** @hide */ + public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; + /** @hide */ + public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; + /** @hide */ + public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; + /** @hide */ + public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; + /** @hide */ + public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; private static INetworkStatsService sStatsService; @@ -209,6 +210,19 @@ public class TrafficStats { setThreadStatsTag(TAG_SYSTEM_RESTORE); } + /** + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. The tag used internally is well-defined to + * distinguish all code-related traffic, such as updates performed by an app + * store. + * + * @hide + */ + @SystemApi + public static void setThreadStatsTagCode() { + setThreadStatsTag(TAG_SYSTEM_CODE); + } + /** * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. From 20d50337cb6c81bb7c83bb8441eb927438d0689a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 27 Jun 2017 11:01:36 -0600 Subject: [PATCH 0397/1150] Only require that system UIDs tag their sockets. Apps with a normal UID are typically isolated enough to not require socket tagging; we're mostly interested in tracking down internal UIDs that have lots of code sharing the same UID. Also fix up everyone doing manual string checks of Build.TYPE, since we now have first-class fields for those. Bug: 38126076 Test: builds, boots Change-Id: I3a40348196bd8459289f2b9355d9783a07f1e7dd --- core/java/android/net/NetworkIdentity.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 0775bdaaf3..acd7b56027 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -157,7 +157,7 @@ public class NetworkIdentity implements Comparable { * Scrub given IMSI on production builds. */ public static String scrubSubscriberId(String subscriberId) { - if ("eng".equals(Build.TYPE)) { + if (Build.IS_ENG) { return subscriberId; } else if (subscriberId != null) { // TODO: parse this as MCC+MNC instead of hard-coding From 5291cb6004ce632676037d23877013a89994460c Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 6 Jul 2017 16:57:51 -0700 Subject: [PATCH 0398/1150] Check ManagedResource is NonNull before Checking Owner If an invalid Resource Id is provided to the Managed Resource Array getter, we should just return null rather than asserting the owner of the resource. Bug: none Test: tbd Change-Id: I407a96e4e82e9d6bf68e89380a88d3851efe4305 --- services/core/java/com/android/server/IpSecService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ec275cc6f7..58f1c8d0dd 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -206,7 +206,11 @@ public class IpSecService extends IIpSecService.Stub { T get(int key) { T val = mArray.get(key); - val.checkOwnerOrSystemAndThrow(); + // The value should never be null unless the resource doesn't exist + // (since we do not allow null resources to be added). + if (val != null) { + val.checkOwnerOrSystemAndThrow(); + } return val; } From afb01e23170504897a609f77cc4952f0e39f7093 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Tue, 11 Jul 2017 10:25:09 -0700 Subject: [PATCH 0399/1150] IpSecService: Actually throw exception Add a missing throw. Bug: 19797138 Test: m Test: Device boots Change-Id: I6c6058ecc95a5b85da43a42bac2846c31cefc038 --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ec275cc6f7..c6fcd4bbd0 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -343,7 +343,7 @@ public class IpSecService extends IIpSecService.Stub { public void setOwnedByTransform() { if (mOwnedByTransform) { // Programming error - new IllegalStateException("Cannot own an SPI twice!"); + throw new IllegalStateException("Cannot own an SPI twice!"); } mOwnedByTransform = true; From 43f61f6b4594154c76f45b0e9d670dfa5b45385c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 26 Jun 2017 11:24:47 -0600 Subject: [PATCH 0400/1150] Unify permissions under UPDATE_DEVICE_STATS. The UPDATE_DEVICE_STATS permission has become the de-facto mechanism that platform components use to shift blame for resource usage, so it's confusing to also have a separate MODIFY_NETWORK_ACCOUNTING permission. So this change replaces MODIFY_NETWORK_ACCOUNTING with UPDATE_DEVICE_STATS. Bug: 62483389 Test: builds, boots Exempt-From-Owner-Approval: Bug 63673347 Change-Id: I872759f02327b6d531ec2338bd876890aded60ad --- .../java/com/android/server/net/NetworkStatsService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ab685ca28b..8209adeb89 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -18,7 +18,6 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; -import static android.Manifest.permission.MODIFY_NETWORK_ACCOUNTING; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; @@ -689,7 +688,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void incrementOperationCount(int uid, int tag, int operationCount) { if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.UPDATE_DEVICE_STATS, TAG); } if (operationCount < 0) { @@ -710,7 +710,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setUidForeground(int uid, boolean uidForeground) { - mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); synchronized (mStatsLock) { final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; @@ -750,7 +750,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void advisePersistThreshold(long thresholdBytes) { - mContext.enforceCallingOrSelfPermission(MODIFY_NETWORK_ACCOUNTING, TAG); + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); assertBandwidthControlEnabled(); // clamp threshold into safe range From 12accd0d1b5e6ba21524e48ca2c505b8993e7a9d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 17 Jul 2017 14:01:53 -0700 Subject: [PATCH 0401/1150] Launch NetD in a different thread Calling run() launches in the current thread; we want to call start() to launch in a separate thread to unblock system initialization. Bug: none Test: compilation Change-Id: Ia85059100add6a44a5e3262500b00ba8ca21e125 --- .../java/com/android/server/IpSecService.java | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ec275cc6f7..bd3a8509f7 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -402,17 +402,14 @@ public class IpSecService extends IIpSecService.Stub { private void connectNativeNetdService() { // Avoid blocking the system server to do this - Thread t = - new Thread( - new Runnable() { - @Override - public void run() { - synchronized (IpSecService.this) { - NetdService.get(NETD_FETCH_TIMEOUT); - } - } - }); - t.run(); + new Thread() { + @Override + public void run() { + synchronized (IpSecService.this) { + NetdService.get(NETD_FETCH_TIMEOUT); + } + } + }.start(); } INetd getNetdInstance() throws RemoteException { From 881296fa453473f798c63d491e8a1b4ef6910bb3 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 19 Jul 2017 09:50:45 -0700 Subject: [PATCH 0402/1150] frameworks/base: use proper nativehelper headers libnativehelper exports headers under nativehelper. These were available before incorrectly as global headers in order to give access to jni.h. Test: modules using frameworks/base find headers Bug: 63762847 Change-Id: I0f9f231acdebe460f279135462f43d3e32eff64d --- core/jni/android_net_TrafficStats.cpp | 2 +- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp index 7b7d0cf498..d0c237da07 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/core/jni/android_net_TrafficStats.cpp @@ -25,7 +25,7 @@ #include "core_jni_helpers.h" #include -#include +#include #include #include diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 4a2b88142e..0cb6935990 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -24,9 +24,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include #include From 5e623eaa028867c42d3f886ec09a104171b4f6e9 Mon Sep 17 00:00:00 2001 From: ludi Date: Fri, 12 May 2017 09:15:00 -0700 Subject: [PATCH 0403/1150] Add unit test for IpSecService Test: runtest frameworks-net Bug:38259578 Change-Id: I4a049d5fdec79e36692e3b12306bd0758c19ad75 --- core/java/android/net/IpSecTransform.java | 10 +++ .../java/com/android/server/IpSecService.java | 63 +++++++++++++------ 2 files changed, 53 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index e65f534f3d..8e3a612970 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -26,6 +26,7 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.IOException; @@ -487,5 +488,14 @@ public final class IpSecTransform implements AutoCloseable { mContext = context; mConfig = new IpSecConfig(); } + + /** + * Return an {@link IpSecConfig} object for testing purposes. + * @hide + */ + @VisibleForTesting + public IpSecConfig getIpSecConfig() { + return mConfig; + } } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ac5da9361c..f72cbc9d68 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -46,6 +46,7 @@ import android.util.Log; import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -64,7 +65,7 @@ public class IpSecService extends IIpSecService.Stub { private static final int[] DIRECTIONS = new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; - private static final int NETD_FETCH_TIMEOUT = 5000; //ms + private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int MAX_PORT_BIND_ATTEMPTS = 10; private static final InetAddress INADDR_ANY; @@ -96,6 +97,24 @@ public class IpSecService extends IIpSecService.Stub { private final ManagedResourceArray mUdpSocketRecords = new ManagedResourceArray<>(); + interface IpSecServiceConfiguration { + INetd getNetdInstance() throws RemoteException; + + static IpSecServiceConfiguration GETSRVINSTANCE = + new IpSecServiceConfiguration() { + @Override + public INetd getNetdInstance() throws RemoteException { + final INetd netd = NetdService.getInstance(); + if (netd == null) { + throw new RemoteException("Failed to Get Netd Instance"); + } + return netd; + } + }; + } + + private final IpSecServiceConfiguration mSrvConfig; + /** * The ManagedResource class provides a facility to cleanly and reliably release system * resources. It relies on two things: an IBinder that allows ManagedResource to automatically @@ -198,8 +217,7 @@ public class IpSecService extends IIpSecService.Stub { }; /** - * Minimal wrapper around SparseArray that performs ownership - * validation on element accesses. + * Minimal wrapper around SparseArray that performs ownership validation on element accesses. */ private class ManagedResourceArray { SparseArray mArray = new SparseArray<>(); @@ -264,7 +282,8 @@ public class IpSecService extends IIpSecService.Stub { for (int direction : DIRECTIONS) { int spi = mSpis[direction].getSpi(); try { - getNetdInstance() + mSrvConfig + .getNetdInstance() .ipSecDeleteSecurityAssociation( mResourceId, direction, @@ -328,7 +347,8 @@ public class IpSecService extends IIpSecService.Stub { } try { - getNetdInstance() + mSrvConfig + .getNetdInstance() .ipSecDeleteSecurityAssociation( mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); } catch (ServiceSpecificException e) { @@ -387,7 +407,7 @@ public class IpSecService extends IIpSecService.Stub { * @param context Binder context for this service */ private IpSecService(Context context) { - mContext = context; + this(context, IpSecServiceConfiguration.GETSRVINSTANCE); } static IpSecService create(Context context) throws InterruptedException { @@ -396,6 +416,13 @@ public class IpSecService extends IIpSecService.Stub { return service; } + /** @hide */ + @VisibleForTesting + public IpSecService(Context context, IpSecServiceConfiguration config) { + mContext = context; + mSrvConfig = config; + } + public void systemReady() { if (isNetdAlive()) { Slog.d(TAG, "IpSecService is ready"); @@ -410,23 +437,15 @@ public class IpSecService extends IIpSecService.Stub { @Override public void run() { synchronized (IpSecService.this) { - NetdService.get(NETD_FETCH_TIMEOUT); + NetdService.get(NETD_FETCH_TIMEOUT_MS); } } }.start(); } - INetd getNetdInstance() throws RemoteException { - final INetd netd = NetdService.getInstance(); - if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance"); - } - return netd; - } - synchronized boolean isNetdAlive() { try { - final INetd netd = getNetdInstance(); + final INetd netd = mSrvConfig.getNetdInstance(); if (netd == null) { return false; } @@ -447,7 +466,8 @@ public class IpSecService extends IIpSecService.Stub { String localAddress = ""; try { spi = - getNetdInstance() + mSrvConfig + .getNetdInstance() .ipSecAllocateSpi( resourceId, direction, @@ -606,7 +626,7 @@ public class IpSecService extends IIpSecService.Stub { spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); try { - getNetdInstance() + mSrvConfig.getNetdInstance() .ipSecAddSecurityAssociation( resourceId, c.getMode(), @@ -676,7 +696,8 @@ public class IpSecService extends IIpSecService.Stub { IpSecConfig c = info.getConfig(); try { for (int direction : DIRECTIONS) { - getNetdInstance() + mSrvConfig + .getNetdInstance() .ipSecApplyTransportModeTransform( socket.getFileDescriptor(), resourceId, @@ -704,7 +725,9 @@ public class IpSecService extends IIpSecService.Stub { public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) throws RemoteException { try { - getNetdInstance().ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); + mSrvConfig + .getNetdInstance() + .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } From 89194d6e459c382aea2c2e0f1839d343463f4cfd Mon Sep 17 00:00:00 2001 From: ludi Date: Mon, 22 May 2017 10:52:23 -0700 Subject: [PATCH 0404/1150] Add dump info to IpSecService Bug:38350824 Test: runtest frameworks-net Change-Id: Ifa11d55e9d337016ad865baada627db3aa8c2db3 --- core/java/android/net/IpSecAlgorithm.java | 15 ++++ core/java/android/net/IpSecConfig.java | 44 +++++++++- core/java/android/net/IpSecTransform.java | 4 +- .../java/com/android/server/IpSecService.java | 84 ++++++++++++++++++- 4 files changed, 141 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 48b095d9b7..5ae3400361 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -16,8 +16,10 @@ package android.net; import android.annotation.StringDef; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -182,4 +184,17 @@ public final class IpSecAlgorithm implements Parcelable { return false; } } + + @Override + public String toString() { + return new StringBuilder() + .append("{mName=") + .append(mName) + .append(", mKey=") + .append(Build.IS_DEBUGGABLE ? HexDump.toHexString(mKey) : "") + .append(", mTruncLenBits=") + .append(mTruncLenBits) + .append("}") + .toString(); + } }; diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 8b80f2ba50..5a5c740c7a 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -47,9 +47,22 @@ public final class IpSecConfig implements Parcelable { // Authentication Algorithm IpSecAlgorithm authentication; + + @Override + public String toString() { + return new StringBuilder() + .append("{spiResourceId=") + .append(spiResourceId) + .append(", encryption=") + .append(encryption) + .append(", authentication=") + .append(authentication) + .append("}") + .toString(); + } } - Flow[] flow = new Flow[] {new Flow(), new Flow()}; + final Flow[] flow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE @@ -166,6 +179,35 @@ public final class IpSecConfig implements Parcelable { encapRemotePort = in.readInt(); } + @Override + public String toString() { + StringBuilder strBuilder = new StringBuilder(); + strBuilder + .append("{mode=") + .append(mode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") + .append(", localAddress=") + .append(localAddress) + .append(", remoteAddress=") + .append(remoteAddress) + .append(", network=") + .append(network) + .append(", encapType=") + .append(encapType) + .append(", encapLocalPortResourceId=") + .append(encapLocalPortResourceId) + .append(", encapRemotePort=") + .append(encapRemotePort) + .append(", nattKeepaliveInterval=") + .append(nattKeepaliveInterval) + .append(", flow[OUT]=") + .append(flow[IpSecTransform.DIRECTION_OUT]) + .append(", flow[IN]=") + .append(flow[IpSecTransform.DIRECTION_IN]) + .append("}"); + + return strBuilder.toString(); + } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecConfig createFromParcel(Parcel in) { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 8e3a612970..cfbac58bbd 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -67,10 +67,10 @@ public final class IpSecTransform implements AutoCloseable { public @interface TransformDirection {} /** @hide */ - private static final int MODE_TUNNEL = 0; + public static final int MODE_TUNNEL = 0; /** @hide */ - private static final int MODE_TRANSPORT = 1; + public static final int MODE_TRANSPORT = 1; /** @hide */ public static final int ENCAP_NONE = 0; diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index f72cbc9d68..3fec6ad8fa 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -214,6 +214,21 @@ public class IpSecService extends IIpSecService.Stub { *

            Calls to this are always guarded by IpSecService#this */ protected abstract void releaseResources() throws RemoteException; + + @Override + public String toString() { + return new StringBuilder() + .append("{mResourceId=") + .append(mResourceId) + .append(", pid=") + .append(pid) + .append(", uid=") + .append(uid) + .append(", mReferenceCount=") + .append(mReferenceCount.get()) + .append("}") + .toString(); + } }; /** @@ -240,6 +255,11 @@ public class IpSecService extends IIpSecService.Stub { void remove(int key) { mArray.remove(key); } + + @Override + public String toString() { + return mArray.toString(); + } } private final class TransformRecord extends ManagedResource { @@ -309,6 +329,24 @@ public class IpSecService extends IIpSecService.Stub { mSocket.removeReference(); } } + + @Override + public String toString() { + StringBuilder strBuilder = new StringBuilder(); + strBuilder + .append("{super=") + .append(super.toString()) + .append(", mSocket=") + .append(mSocket) + .append(", mSpis[OUT].mResourceId=") + .append(mSpis[IpSecTransform.DIRECTION_OUT].mResourceId) + .append(", mSpis[IN].mResourceId=") + .append(mSpis[IpSecTransform.DIRECTION_IN].mResourceId) + .append(", mConfig=") + .append(mConfig) + .append("}"); + return strBuilder.toString(); + } } private final class SpiRecord extends ManagedResource { @@ -372,6 +410,26 @@ public class IpSecService extends IIpSecService.Stub { mOwnedByTransform = true; } + + @Override + public String toString() { + StringBuilder strBuilder = new StringBuilder(); + strBuilder + .append("{super=") + .append(super.toString()) + .append(", mSpi=") + .append(mSpi) + .append(", mDirection=") + .append(mDirection) + .append(", mLocalAddress=") + .append(mLocalAddress) + .append(", mRemoteAddress=") + .append(mRemoteAddress) + .append(", mOwnedByTransform=") + .append(mOwnedByTransform) + .append("}"); + return strBuilder.toString(); + } } private final class UdpSocketRecord extends ManagedResource { @@ -399,6 +457,19 @@ public class IpSecService extends IIpSecService.Stub { public FileDescriptor getSocket() { return mSocket; } + + @Override + public String toString() { + return new StringBuilder() + .append("{super=") + .append(super.toString()) + .append(", mSocket=") + .append(mSocket) + .append(", mPort=") + .append(mPort) + .append("}") + .toString(); + } } /** @@ -734,11 +805,18 @@ public class IpSecService extends IIpSecService.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); - // TODO: Add dump code to print out a log of all the resources being tracked - pw.println("IpSecService Log:"); + + pw.println("IpSecService dump:"); pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); + + pw.println("mTransformRecords:"); + pw.println(mTransformRecords); + pw.println("mUdpSocketRecords:"); + pw.println(mUdpSocketRecords); + pw.println("mSpiRecords:"); + pw.println(mSpiRecords); } } From 43ea1e553296f86423f2cf885f50fb507a745df8 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 2 May 2017 13:36:28 +0900 Subject: [PATCH 0405/1150] NsdManager: remove duplicated argument validation This patch simplifies argument validation in NsdManager public api and regroup duplicated validation into common methods. This makes stack traces more actionable as now specific errors will cause the api to throw exception from specific methods, whereas before IllegalArgumentException would be thrown from inside the same api method for different reasons. This patch also includes a couple of other small cleanups. Test: $ runtest -x frameworks/base/tests/net/../NsdManagerTest.java Bug: 35362108 Bug: 37013369 Bug: 62044295 Bug: 63826516 Merged-In: Iaad13e13976e9bf8f508d7188f823f8184ac414b (cherry pick from commit f2c64f87259679c44ef151b08cccab43ca5d4342) Change-Id: I5e6a1ecc6b98069ef0089bbceecf73f7692df227 --- core/java/android/net/nsd/NsdManager.java | 176 +++++++++------------- 1 file changed, 73 insertions(+), 103 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index ace3748664..1e41eea925 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,10 @@ package android.net.nsd; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkStringNotEmpty; + import android.annotation.SdkConstant; import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; @@ -240,12 +244,12 @@ public final class NsdManager { return name; } + private static int FIRST_LISTENER_KEY = 1; + private final INsdManager mService; private final Context mContext; - private static final int INVALID_LISTENER_KEY = 0; - private static final int BUSY_LISTENER_KEY = -1; - private int mListenerKey = 1; + private int mListenerKey = FIRST_LISTENER_KEY; private final SparseArray mListenerMap = new SparseArray(); private final SparseArray mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); @@ -311,7 +315,6 @@ public final class NsdManager { public void onServiceFound(NsdServiceInfo serviceInfo); public void onServiceLost(NsdServiceInfo serviceInfo); - } /** Interface for callback invocation for service registration */ @@ -342,8 +345,9 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - if (DBG) Log.d(TAG, "received " + nameOf(message.what)); - switch (message.what) { + final int what = message.what; + final int key = message.arg2; + switch (what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); return; @@ -356,19 +360,26 @@ public final class NsdManager { default: break; } - Object listener = getListener(message.arg2); + final Object listener; + final NsdServiceInfo ns; + synchronized (mMapLock) { + listener = mListenerMap.get(key); + ns = mServiceMap.get(key); + } if (listener == null) { Log.d(TAG, "Stale key " + message.arg2); return; } - NsdServiceInfo ns = getNsdService(message.arg2); - switch (message.what) { + if (DBG) { + Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); + } + switch (what) { case DISCOVER_SERVICES_STARTED: String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); break; case DISCOVER_SERVICES_FAILED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; @@ -381,16 +392,16 @@ public final class NsdManager { case STOP_DISCOVERY_FAILED: // TODO: failure to stop discovery should be internal and retried internally, as // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: @@ -398,7 +409,7 @@ public final class NsdManager { (NsdServiceInfo) message.obj); break; case UNREGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: @@ -408,11 +419,11 @@ public final class NsdManager { ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); break; default: @@ -422,40 +433,27 @@ public final class NsdManager { } } - // if the listener is already in the map, reject it. Otherwise, add it and - // return its key. + private int nextListenerKey() { + // Ensure mListenerKey >= FIRST_LISTENER_KEY; + mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); + return mListenerKey; + } + + // Assert that the listener is not in the map, then add it and returns its key private int putListener(Object listener, NsdServiceInfo s) { - if (listener == null) return INVALID_LISTENER_KEY; - int key; + checkListener(listener); + final int key; synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return BUSY_LISTENER_KEY; - } - do { - key = mListenerKey++; - } while (key == INVALID_LISTENER_KEY); + checkArgument(valueIndex == -1, "listener already in use"); + key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); } return key; } - private Object getListener(int key) { - if (key == INVALID_LISTENER_KEY) return null; - synchronized (mMapLock) { - return mListenerMap.get(key); - } - } - - private NsdServiceInfo getNsdService(int key) { - synchronized (mMapLock) { - return mServiceMap.get(key); - } - } - private void removeListener(int key) { - if (key == INVALID_LISTENER_KEY) return; synchronized (mMapLock) { mListenerMap.remove(key); mServiceMap.remove(key); @@ -463,16 +461,15 @@ public final class NsdManager { } private int getListenerKey(Object listener) { + checkListener(listener); synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return mListenerMap.keyAt(valueIndex); - } + checkArgument(valueIndex != -1, "listener not registered"); + return mListenerMap.keyAt(valueIndex); } - return INVALID_LISTENER_KEY; } - private String getNsdServiceInfoType(NsdServiceInfo s) { + private static String getNsdServiceInfoType(NsdServiceInfo s) { if (s == null) return "?"; return s.getServiceType(); } @@ -482,7 +479,9 @@ public final class NsdManager { */ private void init() { final Messenger messenger = getMessenger(); - if (messenger == null) throw new RuntimeException("Failed to initialize"); + if (messenger == null) { + fatal("Failed to obtain service Messenger"); + } HandlerThread t = new HandlerThread("NsdManager"); t.start(); mHandler = new ServiceHandler(t.getLooper()); @@ -490,10 +489,15 @@ public final class NsdManager { try { mConnected.await(); } catch (InterruptedException e) { - Log.e(TAG, "interrupted wait at init"); + fatal("Interrupted wait at init"); } } + private static void fatal(String msg) { + Log.e(TAG, msg); + throw new RuntimeException(msg); + } + /** * Register a service to be discovered by other services. * @@ -513,23 +517,10 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkArgument(serviceInfo.getPort() > 0, "Invalid port number"); + checkServiceInfo(serviceInfo); + checkProtocol(protocolType); int key = putListener(listener, serviceInfo); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); } @@ -548,12 +539,6 @@ public final class NsdManager { */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("listener not registered"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); } @@ -586,25 +571,13 @@ public final class NsdManager { * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkStringNotEmpty(serviceType, "Service type cannot be empty"); + checkProtocol(protocolType); NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); int key = putListener(listener, s); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); } @@ -626,12 +599,6 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("service discovery not active on listener"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); } @@ -645,19 +612,8 @@ public final class NsdManager { * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - + checkServiceInfo(serviceInfo); int key = putListener(listener, serviceInfo); - - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); } @@ -671,10 +627,10 @@ public final class NsdManager { } /** - * Get a reference to NetworkService handler. This is used to establish + * Get a reference to NsdService handler. This is used to establish * an AsyncChannel communication with the service * - * @return Messenger pointing to the NetworkService handler + * @return Messenger pointing to the NsdService handler */ private Messenger getMessenger() { try { @@ -683,4 +639,18 @@ public final class NsdManager { throw e.rethrowFromSystemServer(); } } + + private static void checkListener(Object listener) { + checkNotNull(listener, "listener cannot be null"); + } + + private static void checkProtocol(int protocolType) { + checkArgument(protocolType == PROTOCOL_DNS_SD, "Unsupported protocol"); + } + + private static void checkServiceInfo(NsdServiceInfo serviceInfo) { + checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); + checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty"); + checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); + } } From a00d4b0bf4a200acc47204daf24852af5be7333c Mon Sep 17 00:00:00 2001 From: Tetsutoki Shiozawa Date: Thu, 13 Jul 2017 15:37:40 +0900 Subject: [PATCH 0406/1150] Abort connecting to native daemon during shutdown Symptom: System_server crashed due to unsolved "netd" service. Root cause: Init intentionally killed services when shutdown was triggered. NativeDaemonConnector unnecessarily tried to reconnect the killed daemon and NetworkManagemantService got a callback of connection. Finally, NetworkManagemantService failed to get netd service and it crashed with NPE. Solution: Do not retry connecting to the target native daemon when the device is in the middle of shutdown. Bug: 64237349 Change-Id: I2514cdc47b3eea785b5ffe5bd8bb27609bcc1726 --- .../java/com/android/server/NativeDaemonConnector.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index f5f7732141..b5a8332375 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -24,11 +24,13 @@ import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; +import android.os.SystemProperties; import android.util.LocalLog; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.server.power.ShutdownThread; import com.google.android.collect.Lists; import java.io.FileDescriptor; @@ -136,6 +138,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo listenToSocket(); } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); + String shutdownAct = SystemProperties.get( + ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); + if (shutdownAct != null && shutdownAct.length() > 0) { + // The device is in middle of shutdown. + break; + } SystemClock.sleep(5000); } } From a7e08f91fde1a0b884bfb2b3049bdba1246089f3 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Tue, 2 May 2017 13:36:28 +0900 Subject: [PATCH 0407/1150] NsdManager: remove duplicated argument validation This patch simplifies argument validation in NsdManager public api and regroup duplicated validation into common methods. This makes stack traces more actionable as now specific errors will cause the api to throw exception from specific methods, whereas before IllegalArgumentException would be thrown from inside the same api method for different reasons. This patch also includes a couple of other small cleanups. Test: $ runtest -x frameworks/base/tests/net/../NsdManagerTest.java Bug: 37013369 (cherry picked from commit f2c64f87259679c44ef151b08cccab43ca5d4342) Change-Id: Icf047532aa551fbe0a70721cfb95507eaa84d51e --- core/java/android/net/nsd/NsdManager.java | 176 +++++++++------------- 1 file changed, 73 insertions(+), 103 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index ace3748664..1e41eea925 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -16,6 +16,10 @@ package android.net.nsd; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkStringNotEmpty; + import android.annotation.SdkConstant; import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; @@ -240,12 +244,12 @@ public final class NsdManager { return name; } + private static int FIRST_LISTENER_KEY = 1; + private final INsdManager mService; private final Context mContext; - private static final int INVALID_LISTENER_KEY = 0; - private static final int BUSY_LISTENER_KEY = -1; - private int mListenerKey = 1; + private int mListenerKey = FIRST_LISTENER_KEY; private final SparseArray mListenerMap = new SparseArray(); private final SparseArray mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); @@ -311,7 +315,6 @@ public final class NsdManager { public void onServiceFound(NsdServiceInfo serviceInfo); public void onServiceLost(NsdServiceInfo serviceInfo); - } /** Interface for callback invocation for service registration */ @@ -342,8 +345,9 @@ public final class NsdManager { @Override public void handleMessage(Message message) { - if (DBG) Log.d(TAG, "received " + nameOf(message.what)); - switch (message.what) { + final int what = message.what; + final int key = message.arg2; + switch (what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); return; @@ -356,19 +360,26 @@ public final class NsdManager { default: break; } - Object listener = getListener(message.arg2); + final Object listener; + final NsdServiceInfo ns; + synchronized (mMapLock) { + listener = mListenerMap.get(key); + ns = mServiceMap.get(key); + } if (listener == null) { Log.d(TAG, "Stale key " + message.arg2); return; } - NsdServiceInfo ns = getNsdService(message.arg2); - switch (message.what) { + if (DBG) { + Log.d(TAG, "received " + nameOf(what) + " for key " + key + ", service " + ns); + } + switch (what) { case DISCOVER_SERVICES_STARTED: String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); ((DiscoveryListener) listener).onDiscoveryStarted(s); break; case DISCOVER_SERVICES_FAILED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; @@ -381,16 +392,16 @@ public final class NsdManager { case STOP_DISCOVERY_FAILED: // TODO: failure to stop discovery should be internal and retried internally, as // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), message.arg1); break; case STOP_DISCOVERY_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); break; case REGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); break; case REGISTER_SERVICE_SUCCEEDED: @@ -398,7 +409,7 @@ public final class NsdManager { (NsdServiceInfo) message.obj); break; case UNREGISTER_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); break; case UNREGISTER_SERVICE_SUCCEEDED: @@ -408,11 +419,11 @@ public final class NsdManager { ((RegistrationListener) listener).onServiceUnregistered(ns); break; case RESOLVE_SERVICE_FAILED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onResolveFailed(ns, message.arg1); break; case RESOLVE_SERVICE_SUCCEEDED: - removeListener(message.arg2); + removeListener(key); ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); break; default: @@ -422,40 +433,27 @@ public final class NsdManager { } } - // if the listener is already in the map, reject it. Otherwise, add it and - // return its key. + private int nextListenerKey() { + // Ensure mListenerKey >= FIRST_LISTENER_KEY; + mListenerKey = Math.max(FIRST_LISTENER_KEY, mListenerKey + 1); + return mListenerKey; + } + + // Assert that the listener is not in the map, then add it and returns its key private int putListener(Object listener, NsdServiceInfo s) { - if (listener == null) return INVALID_LISTENER_KEY; - int key; + checkListener(listener); + final int key; synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return BUSY_LISTENER_KEY; - } - do { - key = mListenerKey++; - } while (key == INVALID_LISTENER_KEY); + checkArgument(valueIndex == -1, "listener already in use"); + key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); } return key; } - private Object getListener(int key) { - if (key == INVALID_LISTENER_KEY) return null; - synchronized (mMapLock) { - return mListenerMap.get(key); - } - } - - private NsdServiceInfo getNsdService(int key) { - synchronized (mMapLock) { - return mServiceMap.get(key); - } - } - private void removeListener(int key) { - if (key == INVALID_LISTENER_KEY) return; synchronized (mMapLock) { mListenerMap.remove(key); mServiceMap.remove(key); @@ -463,16 +461,15 @@ public final class NsdManager { } private int getListenerKey(Object listener) { + checkListener(listener); synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - if (valueIndex != -1) { - return mListenerMap.keyAt(valueIndex); - } + checkArgument(valueIndex != -1, "listener not registered"); + return mListenerMap.keyAt(valueIndex); } - return INVALID_LISTENER_KEY; } - private String getNsdServiceInfoType(NsdServiceInfo s) { + private static String getNsdServiceInfoType(NsdServiceInfo s) { if (s == null) return "?"; return s.getServiceType(); } @@ -482,7 +479,9 @@ public final class NsdManager { */ private void init() { final Messenger messenger = getMessenger(); - if (messenger == null) throw new RuntimeException("Failed to initialize"); + if (messenger == null) { + fatal("Failed to obtain service Messenger"); + } HandlerThread t = new HandlerThread("NsdManager"); t.start(); mHandler = new ServiceHandler(t.getLooper()); @@ -490,10 +489,15 @@ public final class NsdManager { try { mConnected.await(); } catch (InterruptedException e) { - Log.e(TAG, "interrupted wait at init"); + fatal("Interrupted wait at init"); } } + private static void fatal(String msg) { + Log.e(TAG, msg); + throw new RuntimeException(msg); + } + /** * Register a service to be discovered by other services. * @@ -513,23 +517,10 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (serviceInfo.getPort() <= 0) { - throw new IllegalArgumentException("Invalid port number"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkArgument(serviceInfo.getPort() > 0, "Invalid port number"); + checkServiceInfo(serviceInfo); + checkProtocol(protocolType); int key = putListener(listener, serviceInfo); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); } @@ -548,12 +539,6 @@ public final class NsdManager { */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("listener not registered"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); } @@ -586,25 +571,13 @@ public final class NsdManager { * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - if (TextUtils.isEmpty(serviceType)) { - throw new IllegalArgumentException("Service type cannot be empty"); - } - - if (protocolType != PROTOCOL_DNS_SD) { - throw new IllegalArgumentException("Unsupported protocol"); - } + checkStringNotEmpty(serviceType, "Service type cannot be empty"); + checkProtocol(protocolType); NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); int key = putListener(listener, s); - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); } @@ -626,12 +599,6 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); - if (id == INVALID_LISTENER_KEY) { - throw new IllegalArgumentException("service discovery not active on listener"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); } @@ -645,19 +612,8 @@ public final class NsdManager { * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { - if (TextUtils.isEmpty(serviceInfo.getServiceName()) || - TextUtils.isEmpty(serviceInfo.getServiceType())) { - throw new IllegalArgumentException("Service name or type cannot be empty"); - } - if (listener == null) { - throw new IllegalArgumentException("listener cannot be null"); - } - + checkServiceInfo(serviceInfo); int key = putListener(listener, serviceInfo); - - if (key == BUSY_LISTENER_KEY) { - throw new IllegalArgumentException("listener already in use"); - } mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); } @@ -671,10 +627,10 @@ public final class NsdManager { } /** - * Get a reference to NetworkService handler. This is used to establish + * Get a reference to NsdService handler. This is used to establish * an AsyncChannel communication with the service * - * @return Messenger pointing to the NetworkService handler + * @return Messenger pointing to the NsdService handler */ private Messenger getMessenger() { try { @@ -683,4 +639,18 @@ public final class NsdManager { throw e.rethrowFromSystemServer(); } } + + private static void checkListener(Object listener) { + checkNotNull(listener, "listener cannot be null"); + } + + private static void checkProtocol(int protocolType) { + checkArgument(protocolType == PROTOCOL_DNS_SD, "Unsupported protocol"); + } + + private static void checkServiceInfo(NsdServiceInfo serviceInfo) { + checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); + checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty"); + checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); + } } From ce144deb7b824a4c2fbc0d48e664267a74c61ba6 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 7 Aug 2017 15:47:35 +0900 Subject: [PATCH 0408/1150] NetworkStats: more robust subtraction for deltas This patch ensures that subtract() between two NetworkStats object will return a delta with no negative entries in all cases. When the stats delta contains some negative values, there are clamped to 0. Some logging is added when this happens. This is what's expected by NetworkStatsHistory#recordData(). Bug: 64365917 Test: runtest frameworks-net Change-Id: I16e97e73f600225f80e0ce517e80c07c6f399196 --- core/java/android/net/NetworkStats.java | 45 ++++++++++++------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 77ce65b081..be9e809738 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -672,36 +672,33 @@ public class NetworkStats implements Parcelable { entry.tag = left.tag[i]; entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; + entry.rxBytes = left.rxBytes[i]; + entry.rxPackets = left.rxPackets[i]; + entry.txBytes = left.txBytes[i]; + entry.txPackets = left.txPackets[i]; + entry.operations = left.operations[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, i); - if (j == -1) { - // newly appearing row, return entire value - entry.rxBytes = left.rxBytes[i]; - entry.rxPackets = left.rxPackets[i]; - entry.txBytes = left.txBytes[i]; - entry.txPackets = left.txPackets[i]; - entry.operations = left.operations[i]; - } else { - // existing row, subtract remote value - entry.rxBytes = left.rxBytes[i] - right.rxBytes[j]; - entry.rxPackets = left.rxPackets[i] - right.rxPackets[j]; - entry.txBytes = left.txBytes[i] - right.txBytes[j]; - entry.txPackets = left.txPackets[i] - right.txPackets[j]; - entry.operations = left.operations[i] - right.operations[j]; + if (j != -1) { + // Found matching row, subtract remote value. + entry.rxBytes -= right.rxBytes[j]; + entry.rxPackets -= right.rxPackets[j]; + entry.txBytes -= right.txBytes[j]; + entry.txPackets -= right.txPackets[j]; + entry.operations -= right.operations[j]; + } - if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 - || entry.txPackets < 0 || entry.operations < 0) { - if (observer != null) { - observer.foundNonMonotonic(left, i, right, j, cookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); + if (entry.isNegative()) { + if (observer != null) { + observer.foundNonMonotonic(left, i, right, j, cookie); } + entry.rxBytes = Math.max(entry.rxBytes, 0); + entry.rxPackets = Math.max(entry.rxPackets, 0); + entry.txBytes = Math.max(entry.txBytes, 0); + entry.txPackets = Math.max(entry.txPackets, 0); + entry.operations = Math.max(entry.operations, 0); } result.addValues(entry); From 6e4681c7e25d0658f98d6871a02a3d07a48cd60a Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 24 Apr 2017 16:16:34 -0700 Subject: [PATCH 0409/1150] Add UserQuotaTracker to IpSecService Add a small tracking object to enforce maximum quotas for SPIs, Transforms, and Encap sockets. The current quota limits are intentionally conservative with the expectation that we can relax them more easily than we can shrink them. Bug: 37688603 Test: tbd Change-Id: Iee59ac59ef9f4a7ab75a2e04f9ca72da82fc3229 --- .../java/com/android/server/IpSecService.java | 99 ++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 3fec6ad8fa..ab7daccb06 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -115,6 +115,67 @@ public class IpSecService extends IIpSecService.Stub { private final IpSecServiceConfiguration mSrvConfig; + /* Very simple counting class that looks much like a counting semaphore */ + public static class ResourceTracker { + private final int mMax; + int mCurrent; + + ResourceTracker(int max) { + mMax = max; + mCurrent = 0; + } + + synchronized boolean isAvailable() { + return (mCurrent < mMax); + } + + synchronized void take() { + if (!isAvailable()) { + Log.wtf(TAG, "Too many resources allocated!"); + } + mCurrent++; + } + + synchronized void give() { + if (mCurrent <= 0) { + Log.wtf(TAG, "We've released this resource too many times"); + } + mCurrent--; + } + } + + private static final class UserQuotaTracker { + /* Maximum number of UDP Encap Sockets that a single UID may possess */ + public static final int MAX_NUM_ENCAP_SOCKETS = 2; + + /* Maximum number of IPsec Transforms that a single UID may possess */ + public static final int MAX_NUM_TRANSFORMS = 4; + + /* Maximum number of IPsec Transforms that a single UID may possess */ + public static final int MAX_NUM_SPIS = 8; + + /* Record for one users's IpSecService-managed objects */ + public static class UserRecord { + public final ResourceTracker socket = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); + public final ResourceTracker transform = new ResourceTracker(MAX_NUM_TRANSFORMS); + public final ResourceTracker spi = new ResourceTracker(MAX_NUM_SPIS); + } + + private final SparseArray mUserRecords = new SparseArray<>(); + + /* a never-fail getter so that we can populate the list of UIDs as-needed */ + public synchronized UserRecord getUserRecord(int uid) { + UserRecord r = mUserRecords.get(uid); + if (r == null) { + r = new UserRecord(); + mUserRecords.put(uid, r); + } + return r; + } + } + + private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker(); + /** * The ManagedResource class provides a facility to cleanly and reliably release system * resources. It relies on two things: an IBinder that allows ManagedResource to automatically @@ -132,11 +193,15 @@ public class IpSecService extends IIpSecService.Stub { ManagedResource(int resourceId, IBinder binder) { super(); + if (resourceId == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); + } mBinder = binder; mResourceId = resourceId; pid = Binder.getCallingPid(); uid = Binder.getCallingUid(); + getResourceTracker().take(); try { mBinder.linkToDeath(this, 0); } catch (RemoteException e) { @@ -184,6 +249,7 @@ public class IpSecService extends IIpSecService.Stub { } releaseResources(); + getResourceTracker().give(); if (mBinder != null) { mBinder.unlinkToDeath(this, 0); } @@ -215,6 +281,9 @@ public class IpSecService extends IIpSecService.Stub { */ protected abstract void releaseResources() throws RemoteException; + /** Get the resource tracker for this resource */ + protected abstract ResourceTracker getResourceTracker(); + @Override public String toString() { return new StringBuilder() @@ -330,6 +399,10 @@ public class IpSecService extends IIpSecService.Stub { } } + protected ResourceTracker getResourceTracker() { + return mUserQuotaTracker.getUserRecord(this.uid).transform; + } + @Override public String toString() { StringBuilder strBuilder = new StringBuilder(); @@ -398,6 +471,11 @@ public class IpSecService extends IIpSecService.Stub { mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; } + @Override + protected ResourceTracker getResourceTracker() { + return mUserQuotaTracker.getUserRecord(this.uid).spi; + } + public int getSpi() { return mSpi; } @@ -450,6 +528,11 @@ public class IpSecService extends IIpSecService.Stub { mSocket = null; } + @Override + protected ResourceTracker getResourceTracker() { + return mUserQuotaTracker.getUserRecord(this.uid).socket; + } + public int getPort() { return mPort; } @@ -535,7 +618,14 @@ public class IpSecService extends IIpSecService.Stub { int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; String localAddress = ""; + try { + if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) { + return new IpSecSpiResponse( + IpSecManager.Status.RESOURCE_UNAVAILABLE, + INVALID_RESOURCE_ID, + spi); + } spi = mSrvConfig .getNetdInstance() @@ -552,7 +642,7 @@ public class IpSecService extends IIpSecService.Stub { } catch (ServiceSpecificException e) { // TODO: Add appropriate checks when other ServiceSpecificException types are supported return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, IpSecManager.INVALID_RESOURCE_ID, spi); + IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -635,6 +725,10 @@ public class IpSecService extends IIpSecService.Stub { int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { + if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).socket.isAvailable()) { + return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); + } + sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (port != 0) { @@ -679,6 +773,9 @@ public class IpSecService extends IIpSecService.Stub { public synchronized IpSecTransformResponse createTransportModeTransform( IpSecConfig c, IBinder binder) throws RemoteException { int resourceId = mNextResourceId.getAndIncrement(); + if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) { + return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); + } SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; // TODO: Basic input validation here since it's coming over the Binder int encapType, encapLocalPort = 0, encapRemotePort = 0; From 63ee528005546ffc41d68bcade5abce2cc81bad6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 11 Aug 2017 15:04:12 -0600 Subject: [PATCH 0410/1150] Rename API to match StorageStats. Since they're both measuring app code (APKs), name this API consistently with StorageStats.getAppBytes(). Bug: 64331226 Test: builds, boots Change-Id: I1b00427b619a78c043b1b5fac2d0e6406b51d454 --- core/java/android/net/TrafficStats.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 19857076a0..c339856f43 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -110,12 +110,12 @@ public class TrafficStats { public static final int TAG_SYSTEM_RESTORE = 0xFFFFFF04; /** - * Default tag value for code or resources downloaded by an app store on - * behalf of the app, such as app updates. + * Default tag value for code (typically APKs) downloaded by an app store on + * behalf of the app, such as updates. * * @hide */ - public static final int TAG_SYSTEM_CODE = 0xFFFFFF05; + public static final int TAG_SYSTEM_APP = 0xFFFFFF05; /** @hide */ public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; @@ -213,14 +213,14 @@ public class TrafficStats { /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. The tag used internally is well-defined to - * distinguish all code-related traffic, such as updates performed by an app - * store. + * distinguish all code (typically APKs) downloaded by an app store on + * behalf of the app, such as updates. * * @hide */ @SystemApi - public static void setThreadStatsTagCode() { - setThreadStatsTag(TAG_SYSTEM_CODE); + public static void setThreadStatsTagApp() { + setThreadStatsTag(TAG_SYSTEM_APP); } /** From 529fdecc4c29aa5fbdb9179f5a450fcef8d189de Mon Sep 17 00:00:00 2001 From: ludi Date: Thu, 10 Aug 2017 15:44:40 -0700 Subject: [PATCH 0411/1150] Add user quota information into the IpSecService dump Bug: 64093788 Test: runtest frameworks-net Change-Id: I6c5fc9e2db4ba57e0db4f6380a1251c4e444951b --- .../java/com/android/server/IpSecService.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ab7daccb06..305683139f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -142,6 +142,17 @@ public class IpSecService extends IIpSecService.Stub { } mCurrent--; } + + @Override + public String toString() { + return new StringBuilder() + .append("{mCurrent=") + .append(mCurrent) + .append(", mMax=") + .append(mMax) + .append("}") + .toString(); + } } private static final class UserQuotaTracker { @@ -159,6 +170,19 @@ public class IpSecService extends IIpSecService.Stub { public final ResourceTracker socket = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); public final ResourceTracker transform = new ResourceTracker(MAX_NUM_TRANSFORMS); public final ResourceTracker spi = new ResourceTracker(MAX_NUM_SPIS); + + @Override + public String toString() { + return new StringBuilder() + .append("{socket=") + .append(socket) + .append(", transform=") + .append(transform) + .append(", spi=") + .append(spi) + .append("}") + .toString(); + } } private final SparseArray mUserRecords = new SparseArray<>(); @@ -172,6 +196,11 @@ public class IpSecService extends IIpSecService.Stub { } return r; } + + @Override + public String toString() { + return mUserRecords.toString(); + } } private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker(); @@ -909,6 +938,8 @@ public class IpSecService extends IIpSecService.Stub { pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); + pw.println("mUserQuotaTracker:"); + pw.println(mUserQuotaTracker); pw.println("mTransformRecords:"); pw.println(mTransformRecords); pw.println("mUdpSocketRecords:"); From f5138c8f44b997fd0d86dbc82c68cef4eeac6c91 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 17 Aug 2017 19:23:08 +0900 Subject: [PATCH 0412/1150] Add tether offload traffic to interface stats as well. Currently, we only count add tethering traffic to per-UID stats, but not to total data usage (i.e., dev and XT stats). This is correct for software tethering, because all software forwarded packets are already included in interface counters, but it is incorrect for hardware offload, because such packets do not increment interface counters. To fix this: 1. Add an argument to ITetheringStatsProvider#getTetherStats to indicate whether per-UID stats are requested. For clarity, define integer constants STATS_PER_IFACE and STATS_PER_UID to represent these operations. 2. Make NetdTetheringStatsProvider return stats only if per-UID stats are requested. (Otherwise tethering traffic would be double-counted). 3. Make OffloadController's stats provider return the same stats regardless of whether per-UID stats were requested or not. 4. Make NetworkStatsService add non-per-UID tethering stats to the dev and XT snapshots. The per-UID snapshots were already correctly adding in per-UID stats. Bug: 29337859 Bug: 32163131 Test: runtest frameworks-net Test: runtest frameworks-telephony Change-Id: I7a4d04ab47694d754874136179f8edad71099638 --- core/java/android/net/NetworkStats.java | 5 +++++ .../android/server/net/NetworkStatsService.java | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index be9e809738..171adc054b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -82,6 +82,11 @@ public class NetworkStats implements Parcelable { /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; + /** Denotes a request for stats at the interface level. */ + public static final int STATS_PER_IFACE = 0; + /** Denotes a request for stats at the interface and UID level. */ + public static final int STATS_PER_UID = 1; + // TODO: move fields to "mVariable" notation /** diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 8209adeb89..b14aa13bfb 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -29,6 +29,8 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; +import static android.net.NetworkStats.STATS_PER_IFACE; +import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; @@ -1041,6 +1043,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats + // providers that isn't already counted by dev and XT stats. + final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + xtSnapshot.combineAllValues(tetherSnapshot); + devSnapshot.combineAllValues(tetherSnapshot); // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. @@ -1371,14 +1378,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); // fold tethering stats and operations into uid snapshot - final NetworkStats tetherSnapshot = getNetworkStatsTethering(); + final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); // fold video calling data usage stats into uid snapshot - final NetworkStats vtStats = telephonyManager.getVtDataUsage(true); + final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { uidSnapshot.combineAllValues(vtStats); } @@ -1397,7 +1404,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Context.TELEPHONY_SERVICE); // Merge video calling data usage into XT - final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(false); + final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE); if (vtSnapshot != null) { xtSnapshot.combineAllValues(vtSnapshot); } @@ -1409,9 +1416,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current tethering statistics. Will return empty * {@link NetworkStats} if any problems are encountered. */ - private NetworkStats getNetworkStatsTethering() throws RemoteException { + private NetworkStats getNetworkStatsTethering(int how) throws RemoteException { try { - return mNetworkManager.getNetworkStatsTethering(); + return mNetworkManager.getNetworkStatsTethering(how); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); return new NetworkStats(0L, 10); From 591c50889a5bd05c56f00f5509e79e713785f8c7 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 17 Aug 2017 19:23:08 +0900 Subject: [PATCH 0413/1150] Add tether offload traffic to interface stats as well. Currently, we only count add tethering traffic to per-UID stats, but not to total data usage (i.e., dev and XT stats). This is correct for software tethering, because all software forwarded packets are already included in interface counters, but it is incorrect for hardware offload, because such packets do not increment interface counters. To fix this: 1. Add an argument to ITetheringStatsProvider#getTetherStats to indicate whether per-UID stats are requested. For clarity, define integer constants STATS_PER_IFACE and STATS_PER_UID to represent these operations. 2. Make NetdTetheringStatsProvider return stats only if per-UID stats are requested. (Otherwise tethering traffic would be double-counted). 3. Make OffloadController's stats provider return the same stats regardless of whether per-UID stats were requested or not. 4. Make NetworkStatsService add non-per-UID tethering stats to the dev and XT snapshots. The per-UID snapshots were already correctly adding in per-UID stats. (cherry picked from commit 5356a35c3bcfcdf2d184c620af6bfbf9bddf35c5) Bug: 29337859 Bug: 32163131 Test: runtest frameworks-net Test: runtest frameworks-telephony Change-Id: I325b13d50e88841dfb0db4c35e7e27f163ee72fe Merged-In: I4e8e923d68dce1a4a68608dbd6c75a91165aa4ee --- core/java/android/net/NetworkStats.java | 5 +++++ .../android/server/net/NetworkStatsService.java | 17 ++++++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 77ce65b081..0780af602b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -82,6 +82,11 @@ public class NetworkStats implements Parcelable { /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; + /** Denotes a request for stats at the interface level. */ + public static final int STATS_PER_IFACE = 0; + /** Denotes a request for stats at the interface and UID level. */ + public static final int STATS_PER_UID = 1; + // TODO: move fields to "mVariable" notation /** diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4152070dc6..ef96de74cb 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -31,6 +31,8 @@ import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; +import static android.net.NetworkStats.STATS_PER_IFACE; +import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; @@ -1032,6 +1034,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats + // providers that isn't already counted by dev and XT stats. + final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + xtSnapshot.combineAllValues(tetherSnapshot); + devSnapshot.combineAllValues(tetherSnapshot); // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. @@ -1328,14 +1335,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); // fold tethering stats and operations into uid snapshot - final NetworkStats tetherSnapshot = getNetworkStatsTethering(); + final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); // fold video calling data usage stats into uid snapshot - final NetworkStats vtStats = telephonyManager.getVtDataUsage(true); + final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { uidSnapshot.combineAllValues(vtStats); } @@ -1354,7 +1361,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Context.TELEPHONY_SERVICE); // Merge video calling data usage into XT - final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(false); + final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE); if (vtSnapshot != null) { xtSnapshot.combineAllValues(vtSnapshot); } @@ -1366,9 +1373,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current tethering statistics. Will return empty * {@link NetworkStats} if any problems are encountered. */ - private NetworkStats getNetworkStatsTethering() throws RemoteException { + private NetworkStats getNetworkStatsTethering(int how) throws RemoteException { try { - return mNetworkManager.getNetworkStatsTethering(); + return mNetworkManager.getNetworkStatsTethering(how); } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); return new NetworkStats(0L, 10); From 95b454fdf50b8654a71ca9f7a2e3527b33c5fa5e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 29 Aug 2017 15:32:13 -0600 Subject: [PATCH 0414/1150] Augment network stats based on SubscriptionPlan. When a carrier provides an "anchor" of data usage at a specific moment in time, augment the network statistics used by warning/limit thresholds and Settings UI. For example, if the OS measured 500MB of usage, but the carrier says only 400MB has been used, we "squish" down the OS measured usage to match that anchor. Callers using the hidden API will have their data augmented by default, and the public API offers a way to opt-into augmentation. Thorough testing to verify behavior. Test: bit FrameworksNetTests:android.net.,com.android.server.net. Test: cts-tradefed run commandAndExit cts-dev -m CtsUsageStatsTestCases -t android.app.usage.cts.NetworkUsageStatsTest Bug: 64534190 Change-Id: Id3d4d7625bbf04f57643e51dbf376e3fa0ea8eca --- core/java/android/app/usage/NetworkStats.java | 4 +- .../app/usage/NetworkStatsManager.java | 45 +++-- .../android/net/INetworkStatsService.aidl | 2 +- .../java/android/net/NetworkStatsHistory.java | 19 ++ core/java/android/net/NetworkTemplate.java | 4 + .../server/net/NetworkStatsCollection.java | 162 +++++++++++++---- .../server/net/NetworkStatsObservers.java | 14 +- .../server/net/NetworkStatsRecorder.java | 9 +- .../server/net/NetworkStatsService.java | 165 ++++++++++++------ 9 files changed, 305 insertions(+), 119 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 3670b914ec..222e9a0e5e 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -97,12 +97,12 @@ public final class NetworkStats implements AutoCloseable { private NetworkStatsHistory.Entry mRecycledHistoryEntry = null; /** @hide */ - NetworkStats(Context context, NetworkTemplate template, long startTimestamp, + NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, long endTimestamp) throws RemoteException, SecurityException { final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); // Open network stats session - mSession = statsService.openSessionForUsageStats(context.getOpPackageName()); + mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); mCloseGuard.open("close"); mTemplate = template; mStartTimeStamp = startTimestamp; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index ef262e0460..853b00331a 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -24,15 +24,14 @@ import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; +import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkTemplate; -import android.net.INetworkStatsService; import android.os.Binder; -import android.os.Build; -import android.os.Message; -import android.os.Messenger; import android.os.Handler; import android.os.Looper; +import android.os.Message; +import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; @@ -79,7 +78,7 @@ import android.util.Log; * In addition to tethering usage, usage by removed users and apps, and usage by the system * is also included in the results for callers with one of these higher levels of access. *

            - * NOTE: Prior to API level {@value Build.VERSION_CODES#N}, all calls to these APIs required + * NOTE: Prior to API level {@value android.os.Build.VERSION_CODES#N}, all calls to these APIs required * the above permission, even to access an app's own data usage, and carrier-privileged apps were * not included. */ @@ -96,6 +95,13 @@ public class NetworkStatsManager { private final Context mContext; private final INetworkStatsService mService; + /** @hide */ + public static final int FLAG_POLL_ON_OPEN = 1 << 0; + /** @hide */ + public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 1; + + private int mFlags; + /** * {@hide} */ @@ -103,6 +109,25 @@ public class NetworkStatsManager { mContext = context; mService = INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); + setPollOnOpen(true); + } + + /** @hide */ + public void setPollOnOpen(boolean pollOnOpen) { + if (pollOnOpen) { + mFlags |= FLAG_POLL_ON_OPEN; + } else { + mFlags &= ~FLAG_POLL_ON_OPEN; + } + } + + /** @hide */ + public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { + if (augmentWithSubscriptionPlan) { + mFlags |= FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; + } else { + mFlags &= ~FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN; + } } /** @@ -136,7 +161,7 @@ public class NetworkStatsManager { } Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, startTime, endTime); + NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); bucket = stats.getDeviceSummaryForNetwork(); stats.close(); @@ -174,7 +199,7 @@ public class NetworkStatsManager { } NetworkStats stats; - stats = new NetworkStats(mContext, template, startTime, endTime); + stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); stats.startSummaryEnumeration(); stats.close(); @@ -211,7 +236,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime); result.startSummaryEnumeration(); return result; @@ -260,7 +285,7 @@ public class NetworkStatsManager { NetworkStats result; try { - result = new NetworkStats(mContext, template, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime); result.startHistoryEnumeration(uid, tag); } catch (RemoteException e) { Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e); @@ -305,7 +330,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime); result.startUserUidEnumeration(); return result; } diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index e693009c33..91801127fd 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -36,7 +36,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - INetworkStatsSession openSessionForUsageStats(String callingPackage); + INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return network layer usage total for traffic that matches template. */ long getNetworkTotalBytes(in NetworkTemplate template, long start, long end); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 5f521de63c..433f9410cc 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -27,6 +27,7 @@ import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import static android.text.format.DateUtils.SECOND_IN_MILLIS; + import static com.android.internal.util.ArrayUtils.total; import android.os.Parcel; @@ -282,6 +283,24 @@ public class NetworkStatsHistory implements Parcelable { return entry; } + public void setValues(int i, Entry entry) { + // Unwind old values + if (rxBytes != null) totalBytes -= rxBytes[i]; + if (txBytes != null) totalBytes -= txBytes[i]; + + bucketStart[i] = entry.bucketStart; + setLong(activeTime, i, entry.activeTime); + setLong(rxBytes, i, entry.rxBytes); + setLong(rxPackets, i, entry.rxPackets); + setLong(txBytes, i, entry.txBytes); + setLong(txPackets, i, entry.txPackets); + setLong(operations, i, entry.operations); + + // Apply new values + if (rxBytes != null) totalBytes += rxBytes[i]; + if (txBytes != null) totalBytes += txBytes[i]; + } + /** * Record that data traffic occurred in the given time range. Will * distribute across internal buckets, creating new buckets as needed. diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 0d2fcd0740..b307c5d6fc 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -326,6 +326,10 @@ public class NetworkTemplate implements Parcelable { } } + public boolean matchesSubscriberId(String subscriberId) { + return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + } + /** * Check if mobile network with matching IMSI. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 03543007c8..8837c157ae 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -28,6 +28,8 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import static com.android.server.net.NetworkStatsService.TAG; + import android.net.NetworkIdentity; import android.net.NetworkStats; import android.net.NetworkStatsHistory; @@ -37,20 +39,24 @@ import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; import android.service.NetworkStatsCollectionProto; import android.service.NetworkStatsCollectionStatsProto; +import android.telephony.SubscriptionPlan; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; +import android.util.Pair; +import android.util.Slog; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; +import libcore.io.IoUtils; + import com.google.android.collect.Lists; import com.google.android.collect.Maps; -import libcore.io.IoUtils; - import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -60,9 +66,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.net.ProtocolException; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.Objects; /** @@ -140,6 +148,35 @@ public class NetworkStatsCollection implements FileRotator.Reader { return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; } + @VisibleForTesting + public long roundUp(long time) { + if (time == Long.MIN_VALUE || time == Long.MAX_VALUE + || time == SubscriptionPlan.TIME_UNKNOWN) { + return time; + } else { + final long mod = time % mBucketDuration; + if (mod > 0) { + time -= mod; + time += mBucketDuration; + } + return time; + } + } + + @VisibleForTesting + public long roundDown(long time) { + if (time == Long.MIN_VALUE || time == Long.MAX_VALUE + || time == SubscriptionPlan.TIME_UNKNOWN) { + return time; + } else { + final long mod = time % mBucketDuration; + if (mod > 0) { + time -= mod; + } + return time; + } + } + public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { return getRelevantUids(accessLevel, Binder.getCallingUid()); } @@ -165,60 +202,110 @@ public class NetworkStatsCollection implements FileRotator.Reader { * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. */ - public NetworkStatsHistory getHistory( - NetworkTemplate template, int uid, int set, int tag, int fields, - @NetworkStatsAccess.Level int accessLevel) { - return getHistory(template, uid, set, tag, fields, Long.MIN_VALUE, Long.MAX_VALUE, - accessLevel); - } - - /** - * Combine all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. - */ - public NetworkStatsHistory getHistory( - NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, - @NetworkStatsAccess.Level int accessLevel) { - return getHistory(template, uid, set, tag, fields, start, end, accessLevel, - Binder.getCallingUid()); - } - - /** - * Combine all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. - */ - public NetworkStatsHistory getHistory( - NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end, + public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, + int uid, int set, int tag, int fields, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { if (!NetworkStatsAccess.isAccessibleToUser(uid, callerUid, accessLevel)) { throw new SecurityException("Network stats history of uid " + uid + " is forbidden for caller " + callerUid); } + final int bucketEstimate = (int) ((end - start) / mBucketDuration); final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDuration, start == end ? 1 : estimateBuckets(), fields); + mBucketDuration, bucketEstimate, fields); // shortcut when we know stats will be empty if (start == end) return combined; + // Figure out the window of time that we should be augmenting (if any) + long augmentStart = SubscriptionPlan.TIME_UNKNOWN; + long augmentEnd = (augmentPlan != null) ? augmentPlan.getDataUsageTime() + : SubscriptionPlan.TIME_UNKNOWN; + // And if augmenting, we might need to collect more data to adjust with + long collectStart = start; + long collectEnd = end; + + if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) { + final Iterator> it = augmentPlan.cycleIterator(); + while (it.hasNext()) { + final Pair cycle = it.next(); + final long cycleStart = cycle.first.toInstant().toEpochMilli(); + final long cycleEnd = cycle.second.toInstant().toEpochMilli(); + if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) { + augmentStart = cycleStart; + collectStart = Long.min(collectStart, augmentStart); + collectEnd = Long.max(collectEnd, augmentEnd); + break; + } + } + } + + if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { + // Shrink augmentation window so we don't risk undercounting. + augmentStart = roundUp(augmentStart); + augmentEnd = roundDown(augmentEnd); + // Grow collection window so we get all the stats needed. + collectStart = roundDown(collectStart); + collectEnd = roundUp(collectEnd); + } + for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); if (key.uid == uid && NetworkStats.setMatches(set, key.set) && key.tag == tag && templateMatches(template, key.ident)) { final NetworkStatsHistory value = mStats.valueAt(i); - combined.recordHistory(value, start, end); + combined.recordHistory(value, collectStart, collectEnd); } } - return combined; - } - /** - * Summarize all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. - */ - public NetworkStats getSummary(NetworkTemplate template, long start, long end, - @NetworkStatsAccess.Level int accessLevel) { - return getSummary(template, start, end, accessLevel, Binder.getCallingUid()); + if (augmentStart != SubscriptionPlan.TIME_UNKNOWN) { + final NetworkStatsHistory.Entry entry = combined.getValues( + augmentStart, augmentEnd, null); + + // If we don't have any recorded data for this time period, give + // ourselves something to scale with. + if (entry.rxBytes == 0 || entry.txBytes == 0) { + combined.recordData(augmentStart, augmentEnd, + new NetworkStats.Entry(1, 0, 1, 0, 0)); + combined.getValues(augmentStart, augmentEnd, entry); + } + + final long rawBytes = entry.rxBytes + entry.txBytes; + final long rawRxBytes = entry.rxBytes; + final long rawTxBytes = entry.txBytes; + final long targetBytes = augmentPlan.getDataUsageBytes(); + final long targetRxBytes = (rawRxBytes * targetBytes) / rawBytes; + final long targetTxBytes = (rawTxBytes * targetBytes) / rawBytes; + + // Scale all matching buckets to reach anchor target + final long beforeTotal = combined.getTotalBytes(); + for (int i = 0; i < combined.size(); i++) { + combined.getValues(i, entry); + if (entry.bucketStart >= augmentStart + && entry.bucketStart + entry.bucketDuration <= augmentEnd) { + entry.rxBytes = (entry.rxBytes * targetRxBytes) / rawRxBytes; + entry.txBytes = (entry.txBytes * targetTxBytes) / rawTxBytes; + // We purposefully clear out packet counters to indicate + // that this data has been augmented. + entry.rxPackets = 0; + entry.txPackets = 0; + combined.setValues(i, entry); + } + } + + final long deltaTotal = combined.getTotalBytes() - beforeTotal; + if (deltaTotal != 0) { + Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); + } + + // Finally we can slice data as originally requested + final NetworkStatsHistory sliced = new NetworkStatsHistory( + mBucketDuration, bucketEstimate, fields); + sliced.recordHistory(combined, start, end); + return sliced; + } else { + return combined; + } } /** @@ -230,6 +317,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { final long now = System.currentTimeMillis(); final NetworkStats stats = new NetworkStats(end - start, 24); + // shortcut when we know stats will be empty if (start == end) return stats; diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index a256cbcf90..741c2062bd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -17,28 +17,26 @@ package com.android.server.net; import static android.net.TrafficStats.MB_IN_BYTES; + import static com.android.internal.util.Preconditions.checkArgument; import android.app.usage.NetworkStatsManager; import android.net.DataUsageRequest; import android.net.NetworkStats; -import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.os.Binder; import android.os.Bundle; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; import android.os.Process; import android.os.RemoteException; import android.util.ArrayMap; -import android.util.IntArray; -import android.util.SparseArray; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnInfo; @@ -410,7 +408,7 @@ class NetworkStatsObservers { */ private long getTotalBytesForNetworkUid(NetworkTemplate template, int uid) { try { - NetworkStatsHistory history = mCollection.getHistory(template, uid, + NetworkStatsHistory history = mCollection.getHistory(template, null, uid, NetworkStats.SET_ALL, NetworkStats.TAG_NONE, NetworkStatsHistory.FIELD_ALL, Long.MIN_VALUE /* start */, Long.MAX_VALUE /* end */, diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 80309e19eb..4bee55ef8b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -20,6 +20,7 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.text.format.DateUtils.YEAR_IN_MILLIS; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; @@ -28,6 +29,7 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.Binder; import android.os.DropBoxManager; import android.service.NetworkStatsRecorderProto; import android.util.Log; @@ -38,6 +40,9 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; + +import libcore.io.IoUtils; + import com.google.android.collect.Sets; import java.io.ByteArrayOutputStream; @@ -52,8 +57,6 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Map; -import libcore.io.IoUtils; - /** * Logic to record deltas between periodic {@link NetworkStats} snapshots into * {@link NetworkStatsHistory} that belong to {@link NetworkStatsCollection}. @@ -150,7 +153,7 @@ public class NetworkStatsRecorder { public NetworkStats.Entry getTotalSinceBootLocked(NetworkTemplate template) { return mSinceBoot.getSummary(template, Long.MIN_VALUE, Long.MAX_VALUE, - NetworkStatsAccess.Level.DEVICE).getTotal(null); + NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotal(null); } public NetworkStatsCollection getSinceBoot() { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b14aa13bfb..4bd927d497 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -26,6 +26,8 @@ import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; @@ -33,10 +35,12 @@ import static android.net.NetworkStats.STATS_PER_IFACE; import static android.net.NetworkStats.STATS_PER_UID; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; @@ -65,6 +69,7 @@ import static com.android.server.NetworkManagementSocketTagger.setKernelCounterS import android.app.AlarmManager; import android.app.PendingIntent; +import android.app.usage.NetworkStatsManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -104,6 +109,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.telephony.SubscriptionManager; +import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; @@ -139,8 +146,8 @@ import java.util.List; * other system services. */ public class NetworkStatsService extends INetworkStatsService.Stub { - private static final String TAG = "NetworkStats"; - private static final boolean LOGV = false; + static final String TAG = "NetworkStats"; + static final boolean LOGV = false; private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; @@ -194,6 +201,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getPollInterval(); public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); + public boolean getAugmentEnabled(); public static class Config { public final long bucketDuration; @@ -466,18 +474,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { - return createSession(null, /* poll on create */ false); + // NOTE: if callers want to get non-augmented data, they should go + // through the public API + return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null); } @Override - public INetworkStatsSession openSessionForUsageStats(final String callingPackage) { - return createSession(callingPackage, /* poll on create */ true); + public INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) { + return openSessionInternal(flags, callingPackage); } - private INetworkStatsSession createSession(final String callingPackage, boolean pollOnCreate) { + private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { assertBandwidthControlEnabled(); - if (pollOnCreate) { + if ((flags & NetworkStatsManager.FLAG_POLL_ON_OPEN) != 0) { final long ident = Binder.clearCallingIdentity(); try { performPoll(FLAG_PERSIST_ALL); @@ -490,9 +500,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // for its lifetime; when caller closes only weak references remain. return new INetworkStatsSession.Stub() { + private final int mCallingUid = Binder.getCallingUid(); + private final String mCallingPackage = callingPackage; + private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( + callingPackage); + private NetworkStatsCollection mUidComplete; private NetworkStatsCollection mUidTagComplete; - private String mCallingPackage = callingPackage; private NetworkStatsCollection getUidComplete() { synchronized (mStatsLock) { @@ -514,55 +528,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public int[] getRelevantUids() { - return getUidComplete().getRelevantUids(checkAccessLevel(mCallingPackage)); + return getUidComplete().getRelevantUids(mAccessLevel); } @Override - public NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, - long end) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { - throw new SecurityException("Calling package " + mCallingPackage - + " cannot access device summary network stats"); - } - NetworkStats result = new NetworkStats(end - start, 1); - final long ident = Binder.clearCallingIdentity(); - try { - // Using access level higher than the one we checked for above. - // Reason is that we are combining usage data in a way that is not PII - // anymore. - result.combineAllValues( - internalGetSummaryForNetwork(template, start, end, - NetworkStatsAccess.Level.DEVICE)); - } finally { - Binder.restoreCallingIdentity(ident); - } - return result; + public NetworkStats getDeviceSummaryForNetwork( + NetworkTemplate template, long start, long end) { + return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel, + mCallingUid); } @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - return internalGetSummaryForNetwork(template, start, end, accessLevel); + return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel, + mCallingUid); } @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - return internalGetHistoryForNetwork(template, fields, accessLevel); + return internalGetHistoryForNetwork(template, flags, fields, mAccessLevel, + mCallingUid); } @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { try { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); - final NetworkStats stats = - getUidComplete().getSummary(template, start, end, accessLevel); + final NetworkStats stats = getUidComplete() + .getSummary(template, start, end, mAccessLevel, mCallingUid); if (includeTags) { final NetworkStats tagStats = getUidTagComplete() - .getSummary(template, start, end, accessLevel); + .getSummary(template, start, end, mAccessLevel, mCallingUid); stats.combineAllValues(tagStats); } return stats; @@ -576,13 +573,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + // NOTE: We don't augment UID-level statistics if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, uid, set, tag, fields, - accessLevel); + return getUidComplete().getHistory(template, null, uid, set, tag, fields, + Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); } else { - return getUidTagComplete().getHistory(template, uid, set, tag, fields, - accessLevel); + return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, + Long.MIN_VALUE, Long.MAX_VALUE, mAccessLevel, mCallingUid); } } @@ -590,13 +587,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsHistory getHistoryIntervalForUid( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { - @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(mCallingPackage); + // NOTE: We don't augment UID-level statistics if (tag == TAG_NONE) { - return getUidComplete().getHistory(template, uid, set, tag, fields, start, end, - accessLevel); + return getUidComplete().getHistory(template, null, uid, set, tag, fields, + start, end, mAccessLevel, mCallingUid); } else if (uid == Binder.getCallingUid()) { - return getUidTagComplete().getHistory(template, uid, set, tag, fields, - start, end, accessLevel); + return getUidTagComplete().getHistory(template, null, uid, set, tag, fields, + start, end, mAccessLevel, mCallingUid); } else { throw new SecurityException("Calling package " + mCallingPackage + " cannot access tag information from a different uid"); @@ -616,37 +613,85 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext, Binder.getCallingUid(), callingPackage); } + /** + * Find the most relevant {@link SubscriptionPlan} for the given + * {@link NetworkTemplate} and flags. This is typically used to augment + * local measurement results to match a known anchor from the carrier. + */ + private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { + SubscriptionPlan plan = null; + if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 + && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL) + && mSettings.getAugmentEnabled()) { + Slog.d(TAG, "Resolving plan for " + template); + final long token = Binder.clearCallingIdentity(); + try { + final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); + final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); + for (int subId : sm.getActiveSubscriptionIdList()) { + if (template.matchesSubscriberId(tm.getSubscriberId(subId))) { + Slog.d(TAG, "Found active matching subId " + subId); + final List plans = sm.getSubscriptionPlans(subId); + if (!plans.isEmpty()) { + plan = plans.get(0); + } + } + } + } finally { + Binder.restoreCallingIdentity(token); + } + Slog.d(TAG, "Resolved to plan " + plan); + } + return plan; + } + /** * Return network summary, splicing between DEV and XT stats when * appropriate. */ - private NetworkStats internalGetSummaryForNetwork( - NetworkTemplate template, long start, long end, - @NetworkStatsAccess.Level int accessLevel) { + private NetworkStats internalGetSummaryForNetwork(NetworkTemplate template, int flags, + long start, long end, @NetworkStatsAccess.Level int accessLevel, int callingUid) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. - return mXtStatsCached.getSummary(template, start, end, accessLevel); + final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL, + accessLevel, callingUid); + + final long now = System.currentTimeMillis(); + final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); + + final NetworkStats stats = new NetworkStats(end - start, 1); + stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, + ROAMING_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, + entry.operations)); + return stats; } /** * Return network history, splicing between DEV and XT stats when * appropriate. */ - private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields, - @NetworkStatsAccess.Level int accessLevel) { + private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, + int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. - return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields, accessLevel); + return mXtStatsCached.getHistory(template, resolveSubscriptionPlan(template, flags), + UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE, + accessLevel, callingUid); } @Override public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - // Special case - since this is for internal use only, don't worry about a full access level - // check and just require the signature/privileged permission. + // Special case - since this is for internal use only, don't worry about + // a full access level check and just require the signature/privileged + // permission. mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); - return internalGetSummaryForNetwork(template, start, end, NetworkStatsAccess.Level.DEVICE) - .getTotalBytes(); + + // NOTE: if callers want to get non-augmented data, they should go + // through the public API + return internalGetSummaryForNetwork(template, + NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end, + NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); } @Override @@ -1530,6 +1575,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true); } @Override + public boolean getAugmentEnabled() { + return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); + } + @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From bcdf1c060a9c9659cb2d9a3e4711f22c2c20ae47 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 1 Sep 2017 11:27:13 -0600 Subject: [PATCH 0415/1150] Don't over-acquire NPMS locks. We only need to hold mNetworkPoliciesSecondLock when working with subscription plans; before this CL we could end up acquiring the two NPMS locks out of order, resulting in a deadlock. Also annotate objects in NSS that require mStatsLock to be held. Test: builds, boots Bug: 65268076 Change-Id: I06497564424316ef895dc8dceba72ae784781dc3 --- .../server/net/NetworkStatsService.java | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4bd927d497..3af5265e6f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -124,6 +124,7 @@ import android.util.SparseIntArray; import android.util.TrustedTime; import android.util.proto.ProtoOutputStream; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; @@ -241,12 +242,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); + @GuardedBy("mStatsLock") private NetworkStatsRecorder mDevRecorder; + @GuardedBy("mStatsLock") private NetworkStatsRecorder mXtRecorder; + @GuardedBy("mStatsLock") private NetworkStatsRecorder mUidRecorder; + @GuardedBy("mStatsLock") private NetworkStatsRecorder mUidTagRecorder; /** Cached {@link #mXtRecorder} stats. */ + @GuardedBy("mStatsLock") private NetworkStatsCollection mXtStatsCached; /** Current counter sets for each UID. */ @@ -328,15 +334,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } - // create data recorders along with historical rotators - mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); - mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); - mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); - mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); - - updatePersistThresholds(); - synchronized (mStatsLock) { + // create data recorders along with historical rotators + mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); + mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); + mUidRecorder = buildRecorder(PREFIX_UID, mSettings.getUidConfig(), false); + mUidTagRecorder = buildRecorder(PREFIX_UID_TAG, mSettings.getUidTagConfig(), true); + + updatePersistThresholdsLocked(); + // upgrade any legacy stats, migrating them to rotated files maybeUpgradeLegacyStatsLocked(); @@ -674,9 +680,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. - return mXtStatsCached.getHistory(template, resolveSubscriptionPlan(template, flags), - UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE, - accessLevel, callingUid); + final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags); + synchronized (mStatsLock) { + return mXtStatsCached.getHistory(template, augmentPlan, + UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE, + accessLevel, callingUid); + } } @Override @@ -813,7 +822,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { if (!mSystemReady) return; - updatePersistThresholds(); + updatePersistThresholdsLocked(); mDevRecorder.maybePersistLocked(currentTime); mXtRecorder.maybePersistLocked(currentTime); @@ -869,7 +878,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * reflect current {@link #mPersistThreshold} value. Always defers to * {@link Global} values when defined. */ - private void updatePersistThresholds() { + private void updatePersistThresholdsLocked() { mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); mUidRecorder.setPersistThreshold(mSettings.getUidPersistBytes(mPersistThreshold)); @@ -1311,7 +1320,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { synchronized (mStatsLock) { if (args.length > 0 && "--proto".equals(args[0])) { // In this case ignore all other arguments. - dumpProto(fd); + dumpProtoLocked(fd); return; } @@ -1387,7 +1396,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void dumpProto(FileDescriptor fd) { + private void dumpProtoLocked(FileDescriptor fd) { final ProtoOutputStream proto = new ProtoOutputStream(fd); // TODO Right now it writes all history. Should it limit to the "since-boot" log? From e5d8610d8e01e5a9d45be5221a10580f63ff8745 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 1 Sep 2017 12:51:51 -0600 Subject: [PATCH 0416/1150] Gracefully handle integer overflows. Try sticking with integer-based math as much as possible for speed, but switch to double-based math if we detect that we'd end up causing an overflow. New tests to verify. Test: bit FrameworksNetTests:com.android.server.net.NetworkStatsCollectionTest Bug: 65257769 Change-Id: I1ae35599be134f81850c0a3d86928b057fba1eff --- .../server/net/NetworkStatsCollection.java | 36 ++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 8837c157ae..4ceb592af0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -177,6 +177,34 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } + /** + * Safely multiple a value by a rational. + *

            + * Internally it uses integer-based math whenever possible, but switches + * over to double-based math if values would overflow. + */ + @VisibleForTesting + public static long multiplySafe(long value, long num, long den) { + long x = value; + long y = num; + + // Logic shamelessly borrowed from Math.multiplyExact() + long r = x * y; + long ax = Math.abs(x); + long ay = Math.abs(y); + if (((ax | ay) >>> 31 != 0)) { + // Some bits greater than 2^31 that might cause overflow + // Check the result using the divide operator + // and check for the special case of Long.MIN_VALUE * -1 + if (((y != 0) && (r / y != x)) || + (x == Long.MIN_VALUE && y == -1)) { + // Use double math to avoid overflowing + return (long) (((double) num / den) * value); + } + } + return r / den; + } + public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { return getRelevantUids(accessLevel, Binder.getCallingUid()); } @@ -274,8 +302,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { final long rawRxBytes = entry.rxBytes; final long rawTxBytes = entry.txBytes; final long targetBytes = augmentPlan.getDataUsageBytes(); - final long targetRxBytes = (rawRxBytes * targetBytes) / rawBytes; - final long targetTxBytes = (rawTxBytes * targetBytes) / rawBytes; + final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes); + final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes); // Scale all matching buckets to reach anchor target final long beforeTotal = combined.getTotalBytes(); @@ -283,8 +311,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { combined.getValues(i, entry); if (entry.bucketStart >= augmentStart && entry.bucketStart + entry.bucketDuration <= augmentEnd) { - entry.rxBytes = (entry.rxBytes * targetRxBytes) / rawRxBytes; - entry.txBytes = (entry.txBytes * targetTxBytes) / rawTxBytes; + entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes); + entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes); // We purposefully clear out packet counters to indicate // that this data has been augmented. entry.rxPackets = 0; From 648283ecc7c036ba183f1776370838b07881f117 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 31 Jul 2017 20:35:58 +0900 Subject: [PATCH 0417/1150] Network Service Discovery test: properly release resources Bug: 32561414 Bug: 62918393 Bug: 62044295 Test: runtest frameworks-net Change-Id: If23993b5e391947ecbdc01677f0a643144794b2b --- core/java/android/net/nsd/NsdManager.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 1e41eea925..535bf675cd 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -21,25 +21,24 @@ import static com.android.internal.util.Preconditions.checkNotNull; import static com.android.internal.util.Preconditions.checkStringNotEmpty; import android.annotation.SdkConstant; -import android.annotation.SystemService; import android.annotation.SdkConstant.SdkConstantType; +import android.annotation.SystemService; import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.RemoteException; import android.os.Messenger; -import android.text.TextUtils; +import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; -import java.util.concurrent.CountDownLatch; - import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.util.concurrent.CountDownLatch; + /** * The Network Service Discovery Manager class provides the API to discover services * on a network. As an example, if device A and device B are connected over a Wi-Fi @@ -244,7 +243,7 @@ public final class NsdManager { return name; } - private static int FIRST_LISTENER_KEY = 1; + private static final int FIRST_LISTENER_KEY = 1; private final INsdManager mService; private final Context mContext; @@ -278,6 +277,7 @@ public final class NsdManager { @VisibleForTesting public void disconnect() { mAsyncChannel.disconnect(); + mHandler.getLooper().quitSafely(); } /** @@ -650,7 +650,7 @@ public final class NsdManager { private static void checkServiceInfo(NsdServiceInfo serviceInfo) { checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); - checkStringNotEmpty(serviceInfo.getServiceName(),"Service name cannot be empty"); + checkStringNotEmpty(serviceInfo.getServiceName(), "Service name cannot be empty"); checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); } } From d18ca7c9fa1ee496dce80fb718717f88a77d0571 Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Mon, 7 Aug 2017 15:47:35 +0900 Subject: [PATCH 0418/1150] NetworkStats: more robust subtraction for deltas This patch ensures that subtract() between two NetworkStats object will return a delta with no negative entries in all cases. When the stats delta contains some negative values, there are clamped to 0. Some logging is added when this happens. This is what's expected by NetworkStatsHistory#recordData(). Bug: 64365917 Bug: 65439160 Test: runtest frameworks-net Merged-In: I16e97e73f600225f80e0ce517e80c07c6f399196 Merged-In: I2ac0bc3914cb65ae8ee27921856d698dc59624b2 Merged-In: I67d5dc4b52b254748ff17fe1e16c2eeb1d03c30d Merged-In: Ib488fb034f72c92f19916490981342a3ef2eb33b (cherry picked from commit ce144deb7b824a4c2fbc0d48e664267a74c61ba6) Change-Id: Ic86b65a65a2517c871221f8784088ec1de18f534 --- core/java/android/net/NetworkStats.java | 45 ++++++++++++------------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0780af602b..171adc054b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -677,36 +677,33 @@ public class NetworkStats implements Parcelable { entry.tag = left.tag[i]; entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; + entry.rxBytes = left.rxBytes[i]; + entry.rxPackets = left.rxPackets[i]; + entry.txBytes = left.txBytes[i]; + entry.txPackets = left.txPackets[i]; + entry.operations = left.operations[i]; // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, i); - if (j == -1) { - // newly appearing row, return entire value - entry.rxBytes = left.rxBytes[i]; - entry.rxPackets = left.rxPackets[i]; - entry.txBytes = left.txBytes[i]; - entry.txPackets = left.txPackets[i]; - entry.operations = left.operations[i]; - } else { - // existing row, subtract remote value - entry.rxBytes = left.rxBytes[i] - right.rxBytes[j]; - entry.rxPackets = left.rxPackets[i] - right.rxPackets[j]; - entry.txBytes = left.txBytes[i] - right.txBytes[j]; - entry.txPackets = left.txPackets[i] - right.txPackets[j]; - entry.operations = left.operations[i] - right.operations[j]; + if (j != -1) { + // Found matching row, subtract remote value. + entry.rxBytes -= right.rxBytes[j]; + entry.rxPackets -= right.rxPackets[j]; + entry.txBytes -= right.txBytes[j]; + entry.txPackets -= right.txPackets[j]; + entry.operations -= right.operations[j]; + } - if (entry.rxBytes < 0 || entry.rxPackets < 0 || entry.txBytes < 0 - || entry.txPackets < 0 || entry.operations < 0) { - if (observer != null) { - observer.foundNonMonotonic(left, i, right, j, cookie); - } - entry.rxBytes = Math.max(entry.rxBytes, 0); - entry.rxPackets = Math.max(entry.rxPackets, 0); - entry.txBytes = Math.max(entry.txBytes, 0); - entry.txPackets = Math.max(entry.txPackets, 0); - entry.operations = Math.max(entry.operations, 0); + if (entry.isNegative()) { + if (observer != null) { + observer.foundNonMonotonic(left, i, right, j, cookie); } + entry.rxBytes = Math.max(entry.rxBytes, 0); + entry.rxPackets = Math.max(entry.rxPackets, 0); + entry.txBytes = Math.max(entry.txBytes, 0); + entry.txPackets = Math.max(entry.txPackets, 0); + entry.operations = Math.max(entry.operations, 0); } result.addValues(entry); From 2e2cec680abb06a580bf2332d30ae2f587d09d66 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 11 Sep 2017 19:50:19 -0700 Subject: [PATCH 0419/1150] Re-Enable Starting of the IpSecService This reverts commit 41004ff4113dc9175c993638a47af602af6d8a98. Bug: 64800246 Test: compilation Change-Id: I4f5e3cd23001b9d94b3f6dc9fcfe731a90650e6e --- core/java/android/net/IpSecAlgorithm.java | 2 ++ core/java/android/net/IpSecManager.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 5ae3400361..7e956bf388 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -19,7 +19,9 @@ import android.annotation.StringDef; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; + import com.android.internal.util.HexDump; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 2f791e151b..00cacbcd71 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -25,7 +25,9 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.AndroidException; import android.util.Log; + import dalvik.system.CloseGuard; + import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramSocket; From 004a59a6ab57e3079556b4b9f82e51973e58d40c Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 11 Sep 2017 19:53:33 -0700 Subject: [PATCH 0420/1150] Re-Expose IpSecService API Surface Note, This reverts commit faf8a9191762444f659164ce633bdfec1ab8de62. Bug: 64800246 Test: compilation Change-Id: I709d4c476647cfe9f6b982fc373f8d76018b3922 --- core/java/android/net/IpSecAlgorithm.java | 2 -- core/java/android/net/IpSecManager.java | 4 +++- core/java/android/net/IpSecTransform.java | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7e956bf388..ead406c20c 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -28,8 +28,6 @@ import java.lang.annotation.RetentionPolicy; /** * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to * RFC 4301. - * - * @hide */ public final class IpSecAlgorithm implements Parcelable { diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 00cacbcd71..d7908c8cee 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -38,7 +38,9 @@ import java.net.Socket; * This class contains methods for managing IPsec sessions, which will perform kernel-space * encryption and decryption of socket or Network traffic. * - * @hide + *

            An IpSecManager may be obtained by calling {@link + * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link + * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} */ @SystemService(Context.IPSEC_SERVICE) public final class IpSecManager { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index cfbac58bbd..62fd65b9c1 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -26,9 +26,12 @@ import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; + import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; + import dalvik.system.CloseGuard; + import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -43,8 +46,6 @@ import java.net.InetAddress; * *

            An IpSecTransform may either represent a tunnel mode transform that operates on a wide array * of traffic or may represent a transport mode transform operating on a Socket or Sockets. - * - * @hide */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; From ed813205fa396982733dd8a1a164d2fdbbe0cd72 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 23 Aug 2017 13:46:33 -0700 Subject: [PATCH 0421/1150] Input Validation for IpSecService All of the input to IpSecService over the Binder interface needs to be validated both for sanity and for safety. -Sanity check all the parameters coming from binder. -Added setters for IpSecConfig to decouple the test from the IpSecManager. This was needed because the input validation caused the tests to fail due to a null parameter that was previously un-tested. -Added the mode flag to the IpSecConfig bundle this oversight was found during testing. -Expose the getResourceId() methods for testing in UdpEncapsulationSocket, SecurityParameterIndex, and IpSecTransform classes. -Remove the unneeded getIpSecConfig() from IpSecTransform: unneeded now that we can synthesize configs. Bug: 38397094 Test: runtest frameworks-net Change-Id: I5241fc7fbfa9816d54219acd8d81a9f7eef10dd4 --- core/java/android/net/IpSecConfig.java | 244 +++++++++++------- core/java/android/net/IpSecManager.java | 8 +- core/java/android/net/IpSecTransform.java | 103 ++------ .../java/com/android/server/IpSecService.java | 151 ++++++++--- 4 files changed, 299 insertions(+), 207 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 5a5c740c7a..56224afc27 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -17,105 +17,163 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; -import android.util.Log; -import java.net.InetAddress; -import java.net.UnknownHostException; + +import com.android.internal.annotations.VisibleForTesting; /** @hide */ public final class IpSecConfig implements Parcelable { private static final String TAG = "IpSecConfig"; - //MODE_TRANSPORT or MODE_TUNNEL - int mode; + // MODE_TRANSPORT or MODE_TUNNEL + private int mMode = IpSecTransform.MODE_TRANSPORT; - // For tunnel mode - InetAddress localAddress; + // Needs to be valid only for tunnel mode + // Preventing this from being null simplifies Java->Native binder + private String mLocalAddress = ""; - InetAddress remoteAddress; + // Preventing this from being null simplifies Java->Native binder + private String mRemoteAddress = ""; - // Limit selection by network interface - Network network; + // The underlying network interface that represents the "gateway" Network + // for outbound packets. It may also be used to select packets. + private Network mNetwork; public static class Flow { // Minimum requirements for identifying a transform // SPI identifying the IPsec flow in packet processing // and a remote IP address - int spiResourceId; + private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; // Encryption Algorithm - IpSecAlgorithm encryption; + private IpSecAlgorithm mEncryption; // Authentication Algorithm - IpSecAlgorithm authentication; + private IpSecAlgorithm mAuthentication; @Override public String toString() { return new StringBuilder() - .append("{spiResourceId=") - .append(spiResourceId) - .append(", encryption=") - .append(encryption) - .append(", authentication=") - .append(authentication) + .append("{mSpiResourceId=") + .append(mSpiResourceId) + .append(", mEncryption=") + .append(mEncryption) + .append(", mAuthentication=") + .append(mAuthentication) .append("}") .toString(); } } - final Flow[] flow = new Flow[] {new Flow(), new Flow()}; + private final Flow[] mFlow = new Flow[] {new Flow(), new Flow()}; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE - int encapType; - int encapLocalPortResourceId; - int encapRemotePort; + private int mEncapType = IpSecTransform.ENCAP_NONE; + private int mEncapSocketResourceId = IpSecManager.INVALID_RESOURCE_ID; + private int mEncapRemotePort; // An interval, in seconds between the NattKeepalive packets - int nattKeepaliveInterval; + private int mNattKeepaliveInterval; + + /** Set the mode for this IPsec transform */ + public void setMode(int mode) { + mMode = mode; + } + + /** Set the local IP address for Tunnel mode */ + public void setLocalAddress(String localAddress) { + if (localAddress == null) { + throw new IllegalArgumentException("localAddress may not be null!"); + } + mLocalAddress = localAddress; + } + + /** Set the remote IP address for this IPsec transform */ + public void setRemoteAddress(String remoteAddress) { + if (remoteAddress == null) { + throw new IllegalArgumentException("remoteAddress may not be null!"); + } + mRemoteAddress = remoteAddress; + } + + /** Set the SPI for a given direction by resource ID */ + public void setSpiResourceId(int direction, int resourceId) { + mFlow[direction].mSpiResourceId = resourceId; + } + + /** Set the encryption algorithm for a given direction */ + public void setEncryption(int direction, IpSecAlgorithm encryption) { + mFlow[direction].mEncryption = encryption; + } + + /** Set the authentication algorithm for a given direction */ + public void setAuthentication(int direction, IpSecAlgorithm authentication) { + mFlow[direction].mAuthentication = authentication; + } + + public void setNetwork(Network network) { + mNetwork = network; + } + + public void setEncapType(int encapType) { + mEncapType = encapType; + } + + public void setEncapSocketResourceId(int resourceId) { + mEncapSocketResourceId = resourceId; + } + + public void setEncapRemotePort(int port) { + mEncapRemotePort = port; + } + + public void setNattKeepaliveInterval(int interval) { + mNattKeepaliveInterval = interval; + } // Transport or Tunnel public int getMode() { - return mode; + return mMode; } - public InetAddress getLocalAddress() { - return localAddress; + public String getLocalAddress() { + return mLocalAddress; } public int getSpiResourceId(int direction) { - return flow[direction].spiResourceId; + return mFlow[direction].mSpiResourceId; } - public InetAddress getRemoteAddress() { - return remoteAddress; + public String getRemoteAddress() { + return mRemoteAddress; } public IpSecAlgorithm getEncryption(int direction) { - return flow[direction].encryption; + return mFlow[direction].mEncryption; } public IpSecAlgorithm getAuthentication(int direction) { - return flow[direction].authentication; + return mFlow[direction].mAuthentication; } public Network getNetwork() { - return network; + return mNetwork; } public int getEncapType() { - return encapType; + return mEncapType; } - public int getEncapLocalResourceId() { - return encapLocalPortResourceId; + public int getEncapSocketResourceId() { + return mEncapSocketResourceId; } public int getEncapRemotePort() { - return encapRemotePort; + return mEncapRemotePort; } public int getNattKeepaliveInterval() { - return nattKeepaliveInterval; + return mNattKeepaliveInterval; } // Parcelable Methods @@ -127,82 +185,68 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { - // TODO: Use a byte array or other better method for storing IPs that can also include scope - out.writeString((localAddress != null) ? localAddress.getHostAddress() : null); - // TODO: Use a byte array or other better method for storing IPs that can also include scope - out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null); - out.writeParcelable(network, flags); - out.writeInt(flow[IpSecTransform.DIRECTION_IN].spiResourceId); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryption, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authentication, flags); - out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spiResourceId); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryption, flags); - out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authentication, flags); - out.writeInt(encapType); - out.writeInt(encapLocalPortResourceId); - out.writeInt(encapRemotePort); + out.writeInt(mMode); + out.writeString(mLocalAddress); + out.writeString(mRemoteAddress); + out.writeParcelable(mNetwork, flags); + out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); + out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags); + out.writeInt(mEncapType); + out.writeInt(mEncapSocketResourceId); + out.writeInt(mEncapRemotePort); } - // Package Private: Used by the IpSecTransform.Builder; - // there should be no public constructor for this object - IpSecConfig() {} - - private static InetAddress readInetAddressFromParcel(Parcel in) { - String addrString = in.readString(); - if (addrString == null) { - return null; - } - try { - return InetAddress.getByName(addrString); - } catch (UnknownHostException e) { - Log.wtf(TAG, "Invalid IpAddress " + addrString); - return null; - } - } + @VisibleForTesting + public IpSecConfig() {} private IpSecConfig(Parcel in) { - localAddress = readInetAddressFromParcel(in); - remoteAddress = readInetAddressFromParcel(in); - network = (Network) in.readParcelable(Network.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_IN].spiResourceId = in.readInt(); - flow[IpSecTransform.DIRECTION_IN].encryption = + mMode = in.readInt(); + mLocalAddress = in.readString(); + mRemoteAddress = in.readString(); + mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); + mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt(); + mFlow[IpSecTransform.DIRECTION_IN].mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_IN].authentication = + mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_OUT].spiResourceId = in.readInt(); - flow[IpSecTransform.DIRECTION_OUT].encryption = + mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt(); + mFlow[IpSecTransform.DIRECTION_OUT].mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - flow[IpSecTransform.DIRECTION_OUT].authentication = + mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - encapType = in.readInt(); - encapLocalPortResourceId = in.readInt(); - encapRemotePort = in.readInt(); + mEncapType = in.readInt(); + mEncapSocketResourceId = in.readInt(); + mEncapRemotePort = in.readInt(); } @Override public String toString() { StringBuilder strBuilder = new StringBuilder(); strBuilder - .append("{mode=") - .append(mode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") - .append(", localAddress=") - .append(localAddress) - .append(", remoteAddress=") - .append(remoteAddress) - .append(", network=") - .append(network) - .append(", encapType=") - .append(encapType) - .append(", encapLocalPortResourceId=") - .append(encapLocalPortResourceId) - .append(", encapRemotePort=") - .append(encapRemotePort) - .append(", nattKeepaliveInterval=") - .append(nattKeepaliveInterval) - .append(", flow[OUT]=") - .append(flow[IpSecTransform.DIRECTION_OUT]) - .append(", flow[IN]=") - .append(flow[IpSecTransform.DIRECTION_IN]) + .append("{mMode=") + .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") + .append(", mLocalAddress=") + .append(mLocalAddress) + .append(", mRemoteAddress=") + .append(mRemoteAddress) + .append(", mNetwork=") + .append(mNetwork) + .append(", mEncapType=") + .append(mEncapType) + .append(", mEncapSocketResourceId=") + .append(mEncapSocketResourceId) + .append(", mEncapRemotePort=") + .append(mEncapRemotePort) + .append(", mNattKeepaliveInterval=") + .append(mNattKeepaliveInterval) + .append(", mFlow[OUT]=") + .append(mFlow[IpSecTransform.DIRECTION_OUT]) + .append(", mFlow[IN]=") + .append(mFlow[IpSecTransform.DIRECTION_IN]) .append("}"); return strBuilder.toString(); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d7908c8cee..d7b325613f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -26,6 +26,8 @@ import android.os.RemoteException; import android.util.AndroidException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + import dalvik.system.CloseGuard; import java.io.FileDescriptor; @@ -188,7 +190,8 @@ public final class IpSecManager { } /** @hide */ - int getResourceId() { + @VisibleForTesting + public int getResourceId() { return mResourceId; } } @@ -489,7 +492,8 @@ public final class IpSecManager { } /** @hide */ - int getResourceId() { + @VisibleForTesting + public int getResourceId() { return mResourceId; } }; diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 62fd65b9c1..529cf1a495 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -68,10 +68,10 @@ public final class IpSecTransform implements AutoCloseable { public @interface TransformDirection {} /** @hide */ - public static final int MODE_TUNNEL = 0; + public static final int MODE_TRANSPORT = 0; /** @hide */ - public static final int MODE_TRANSPORT = 1; + public static final int MODE_TUNNEL = 1; /** @hide */ public static final int ENCAP_NONE = 0; @@ -113,7 +113,11 @@ public final class IpSecTransform implements AutoCloseable { return IIpSecService.Stub.asInterface(b); } - private void checkResultStatusAndThrow(int status) + /** + * Checks the result status and throws an appropriate exception if + * the status is not Status.OK. + */ + private void checkResultStatus(int status) throws IOException, IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException { switch (status) { @@ -141,7 +145,7 @@ public final class IpSecTransform implements AutoCloseable { IpSecTransformResponse result = svc.createTransportModeTransform(mConfig, new Binder()); int status = result.status; - checkResultStatusAndThrow(status); + checkResultStatus(status); mResourceId = result.resourceId; /* Keepalive will silently fail if not needed by the config; but, if needed and @@ -243,61 +247,20 @@ public final class IpSecTransform implements AutoCloseable { /* Package */ void startKeepalive(Context c) { - // FIXME: NO_KEEPALIVE needs to be a constant - if (mConfig.getNattKeepaliveInterval() == 0) { - return; - } - - ConnectivityManager cm = - (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); - - if (mKeepalive != null) { - Log.wtf(TAG, "Keepalive already started for this IpSecTransform."); - return; - } - - synchronized (mKeepaliveSyncLock) { - mKeepalive = - cm.startNattKeepalive( - mConfig.getNetwork(), - mConfig.getNattKeepaliveInterval(), - mKeepaliveCallback, - mConfig.getLocalAddress(), - 0x1234, /* FIXME: get the real port number again, - which we need to retrieve from the provided - EncapsulationSocket, and which isn't currently - stashed in IpSecConfig */ - mConfig.getRemoteAddress()); - try { - // FIXME: this is still a horrible way to fudge the synchronous callback - mKeepaliveSyncLock.wait(2000); - } catch (InterruptedException e) { - } - } - if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) { - throw new UnsupportedOperationException("Packet Keepalive cannot be started"); + if (mConfig.getNattKeepaliveInterval() != 0) { + Log.wtf(TAG, "Keepalive not yet supported."); } } - /* Package */ - int getResourceId() { + /** @hide */ + @VisibleForTesting + public int getResourceId() { return mResourceId; } /* Package */ void stopKeepalive() { - if (mKeepalive == null) { - return; - } - mKeepalive.stop(); - synchronized (mKeepaliveSyncLock) { - if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) { - try { - mKeepaliveSyncLock.wait(2000); - } catch (InterruptedException e) { - } - } - } + return; } /** @@ -323,7 +286,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].encryption = algo; + mConfig.setEncryption(direction, algo); return this; } @@ -338,7 +301,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.flow[direction].authentication = algo; + mConfig.setAuthentication(direction, algo); return this; } @@ -361,9 +324,7 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { - // TODO: convert to using the resource Id of the SPI. Then build() can validate - // the owner in the IpSecService - mConfig.flow[direction].spiResourceId = spi.getResourceId(); + mConfig.setSpiResourceId(direction, spi.getResourceId()); return this; } @@ -378,7 +339,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi public IpSecTransform.Builder setUnderlyingNetwork(Network net) { - mConfig.network = net; + mConfig.setNetwork(net); return this; } @@ -395,10 +356,9 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setIpv4Encapsulation( IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { - // TODO: check encap type is valid. - mConfig.encapType = ENCAP_ESPINUDP; - mConfig.encapLocalPortResourceId = localSocket.getResourceId(); - mConfig.encapRemotePort = remotePort; + mConfig.setEncapType(ENCAP_ESPINUDP); + mConfig.setEncapSocketResourceId(localSocket.getResourceId()); + mConfig.setEncapRemotePort(remotePort); return this; } @@ -416,7 +376,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) { - mConfig.nattKeepaliveInterval = intervalSeconds; + mConfig.setNattKeepaliveInterval(intervalSeconds); return this; } @@ -451,8 +411,8 @@ public final class IpSecTransform implements AutoCloseable { IpSecManager.SpiUnavailableException, IOException { //FIXME: argument validation here //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); - mConfig.mode = MODE_TRANSPORT; - mConfig.remoteAddress = remoteAddress; + mConfig.setMode(MODE_TRANSPORT); + mConfig.setRemoteAddress(remoteAddress.getHostAddress()); return new IpSecTransform(mContext, mConfig).activate(); } @@ -473,9 +433,9 @@ public final class IpSecTransform implements AutoCloseable { InetAddress localAddress, InetAddress remoteAddress) { //FIXME: argument validation here //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); - mConfig.localAddress = localAddress; - mConfig.remoteAddress = remoteAddress; - mConfig.mode = MODE_TUNNEL; + mConfig.setLocalAddress(localAddress.getHostAddress()); + mConfig.setRemoteAddress(remoteAddress.getHostAddress()); + mConfig.setMode(MODE_TUNNEL); return new IpSecTransform(mContext, mConfig); } @@ -489,14 +449,5 @@ public final class IpSecTransform implements AutoCloseable { mContext = context; mConfig = new IpSecConfig(); } - - /** - * Return an {@link IpSecConfig} object for testing purposes. - * @hide - */ - @VisibleForTesting - public IpSecConfig getIpSecConfig() { - return mConfig; - } } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 305683139f..555874c0e1 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -33,6 +33,7 @@ import android.net.IpSecSpiResponse; import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecUdpEncapResponse; +import android.net.NetworkUtils; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; @@ -42,11 +43,14 @@ import android.os.ServiceSpecificException; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.text.TextUtils; import android.util.Log; import android.util.Slog; import android.util.SparseArray; + import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; + import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -54,6 +58,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.concurrent.atomic.AtomicInteger; + import libcore.io.IoUtils; /** @hide */ @@ -252,7 +257,11 @@ public class IpSecService extends IIpSecService.Stub { return (mReferenceCount.get() > 0); } - public void checkOwnerOrSystemAndThrow() { + /** + * Ensures that the caller is either the owner of this resource or has the system UID and + * throws a SecurityException otherwise. + */ + public void checkOwnerOrSystem() { if (uid != Binder.getCallingUid() && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { throw new SecurityException("Only the owner may access managed resources!"); @@ -340,7 +349,7 @@ public class IpSecService extends IIpSecService.Stub { // The value should never be null unless the resource doesn't exist // (since we do not allow null resources to be added). if (val != null) { - val.checkOwnerOrSystemAndThrow(); + val.checkOwnerOrSystem(); } return val; } @@ -405,12 +414,8 @@ public class IpSecService extends IIpSecService.Stub { .ipSecDeleteSecurityAssociation( mResourceId, direction, - (mConfig.getLocalAddress() != null) - ? mConfig.getLocalAddress().getHostAddress() - : "", - (mConfig.getRemoteAddress() != null) - ? mConfig.getRemoteAddress().getHostAddress() - : "", + mConfig.getLocalAddress(), + mConfig.getRemoteAddress(), spi); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception @@ -638,11 +643,45 @@ public class IpSecService extends IIpSecService.Stub { } } + /** + * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be + * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. + */ + private static void checkInetAddress(String inetAddress) { + if (TextUtils.isEmpty(inetAddress)) { + throw new IllegalArgumentException("Unspecified address"); + } + + InetAddress checkAddr = NetworkUtils.numericToInetAddress(inetAddress); + + if (checkAddr.isAnyLocalAddress()) { + throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress); + } + } + + /** + * Checks the user-provided direction field and throws an IllegalArgumentException if it is not + * DIRECTION_IN or DIRECTION_OUT + */ + private static void checkDirection(int direction) { + switch (direction) { + case IpSecTransform.DIRECTION_OUT: + case IpSecTransform.DIRECTION_IN: + return; + } + throw new IllegalArgumentException("Invalid Direction: " + direction); + } + @Override /** Get a new SPI and maintain the reservation in the system server */ public synchronized IpSecSpiResponse reserveSecurityParameterIndex( int direction, String remoteAddress, int requestedSpi, IBinder binder) throws RemoteException { + checkDirection(direction); + checkInetAddress(remoteAddress); + /* requestedSpi can be anything in the int range, so no check is needed. */ + checkNotNull(binder, "Null Binder passed to reserveSecurityParameterIndex"); + int resourceId = mNextResourceId.getAndIncrement(); int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; @@ -651,9 +690,7 @@ public class IpSecService extends IIpSecService.Stub { try { if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) { return new IpSecSpiResponse( - IpSecManager.Status.RESOURCE_UNAVAILABLE, - INVALID_RESOURCE_ID, - spi); + IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } spi = mSrvConfig @@ -751,6 +788,8 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException( "Specified port number must be a valid non-reserved UDP port"); } + checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); + int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { @@ -791,6 +830,67 @@ public class IpSecService extends IIpSecService.Stub { releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); } + /** + * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an + * IllegalArgumentException if they are not. + */ + private void checkIpSecConfig(IpSecConfig config) { + if (config.getLocalAddress() == null) { + throw new IllegalArgumentException("Invalid null Local InetAddress"); + } + + if (config.getRemoteAddress() == null) { + throw new IllegalArgumentException("Invalid null Remote InetAddress"); + } + + switch (config.getMode()) { + case IpSecTransform.MODE_TRANSPORT: + if (!config.getLocalAddress().isEmpty()) { + throw new IllegalArgumentException("Non-empty Local Address"); + } + // Must be valid, and not a wildcard + checkInetAddress(config.getRemoteAddress()); + break; + case IpSecTransform.MODE_TUNNEL: + break; + default: + throw new IllegalArgumentException( + "Invalid IpSecTransform.mode: " + config.getMode()); + } + + switch (config.getEncapType()) { + case IpSecTransform.ENCAP_NONE: + break; + case IpSecTransform.ENCAP_ESPINUDP: + case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: + if (mUdpSocketRecords.get(config.getEncapSocketResourceId()) == null) { + throw new IllegalStateException( + "No Encapsulation socket for Resource Id: " + + config.getEncapSocketResourceId()); + } + + int port = config.getEncapRemotePort(); + if (port <= 0 || port > 0xFFFF) { + throw new IllegalArgumentException("Invalid remote UDP port: " + port); + } + break; + default: + throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); + } + + for (int direction : DIRECTIONS) { + IpSecAlgorithm crypt = config.getEncryption(direction); + IpSecAlgorithm auth = config.getAuthentication(direction); + if (crypt == null && auth == null) { + throw new IllegalArgumentException("Encryption and Authentication are both null"); + } + + if (mSpiRecords.get(config.getSpiResourceId(direction)) == null) { + throw new IllegalStateException("No SPI for specified Resource Id"); + } + } + } + /** * Create a transport mode transform, which represent two security associations (one in each * direction) in the kernel. The transform will be cached by the system server and must be freed @@ -801,17 +901,19 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized IpSecTransformResponse createTransportModeTransform( IpSecConfig c, IBinder binder) throws RemoteException { + checkIpSecConfig(c); + checkNotNull(binder, "Null Binder passed to createTransportModeTransform"); int resourceId = mNextResourceId.getAndIncrement(); if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; - // TODO: Basic input validation here since it's coming over the Binder + int encapType, encapLocalPort = 0, encapRemotePort = 0; UdpSocketRecord socketRecord = null; encapType = c.getEncapType(); if (encapType != IpSecTransform.ENCAP_NONE) { - socketRecord = mUdpSocketRecords.get(c.getEncapLocalResourceId()); + socketRecord = mUdpSocketRecords.get(c.getEncapSocketResourceId()); encapLocalPort = socketRecord.getPort(); encapRemotePort = c.getEncapRemotePort(); } @@ -823,20 +925,15 @@ public class IpSecService extends IIpSecService.Stub { spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); try { - mSrvConfig.getNetdInstance() + mSrvConfig + .getNetdInstance() .ipSecAddSecurityAssociation( resourceId, c.getMode(), direction, - (c.getLocalAddress() != null) - ? c.getLocalAddress().getHostAddress() - : "", - (c.getRemoteAddress() != null) - ? c.getRemoteAddress().getHostAddress() - : "", - (c.getNetwork() != null) - ? c.getNetwork().getNetworkHandle() - : 0, + c.getLocalAddress(), + c.getRemoteAddress(), + (c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, spi, (auth != null) ? auth.getName() : "", (auth != null) ? auth.getKey() : null, @@ -899,12 +996,8 @@ public class IpSecService extends IIpSecService.Stub { socket.getFileDescriptor(), resourceId, direction, - (c.getLocalAddress() != null) - ? c.getLocalAddress().getHostAddress() - : "", - (c.getRemoteAddress() != null) - ? c.getRemoteAddress().getHostAddress() - : "", + c.getLocalAddress(), + c.getRemoteAddress(), info.getSpiRecord(direction).getSpi()); } } catch (ServiceSpecificException e) { From ffc2fa53f59bb3ae23a87a3834565a358100f414 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 25 Sep 2017 19:33:13 -0700 Subject: [PATCH 0422/1150] Add equals() for IpSecAlgorithm and IpSecConfig Add equality testing methods to support tests for parceling and un-parceling IpSecConfig. Bug: 38397094 Test: runtest -x IpSecConfigTest.java Change-Id: I31e318334d39ed6e9daf5ec8f3be7dcec75e12ad --- core/java/android/net/IpSecAlgorithm.java | 17 ++++++++------ core/java/android/net/IpSecConfig.java | 27 +++++++++++++++++++++++ 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index ead406c20c..79310e295a 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -24,6 +24,7 @@ import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Arrays; /** * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to @@ -75,13 +76,7 @@ public final class IpSecAlgorithm implements Parcelable { public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; /** @hide */ - @StringDef({ - CRYPT_AES_CBC, - AUTH_HMAC_MD5, - AUTH_HMAC_SHA1, - AUTH_HMAC_SHA256, - AUTH_HMAC_SHA512 - }) + @StringDef({CRYPT_AES_CBC, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA512}) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -197,4 +192,12 @@ public final class IpSecAlgorithm implements Parcelable { .append("}") .toString(); } + + /** package */ + static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) { + if (lhs == null || rhs == null) return (lhs == rhs); + return (lhs.mName.equals(rhs.mName) + && Arrays.equals(lhs.mKey, rhs.mKey) + && lhs.mTruncLenBits == rhs.mTruncLenBits); + } }; diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 56224afc27..ceccc07c3c 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -62,6 +62,13 @@ public final class IpSecConfig implements Parcelable { .append("}") .toString(); } + + static boolean equals(IpSecConfig.Flow lhs, IpSecConfig.Flow rhs) { + if (lhs == null || rhs == null) return (lhs == rhs); + return (lhs.mSpiResourceId == rhs.mSpiResourceId + && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) + && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); + } } private final Flow[] mFlow = new Flow[] {new Flow(), new Flow()}; @@ -198,6 +205,7 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mEncapType); out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); + out.writeInt(mNattKeepaliveInterval); } @VisibleForTesting @@ -221,6 +229,7 @@ public final class IpSecConfig implements Parcelable { mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); + mNattKeepaliveInterval = in.readInt(); } @Override @@ -262,4 +271,22 @@ public final class IpSecConfig implements Parcelable { return new IpSecConfig[size]; } }; + + @VisibleForTesting + public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { + if (lhs == null || rhs == null) return (lhs == rhs); + return (lhs.mMode == rhs.mMode + && lhs.mLocalAddress.equals(rhs.mLocalAddress) + && lhs.mRemoteAddress.equals(rhs.mRemoteAddress) + && ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork)) + || (lhs.mNetwork == rhs.mNetwork)) + && lhs.mEncapType == rhs.mEncapType + && lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId + && lhs.mEncapRemotePort == rhs.mEncapRemotePort + && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval + && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_OUT], + rhs.mFlow[IpSecTransform.DIRECTION_OUT]) + && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_IN], + rhs.mFlow[IpSecTransform.DIRECTION_IN])); + } } From 71d62fd62392ce8a4e86e2d0d6ee7dc55d8c7be8 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 4 Oct 2017 12:58:55 -0700 Subject: [PATCH 0423/1150] Cosmetic Cleanups for IpSecService This is a follow-up CL to address comments on aosp/466677 -Rename ManagedResourceArray.get() -Comment cleanup Bug: 38397094 Test: runtest frameworks-net Change-Id: I6fbdd89c4a864fe1d8a19c68947f582d7b1f0f21 --- core/java/android/net/IpSecConfig.java | 3 ++- core/java/android/net/IpSecTransform.java | 2 -- .../java/com/android/server/IpSecService.java | 15 ++++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index ceccc07c3c..632b7fc07f 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -34,7 +34,7 @@ public final class IpSecConfig implements Parcelable { // Preventing this from being null simplifies Java->Native binder private String mRemoteAddress = ""; - // The underlying network interface that represents the "gateway" Network + // The underlying Network that represents the "gateway" Network // for outbound packets. It may also be used to select packets. private Network mNetwork; @@ -273,6 +273,7 @@ public final class IpSecConfig implements Parcelable { }; @VisibleForTesting + /** Equals method used for testing */ public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { if (lhs == null || rhs == null) return (lhs == rhs); return (lhs.mMode == rhs.mMode diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 529cf1a495..e15a2c672c 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -409,8 +409,6 @@ public final class IpSecTransform implements AutoCloseable { public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - //FIXME: argument validation here - //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); mConfig.setMode(MODE_TRANSPORT); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); return new IpSecTransform(mContext, mConfig).activate(); diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 555874c0e1..2e1f142a7d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -344,7 +344,7 @@ public class IpSecService extends IIpSecService.Stub { private class ManagedResourceArray { SparseArray mArray = new SparseArray<>(); - T get(int key) { + T getAndCheckOwner(int key) { T val = mArray.get(key); // The value should never be null unless the resource doesn't exist // (since we do not allow null resources to be added). @@ -723,7 +723,7 @@ public class IpSecService extends IIpSecService.Stub { throws RemoteException { // We want to non-destructively get so that we can check credentials before removing // this from the records. - T record = resArray.get(resourceId); + T record = resArray.getAndCheckOwner(resourceId); if (record == null) { throw new IllegalArgumentException( @@ -863,7 +863,8 @@ public class IpSecService extends IIpSecService.Stub { break; case IpSecTransform.ENCAP_ESPINUDP: case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: - if (mUdpSocketRecords.get(config.getEncapSocketResourceId()) == null) { + if (mUdpSocketRecords.getAndCheckOwner( + config.getEncapSocketResourceId()) == null) { throw new IllegalStateException( "No Encapsulation socket for Resource Id: " + config.getEncapSocketResourceId()); @@ -885,7 +886,7 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Encryption and Authentication are both null"); } - if (mSpiRecords.get(config.getSpiResourceId(direction)) == null) { + if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) { throw new IllegalStateException("No SPI for specified Resource Id"); } } @@ -913,7 +914,7 @@ public class IpSecService extends IIpSecService.Stub { UdpSocketRecord socketRecord = null; encapType = c.getEncapType(); if (encapType != IpSecTransform.ENCAP_NONE) { - socketRecord = mUdpSocketRecords.get(c.getEncapSocketResourceId()); + socketRecord = mUdpSocketRecords.getAndCheckOwner(c.getEncapSocketResourceId()); encapLocalPort = socketRecord.getPort(); encapRemotePort = c.getEncapRemotePort(); } @@ -922,7 +923,7 @@ public class IpSecService extends IIpSecService.Stub { IpSecAlgorithm auth = c.getAuthentication(direction); IpSecAlgorithm crypt = c.getEncryption(direction); - spis[direction] = mSpiRecords.get(c.getSpiResourceId(direction)); + spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); try { mSrvConfig @@ -976,7 +977,7 @@ public class IpSecService extends IIpSecService.Stub { // Synchronize liberally here because we are using ManagedResources in this block TransformRecord info; // FIXME: this code should be factored out into a security check + getter - info = mTransformRecords.get(resourceId); + info = mTransformRecords.getAndCheckOwner(resourceId); if (info == null) { throw new IllegalArgumentException("Transform " + resourceId + " is not active"); From be4309663578d49babb43435e1288584b365be30 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 22 Aug 2017 21:42:33 -0700 Subject: [PATCH 0424/1150] Add support for AES-GCM-ESP as an IPSec algorithm Allows native AES-GCM-ESP to be used as an IPSec transport/tunnel mode algorithm with kernel support Bug: 63589918 Test: IPsecService tests added, existing ones pass Change-Id: Ie1a9a902be205f269aa37bf956198f2e5b177c21 --- core/java/android/net/IpSecAlgorithm.java | 24 ++++++++++++++--- core/java/android/net/IpSecConfig.java | 20 ++++++++++++++ core/java/android/net/IpSecTransform.java | 27 +++++++++++++++++++ .../java/com/android/server/IpSecService.java | 14 ++++++++-- 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 79310e295a..16b1452311 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -31,7 +31,6 @@ import java.util.Arrays; * RFC 4301. */ public final class IpSecAlgorithm implements Parcelable { - /** * AES-CBC Encryption/Ciphering Algorithm. * @@ -68,6 +67,7 @@ public final class IpSecAlgorithm implements Parcelable { *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; + /** * SHA512 HMAC Authentication/Integrity Algorithm * @@ -75,8 +75,24 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; + /** + * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. + * + *

            Valid lengths for this key are {128, 192, 256}. + * + *

            Valid ICV (truncation) lengths are {64, 96, 128}. + */ + public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + /** @hide */ - @StringDef({CRYPT_AES_CBC, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA512}) + @StringDef({ + CRYPT_AES_CBC, + AUTH_HMAC_MD5, + AUTH_HMAC_SHA1, + AUTH_HMAC_SHA256, + AUTH_HMAC_SHA512, + AUTH_CRYPT_AES_GCM + }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} @@ -102,7 +118,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algoName precise name of the algorithm to be used. * @param key non-null Key padded to a multiple of 8 bits. * @param truncLenBits the number of bits of output hash to use; only meaningful for - * Authentication. + * Authentication or Authenticated Encryption (equivalent to ICV length). */ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) { if (!isTruncationLengthValid(algoName, truncLenBits)) { @@ -175,6 +191,8 @@ public final class IpSecAlgorithm implements Parcelable { return (truncLenBits >= 192 && truncLenBits <= 384); case AUTH_HMAC_SHA512: return (truncLenBits >= 256 && truncLenBits <= 512); + case AUTH_CRYPT_AES_GCM: + return (truncLenBits == 64 || truncLenBits == 96 || truncLenBits == 128); default: return false; } diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 632b7fc07f..61b13a922d 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -50,6 +50,9 @@ public final class IpSecConfig implements Parcelable { // Authentication Algorithm private IpSecAlgorithm mAuthentication; + // Authenticated Encryption Algorithm + private IpSecAlgorithm mAuthenticatedEncryption; + @Override public String toString() { return new StringBuilder() @@ -59,6 +62,8 @@ public final class IpSecConfig implements Parcelable { .append(mEncryption) .append(", mAuthentication=") .append(mAuthentication) + .append(", mAuthenticatedEncryption=") + .append(mAuthenticatedEncryption) .append("}") .toString(); } @@ -118,6 +123,11 @@ public final class IpSecConfig implements Parcelable { mFlow[direction].mAuthentication = authentication; } + /** Set the authenticated encryption algorithm for a given direction */ + public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) { + mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption; + } + public void setNetwork(Network network) { mNetwork = network; } @@ -163,6 +173,10 @@ public final class IpSecConfig implements Parcelable { return mFlow[direction].mAuthentication; } + public IpSecAlgorithm getAuthenticatedEncryption(int direction) { + return mFlow[direction].mAuthenticatedEncryption; + } + public Network getNetwork() { return mNetwork; } @@ -199,9 +213,11 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags); out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags); out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags); + out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags); out.writeInt(mEncapType); out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); @@ -221,11 +237,15 @@ public final class IpSecConfig implements Parcelable { (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt(); mFlow[IpSecTransform.DIRECTION_OUT].mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption = + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index e15a2c672c..48b5bd5c3d 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -281,6 +281,8 @@ public final class IpSecTransform implements AutoCloseable { *

            If encryption is set for a given direction without also providing an SPI for that * direction, creation of an IpSecTransform will fail upon calling a build() method. * + *

            Authenticated encryption is mutually exclusive with encryption and authentication. + * * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ @@ -296,6 +298,8 @@ public final class IpSecTransform implements AutoCloseable { *

            If authentication is set for a given direction without also providing an SPI for that * direction, creation of an IpSecTransform will fail upon calling a build() method. * + *

            Authenticated encryption is mutually exclusive with encryption and authentication. + * * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ @@ -305,6 +309,29 @@ public final class IpSecTransform implements AutoCloseable { return this; } + /** + * Add an authenticated encryption algorithm to the transform for the given direction. + * + *

            If an authenticated encryption algorithm is set for a given direction without also + * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling + * a build() method. + * + *

            The Authenticated Encryption (AE) class of algorithms are also known as Authenticated + * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as + * referred to in RFC 4301) + * + *

            Authenticated encryption is mutually exclusive with encryption and authentication. + * + * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to + * be applied. + */ + public IpSecTransform.Builder setAuthenticatedEncryption( + @TransformDirection int direction, IpSecAlgorithm algo) { + mConfig.setAuthenticatedEncryption(direction, algo); + return this; + } + /** * Set the SPI, which uniquely identifies a particular IPsec session from others. Because * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2e1f142a7d..cf1d33c861 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -882,8 +882,14 @@ public class IpSecService extends IIpSecService.Stub { for (int direction : DIRECTIONS) { IpSecAlgorithm crypt = config.getEncryption(direction); IpSecAlgorithm auth = config.getAuthentication(direction); - if (crypt == null && auth == null) { - throw new IllegalArgumentException("Encryption and Authentication are both null"); + IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction); + if (authenticatedEncryption == null && crypt == null && auth == null) { + throw new IllegalArgumentException( + "No Encryption or Authentication algorithms specified"); + } else if (authenticatedEncryption != null && (auth != null || crypt != null)) { + throw new IllegalArgumentException( + "Authenticated Encryption is mutually" + + " exclusive with other Authentication or Encryption algorithms"); } if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) { @@ -922,6 +928,7 @@ public class IpSecService extends IIpSecService.Stub { for (int direction : DIRECTIONS) { IpSecAlgorithm auth = c.getAuthentication(direction); IpSecAlgorithm crypt = c.getEncryption(direction); + IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction); spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction)); int spi = spis[direction].getSpi(); @@ -942,6 +949,9 @@ public class IpSecService extends IIpSecService.Stub { (crypt != null) ? crypt.getName() : "", (crypt != null) ? crypt.getKey() : null, (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : null, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, encapType, encapLocalPort, encapRemotePort); From 0225c3c6d14a574527df3bd869075f27cc61fe41 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 10 Oct 2017 20:44:28 -0700 Subject: [PATCH 0425/1150] Return a port from bindToPort() in IpSecService When binding to a random port, the port number was not being returned, so the user is incorrectly receiving a port of zero. Return the port number that was ultimately bound. Bug: 67662580 Test: Ran CTS test on aosp_angler-eng Change-Id: I22f4e5cdc83d43dc453788889990feb34e451bd3 --- services/core/java/com/android/server/IpSecService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2e1f142a7d..3d54ee6b6e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -754,7 +754,7 @@ public class IpSecService extends IIpSecService.Stub { * and re-binding, during which the system could *technically* hand that port out to someone * else. */ - private void bindToRandomPort(FileDescriptor sockFd) throws IOException { + private int bindToRandomPort(FileDescriptor sockFd) throws IOException { for (int i = MAX_PORT_BIND_ATTEMPTS; i > 0; i--) { try { FileDescriptor probeSocket = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -763,7 +763,7 @@ public class IpSecService extends IIpSecService.Stub { Os.close(probeSocket); Log.v(TAG, "Binding to port " + port); Os.bind(sockFd, INADDR_ANY, port); - return; + return port; } catch (ErrnoException e) { // Someone miraculously claimed the port just after we closed probeSocket. if (e.errno == OsConstants.EADDRINUSE) { @@ -803,7 +803,7 @@ public class IpSecService extends IIpSecService.Stub { Log.v(TAG, "Binding to port " + port); Os.bind(sockFd, INADDR_ANY, port); } else { - bindToRandomPort(sockFd); + port = bindToRandomPort(sockFd); } // This code is common to both the unspecified and specified port cases Os.setsockoptInt( From dae8417c18253100849b25083df262008f096612 Mon Sep 17 00:00:00 2001 From: Manoj Boopathi Raj Date: Thu, 26 Oct 2017 11:49:02 -0700 Subject: [PATCH 0426/1150] Fixed NullPointerException in IpSecService-Netd binder layer Replaced null with empty byte array in createTransportModeTransform for null auth.getKey, crypt.getKey() and authCrypt.getKey() Test: Ran CTS test Bug: 68052730 Change-Id: I5110b1297b4bfbb5766e8ecfd3d64f8110b52945 --- services/core/java/com/android/server/IpSecService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a139ac4f3f..1154fbe609 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -944,13 +944,13 @@ public class IpSecService extends IIpSecService.Stub { (c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, spi, (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : null, + (auth != null) ? auth.getKey() : new byte[] {}, (auth != null) ? auth.getTruncationLengthBits() : 0, (crypt != null) ? crypt.getName() : "", - (crypt != null) ? crypt.getKey() : null, + (crypt != null) ? crypt.getKey() : new byte[] {}, (crypt != null) ? crypt.getTruncationLengthBits() : 0, (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : null, + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, encapType, encapLocalPort, From 1c09bde6ad24b7bee76c99ae0b8894644196f87a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 27 Oct 2017 17:22:59 -0600 Subject: [PATCH 0427/1150] Define NOT_ROAMING network capability. The "roaming" state of a network really belongs on NetworkCapabilities instead of being published through NetworkInfo.isRoaming(). One major reason is to support developers creating NetworkRequests for a non-roaming network. Watch for any capability changes that network statistics are interested in (either metered or roaming) and notify it to perform an update pass; fixes bug where we previously only triggered on roaming changes. Fix bug in VPNs where metered/roaming capabilities of underlying networks weren't being propagated; this was probably preventing some jobs from running over unmetered networks, and causing other jobs to run over roaming networks! Also passes along link bandwidth information from underlying networks, and propegates any changes to underlying networks. Fix race condition by reading prevNc inside lock. Utility methods correctly calculate min/max link bandwidth values. Test: bit FrameworksNetTests:android.net.,com.android.server.net.,com.android.server.connectivity.,com.android.server.ConnectivityServiceTest Bug: 68397798, 16207332 Change-Id: I3e1a6544c902bf3a79356b72d3616af1fd2b0f49 --- core/java/android/net/NetworkIdentity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 0775bdaaf3..df404b7dce 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -189,7 +189,8 @@ public class NetworkIdentity implements Comparable { String subscriberId = null; String networkId = null; - boolean roaming = false; + boolean roaming = !state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); boolean metered = !state.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); @@ -203,7 +204,6 @@ public class NetworkIdentity implements Comparable { } subscriberId = state.subscriberId; - roaming = state.networkInfo.isRoaming(); } else if (type == TYPE_WIFI) { if (state.networkId != null) { From debeb8779d2257a1c9ed47d34bcb7553e7886f09 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 1 Nov 2017 17:14:25 -0700 Subject: [PATCH 0428/1150] Update documentation for AES-GCM-ESP keymat length Added notes that keymat length must include 32 bits of salt. Bug: 68672051 Test: Frameworks-net unit tests & IpSecManager CTS tests run Change-Id: I0ae0c5be8a45b2374783b3bd1fa8bf930f15e687 --- core/java/android/net/IpSecAlgorithm.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 16b1452311..64f8f39e2b 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -78,7 +78,11 @@ public final class IpSecAlgorithm implements Parcelable { /** * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. * - *

            Valid lengths for this key are {128, 192, 256}. + *

            Valid lengths for keying material are {160, 224, 288}. + * + *

            As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key + * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per + * invocation with the same key. * *

            Valid ICV (truncation) lengths are {64, 96, 128}. */ From 8d88a143924b808ac72fdda0073d29bff3319259 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 7 Nov 2017 17:17:45 -0800 Subject: [PATCH 0429/1150] Fix signature for finalize() to resolve API Lint error The API linter on goog/master noticed that this method is listed in the public API even though it's protected. The change is probably related to a signature change from the internal finalize method which throws a Throwable. Fix the method in IpSecManager to throw Throwable, which should fix the current.txt and resolve the lint error. Bug: 69006767 Test: compilation, make update-api Change-Id: I173d014baaa505c365b7916fcb52f2a8b4af9373 --- core/java/android/net/IpSecManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d7b325613f..eccd5f47f2 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -136,7 +136,7 @@ public final class IpSecManager { } @Override - protected void finalize() { + protected void finalize() throws Throwable { if (mCloseGuard != null) { mCloseGuard.warnIfOpen(); } From 92ea134c15512137b9e7f9a0a097f4202c3fe547 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Thu, 9 Nov 2017 15:22:59 +0000 Subject: [PATCH 0430/1150] Hide NetworkStatsFactory class Test: Able to compile Change-Id: I37f385c773120405c437643b5de406772a684dcd --- core/java/com/android/internal/net/NetworkStatsFactory.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 3d3e148fb3..5eda81baa3 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -43,6 +43,8 @@ import java.util.Objects; /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} * files as needed. + * + * @hide */ public class NetworkStatsFactory { private static final String TAG = "NetworkStatsFactory"; From 745d586d48be8e72b384f53eced19b5f21d0c4cc Mon Sep 17 00:00:00 2001 From: Jonathan Basseri Date: Fri, 21 Apr 2017 15:53:51 -0700 Subject: [PATCH 0431/1150] Javadoc cleanup of IpSecManager API. This changes only comments and annotations, which results in minor API changes. Bug: 63777932 Test: `make update-api` and visually inspect generated HTML. Change-Id: I7a7a9244eade6cc55aca17a47e0a838cd6f84cc9 --- core/java/android/net/IpSecAlgorithm.java | 62 ++--- core/java/android/net/IpSecConfig.java | 10 +- core/java/android/net/IpSecManager.java | 272 ++++++++++++++-------- core/java/android/net/IpSecTransform.java | 177 +++++++------- 4 files changed, 299 insertions(+), 222 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 64f8f39e2b..d6e62cf1f8 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -15,6 +15,7 @@ */ package android.net; +import android.annotation.NonNull; import android.annotation.StringDef; import android.os.Build; import android.os.Parcel; @@ -27,8 +28,10 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to - * RFC 4301. + * This class represents a single algorithm that can be used by an {@link IpSecTransform}. + * + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ public final class IpSecAlgorithm implements Parcelable { /** @@ -39,16 +42,16 @@ public final class IpSecAlgorithm implements Parcelable { public static final String CRYPT_AES_CBC = "cbc(aes)"; /** - * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new - * applications and is provided for legacy compatibility with 3gpp infrastructure. + * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in + * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ public static final String AUTH_HMAC_MD5 = "hmac(md5)"; /** - * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in - * new applications and is provided for legacy compatibility with 3gpp infrastructure. + * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in + * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. */ @@ -69,7 +72,7 @@ public final class IpSecAlgorithm implements Parcelable { public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; /** - * SHA512 HMAC Authentication/Integrity Algorithm + * SHA512 HMAC Authentication/Integrity Algorithm. * *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ @@ -80,9 +83,9 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Valid lengths for keying material are {160, 224, 288}. * - *

            As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key - * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per - * invocation with the same key. + *

            As per RFC4106 (Section + * 8.1), keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit + * salt. RFC compliance requires that the salt must be unique per invocation with the same key. * *

            Valid ICV (truncation) lengths are {64, 96, 128}. */ @@ -105,48 +108,47 @@ public final class IpSecAlgorithm implements Parcelable { private final int mTruncLenBits; /** - * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the - * algorithm + * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are + * defined as constants in this class. * - * @param algorithm type for IpSec. - * @param key non-null Key padded to a multiple of 8 bits. + * @param algorithm name of the algorithm. + * @param key key padded to a multiple of 8 bits. */ - public IpSecAlgorithm(String algorithm, byte[] key) { + public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) { this(algorithm, key, key.length * 8); } /** - * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the - * algorithm + * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are + * defined as constants in this class. * - * @param algoName precise name of the algorithm to be used. - * @param key non-null Key padded to a multiple of 8 bits. - * @param truncLenBits the number of bits of output hash to use; only meaningful for - * Authentication or Authenticated Encryption (equivalent to ICV length). + *

            This constructor only supports algorithms that use a truncation length. i.e. + * Authentication and Authenticated Encryption algorithms. + * + * @param algorithm name of the algorithm. + * @param key key padded to a multiple of 8 bits. + * @param truncLenBits number of bits of output hash to use. */ - public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) { - if (!isTruncationLengthValid(algoName, truncLenBits)) { + public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { + if (!isTruncationLengthValid(algorithm, truncLenBits)) { throw new IllegalArgumentException("Unknown algorithm or invalid length"); } - mName = algoName; + mName = algorithm; mKey = key.clone(); mTruncLenBits = Math.min(truncLenBits, key.length * 8); } - /** Retrieve the algorithm name */ + /** Get the algorithm name */ public String getName() { return mName; } - /** Retrieve the key for this algorithm */ + /** Get the key for this algorithm */ public byte[] getKey() { return mKey.clone(); } - /** - * Retrieve the truncation length, in bits, for the key in this algo. By default this will be - * the length in bits of the key. - */ + /** Get the truncation length of this algorithm, in bits */ public int getTruncationLengthBits() { return mTruncLenBits; } diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 61b13a922d..e6cd3fc130 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -20,7 +20,12 @@ import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; -/** @hide */ +/** + * This class encapsulates all the configuration parameters needed to create IPsec transforms and + * policies. + * + * @hide + */ public final class IpSecConfig implements Parcelable { private static final String TAG = "IpSecConfig"; @@ -38,6 +43,9 @@ public final class IpSecConfig implements Parcelable { // for outbound packets. It may also be used to select packets. private Network mNetwork; + /** + * This class captures the parameters that specifically apply to inbound or outbound traffic. + */ public static class Flow { // Minimum requirements for identifying a transform // SPI identifying the IPsec flow in packet processing diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index eccd5f47f2..a9e60ec88a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; @@ -37,22 +38,28 @@ import java.net.InetAddress; import java.net.Socket; /** - * This class contains methods for managing IPsec sessions, which will perform kernel-space - * encryption and decryption of socket or Network traffic. + * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply + * confidentiality (encryption) and integrity (authentication) to IP traffic. * - *

            An IpSecManager may be obtained by calling {@link - * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link - * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE} + *

            Note that not all aspects of IPsec are permitted by this API. Applications may create + * transport mode security associations and apply them to individual sockets. Applications looking + * to create a VPN should use {@link VpnService}. + * + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ @SystemService(Context.IPSEC_SERVICE) public final class IpSecManager { private static final String TAG = "IpSecManager"; /** - * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index. + * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * *

            No IPsec packet may contain an SPI of 0. + * + * @hide */ + @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** @hide */ @@ -66,10 +73,12 @@ public final class IpSecManager { public static final int INVALID_RESOURCE_ID = 0; /** - * Indicates that the combination of remote InetAddress and SPI was non-unique for a given - * request. If encountered, selection of a new SPI is required before a transform may be - * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random - * or reserved using reserveSecurityParameterIndex. + * Thrown to indicate that a requested SPI is in use. + * + *

            The combination of remote {@code InetAddress} and SPI must be unique across all apps on + * one device. If this error is encountered, a new SPI is required before a transform may be + * created. This error can be avoided by calling {@link + * IpSecManager#reserveSecurityParameterIndex}. */ public static final class SpiUnavailableException extends AndroidException { private final int mSpi; @@ -78,24 +87,26 @@ public final class IpSecManager { * Construct an exception indicating that a transform with the given SPI is already in use * or otherwise unavailable. * - * @param msg Description indicating the colliding SPI + * @param msg description indicating the colliding SPI * @param spi the SPI that could not be used due to a collision */ SpiUnavailableException(String msg, int spi) { - super(msg + "(spi: " + spi + ")"); + super(msg + " (spi: " + spi + ")"); mSpi = spi; } - /** Retrieve the SPI that caused a collision */ + /** Get the SPI that caused a collision. */ public int getSpi() { return mSpi; } } /** - * Indicates that the requested system resource for IPsec, such as a socket or other system - * resource is unavailable. If this exception is thrown, try releasing allocated objects of the - * type requested. + * Thrown to indicate that an IPsec resource is unavailable. + * + *

            This could apply to resources such as sockets, {@link SecurityParameterIndex}, {@link + * IpSecTransform}, or other system resources. If this exception is thrown, users should release + * allocated objects of the type requested. */ public static final class ResourceUnavailableException extends AndroidException { @@ -106,6 +117,13 @@ public final class IpSecManager { private final IIpSecService mService; + /** + * This class represents a reserved SPI. + * + *

            Objects of this type are used to track reserved security parameter indices. They can be + * obtained by calling {@link IpSecManager#reserveSecurityParameterIndex} and must be released + * by calling {@link #close()} when they are no longer needed. + */ public static final class SecurityParameterIndex implements AutoCloseable { private final IIpSecService mService; private final InetAddress mRemoteAddress; @@ -113,7 +131,7 @@ public final class IpSecManager { private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId; - /** Return the underlying SPI held by this object */ + /** Get the underlying SPI held by this object. */ public int getSpi() { return mSpi; } @@ -135,6 +153,7 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the SPI was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -197,13 +216,13 @@ public final class IpSecManager { } /** - * Reserve an SPI for traffic bound towards the specified remote address. + * Reserve a random SPI for traffic bound to or from the specified remote address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user @@ -223,17 +242,18 @@ public final class IpSecManager { } /** - * Reserve an SPI for traffic bound towards the specified remote address. + * Reserve the requested SPI for traffic bound to or from the specified remote address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. + * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI * @return the reserved SecurityParameterIndex * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated * for this user + * @throws SpiUnavailableException indicating that the requested SPI could not be reserved */ public SecurityParameterIndex reserveSecurityParameterIndex( int direction, InetAddress remoteAddress, int requestedSpi) @@ -245,16 +265,28 @@ public final class IpSecManager { } /** - * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec - * encapsulation of the traffic flowing between the socket and the remote InetAddress of that - * transform. For security reasons, attempts to send traffic to any IP address other than the - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(Socket, IpSecTransform)}; + * Apply an IPsec transform to a stream socket. + * + *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *

            For security reasons, the destination address of any traffic on the socket must match the + * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any + * other IP address will result in an IOException. In addition, reads and writes on the socket + * will throw IOException if the user deactivates the transform (by calling {@link + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * + *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform + * will be removed. However, inbound traffic on the old transform will continue to be decrypted + * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap + * allows rekey procedures where both transforms are valid until both endpoints are using the + * new transform and all in-flight packets have been received. * * @param socket a stream socket - * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + * @param transform a transport mode {@code IpSecTransform} + * @throws IOException indicating that the transform could not be applied * @hide */ public void applyTransportModeTransform(Socket socket, IpSecTransform transform) @@ -265,16 +297,28 @@ public final class IpSecManager { } /** - * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec - * encapsulation of the traffic flowing between the socket and the remote InetAddress of that - * transform. For security reasons, attempts to send traffic to any IP address other than the - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(DatagramSocket, IpSecTransform)}; + * Apply an IPsec transform to a datagram socket. + * + *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *

            For security reasons, the destination address of any traffic on the socket must match the + * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any + * other IP address will result in an IOException. In addition, reads and writes on the socket + * will throw IOException if the user deactivates the transform (by calling {@link + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * + *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform + * will be removed. However, inbound traffic on the old transform will continue to be decrypted + * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap + * allows rekey procedures where both transforms are valid until both endpoints are using the + * new transform and all in-flight packets have been received. * * @param socket a datagram socket - * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + * @param transform a transport mode {@code IpSecTransform} + * @throws IOException indicating that the transform could not be applied * @hide */ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) @@ -285,16 +329,28 @@ public final class IpSecManager { } /** - * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec - * encapsulation of the traffic flowing between the socket and the remote InetAddress of that - * transform. For security reasons, attempts to send traffic to any IP address other than the - * address associated with that transform will throw an IOException. In addition, if the - * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to - * send() or receive() until the transform is removed from the socket by calling {@link - * #removeTransportModeTransform(FileDescriptor, IpSecTransform)}; + * Apply an IPsec transform to a socket. + * + *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the + * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When + * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * unprotected traffic can resume on that socket. + * + *

            For security reasons, the destination address of any traffic on the socket must match the + * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any + * other IP address will result in an IOException. In addition, reads and writes on the socket + * will throw IOException if the user deactivates the transform (by calling {@link + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * + *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform + * will be removed. However, inbound traffic on the old transform will continue to be decrypted + * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap + * allows rekey procedures where both transforms are valid until both endpoints are using the + * new transform and all in-flight packets have been received. * * @param socket a socket file descriptor - * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. + * @param transform a transport mode {@code IpSecTransform} + * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) throws IOException { @@ -323,6 +379,7 @@ public final class IpSecManager { * Applications should probably not use this API directly. Instead, they should use {@link * VpnService} to provide VPN capability in a more generic fashion. * + * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. * @param net a {@link Network} that will be tunneled via IP Sec. * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @hide @@ -330,14 +387,19 @@ public final class IpSecManager { public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} /** - * Remove a transform from a given stream socket. Once removed, traffic on the socket will not - * be encypted. This allows sockets that have been used for IPsec to be reclaimed for - * communication in the clear in the event socket reuse is desired. This operation will succeed - * regardless of the underlying state of a transform. If a transform is removed, communication - * on all sockets to which that transform was applied will fail until this method is called. + * Remove an IPsec transform from a stream socket. * - * @param socket a socket that previously had a transform applied to it. + *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed + * regardless of the state of the transform. Removing a transform from a socket allows the + * socket to be reused for communication in the clear. + * + *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling + * {@link IpSecTransform#close()}, then communication on the socket will fail until this method + * is called. + * + * @param socket a socket that previously had a transform applied to it * @param transform the IPsec Transform that was previously applied to the given socket + * @throws IOException indicating that the transform could not be removed from the socket * @hide */ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) @@ -348,14 +410,19 @@ public final class IpSecManager { } /** - * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not - * be encypted. This allows sockets that have been used for IPsec to be reclaimed for - * communication in the clear in the event socket reuse is desired. This operation will succeed - * regardless of the underlying state of a transform. If a transform is removed, communication - * on all sockets to which that transform was applied will fail until this method is called. + * Remove an IPsec transform from a datagram socket. * - * @param socket a socket that previously had a transform applied to it. + *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed + * regardless of the state of the transform. Removing a transform from a socket allows the + * socket to be reused for communication in the clear. + * + *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling + * {@link IpSecTransform#close()}, then communication on the socket will fail until this method + * is called. + * + * @param socket a socket that previously had a transform applied to it * @param transform the IPsec Transform that was previously applied to the given socket + * @throws IOException indicating that the transform could not be removed from the socket * @hide */ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) @@ -366,14 +433,19 @@ public final class IpSecManager { } /** - * Remove a transform from a given stream socket. Once removed, traffic on the socket will not - * be encypted. This allows sockets that have been used for IPsec to be reclaimed for - * communication in the clear in the event socket reuse is desired. This operation will succeed - * regardless of the underlying state of a transform. If a transform is removed, communication - * on all sockets to which that transform was applied will fail until this method is called. + * Remove an IPsec transform from a socket. * - * @param socket a socket file descriptor that previously had a transform applied to it. + *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed + * regardless of the state of the transform. Removing a transform from a socket allows the + * socket to be reused for communication in the clear. + * + *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling + * {@link IpSecTransform#close()}, then communication on the socket will fail until this method + * is called. + * + * @param socket a socket that previously had a transform applied to it * @param transform the IPsec Transform that was previously applied to the given socket + * @throws IOException indicating that the transform could not be removed from the socket */ public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) throws IOException { @@ -382,7 +454,7 @@ public final class IpSecManager { } } - /* Call down to activate a transform */ + /* Call down to remove a transform */ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { try { mService.removeTransportModeTransform(pfd, transform.getResourceId()); @@ -397,6 +469,7 @@ public final class IpSecManager { * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is * lost, all traffic will drop. * + * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. * @param net a network that currently has transform applied to it. * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given * network @@ -405,11 +478,18 @@ public final class IpSecManager { public void removeTunnelModeTransform(Network net, IpSecTransform transform) {} /** - * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for - * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic. + * This class provides access to a UDP encapsulation Socket. * - *

            The socket provided by this class cannot be re-bound or closed via the inner - * FileDescriptor. Instead, disposing of this socket requires a call to close(). + *

            {@code UdpEncapsulationSocket} wraps a system-provided datagram socket intended for IKEv2 + * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link + * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the + * caller. The caller should not close the {@code FileDescriptor} returned by {@link + * #getSocket}, but should use {@link #close} instead. + * + *

            Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic + * of the next user who binds to that port. To prevent this scenario, these sockets are held + * open by the system so that they may only be closed by calling {@link #close} or when the user + * process exits. */ public static final class UdpEncapsulationSocket implements AutoCloseable { private final ParcelFileDescriptor mPfd; @@ -443,7 +523,7 @@ public final class IpSecManager { mCloseGuard.open("constructor"); } - /** Access the inner UDP Encapsulation Socket */ + /** Get the wrapped socket. */ public FileDescriptor getSocket() { if (mPfd == null) { return null; @@ -451,22 +531,19 @@ public final class IpSecManager { return mPfd.getFileDescriptor(); } - /** Retrieve the port number of the inner encapsulation socket */ + /** Get the bound port of the wrapped socket. */ public int getPort() { return mPort; } - @Override /** - * Release the resources that have been reserved for this Socket. + * Close this socket. * - *

            This method closes the underlying socket, reducing a user's allocated sockets in the - * system. This must be done as part of cleanup following use of a socket. Failure to do so - * will cause the socket to count against a total allocation limit for IpSec and eventually - * fail due to resource limits. - * - * @param fd a file descriptor previously returned as a UDP Encapsulation socket. + *

            This closes the wrapped socket. Open encapsulation sockets count against a user's + * resource limits, and forgetting to close them eventually will result in {@link + * ResourceUnavailableException} being thrown. */ + @Override public void close() throws IOException { try { mService.closeUdpEncapsulationSocket(mResourceId); @@ -483,6 +560,7 @@ public final class IpSecManager { mCloseGuard.close(); } + /** Check that the socket was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -499,21 +577,14 @@ public final class IpSecManager { }; /** - * Open a socket that is bound to a free UDP port on the system. + * Open a socket for UDP encapsulation and bind to the given port. * - *

            By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by - * the caller. This provides safe access to a socket on a port that can later be used as a UDP - * Encapsulation port. + *

            See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. * - *

            This socket reservation works in conjunction with IpSecTransforms, which may re-use the - * socket port. Explicitly opening this port is only necessary if communication is desired on - * that port. - * - * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this - * method will bind to the specified port or fail. To retrieve the port number, call {@link - * android.system.Os#getsockname(FileDescriptor)}. - * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime - * of the object. + * @param port a local UDP port + * @return a socket that is bound to the given port + * @throws IOException indicating that the socket could not be opened or bound + * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open */ // Returning a socket in this fashion that has been created and bound by the system // is the only safe way to ensure that a socket is both accessible to the user and @@ -533,17 +604,16 @@ public final class IpSecManager { } /** - * Open a socket that is bound to a port selected by the system. + * Open a socket for UDP encapsulation. * - *

            By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by - * the caller. This provides safe access to a socket on a port that can later be used as a UDP - * Encapsulation port. + *

            See {@link UdpEncapsulationSocket} for the proper way to close the returned socket. * - *

            This socket reservation works in conjunction with IpSecTransforms, which may re-use the - * socket port. Explicitly opening this port is only necessary if communication is desired on - * that port. + *

            The local port of the returned socket can be obtained by calling {@link + * UdpEncapsulationSocket#getPort()}. * - * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port + * @return a socket that is bound to a local port + * @throws IOException indicating that the socket could not be opened or bound + * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open */ // Returning a socket in this fashion that has been created and bound by the system // is the only safe way to ensure that a socket is both accessible to the user and @@ -556,7 +626,7 @@ public final class IpSecManager { } /** - * Retrieve an instance of an IpSecManager within you application context + * Construct an instance of IpSecManager within an application context. * * @param context the application context for this manager * @hide diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 48b5bd5c3d..cda4ec762c 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -38,27 +38,29 @@ import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; /** - * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec. + * This class represents an IPsec transform, which comprises security associations in one or both + * directions. * - *

            IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout - * the lifetime of the underlying transform. If a transform object leaves scope, the underlying - * transform may be disabled automatically, with likely undesirable results. + *

            Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} + * object encapsulates the properties and state of an inbound and outbound IPsec security + * association. That includes, but is not limited to, algorithm choice, key material, and allocated + * system resources. * - *

            An IpSecTransform may either represent a tunnel mode transform that operates on a wide array - * of traffic or may represent a transport mode transform operating on a Socket or Sockets. + * @see RFC 4301, Security Architecture for the + * Internet Protocol */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; /** - * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies - * to traffic towards the host. + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic towards the host. */ public static final int DIRECTION_IN = 0; /** - * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies - * to traffic from the host. + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic from the host. */ public static final int DIRECTION_OUT = 1; @@ -77,16 +79,16 @@ public final class IpSecTransform implements AutoCloseable { public static final int ENCAP_NONE = 0; /** - * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad - * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP. + * IPsec traffic will be encapsulated within UDP, but with 8 zero-value bytes between the UDP + * header and payload. This prevents traffic from being interpreted as ESP or IKEv2. * * @hide */ public static final int ENCAP_ESPINUDP_NON_IKE = 1; /** - * IpSec traffic will be encapsulated within UDP as per RFC3498. + * IPsec traffic will be encapsulated within UDP as per + * RFC 3498. * * @hide */ @@ -165,13 +167,14 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Deactivate an IpSecTransform and free all resources for that transform that are managed by - * the system for this Transform. + * Deactivate this {@code IpSecTransform} and free allocated resources. * - *

            Deactivating a transform while it is still applied to any Socket will result in sockets - * refusing to send or receive data. This method will silently succeed if the specified - * transform has already been removed; thus, it is always safe to attempt cleanup when a - * transform is no longer needed. + *

            Deactivating a transform while it is still applied to a socket will result in errors on + * that socket. Make sure to remove transforms by calling {@link + * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a + * socket will not deactivate it (because one transform may be applied to multiple sockets). + * + *

            It is safe to call this method on a transform that has already been deactivated. */ public void close() { Log.d(TAG, "Removing Transform with Id " + mResourceId); @@ -197,6 +200,7 @@ public final class IpSecTransform implements AutoCloseable { } } + /** Check that the transform was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -264,65 +268,63 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Builder object to facilitate the creation of IpSecTransform objects. - * - *

            Apply additional properties to the transform and then call a build() method to return an - * IpSecTransform object. - * - * @see Builder#buildTransportModeTransform(InetAddress) + * This class is used to build {@link IpSecTransform} objects. */ public static class Builder { private Context mContext; private IpSecConfig mConfig; /** - * Add an encryption algorithm to the transform for the given direction. + * Set the encryption algorithm for the given direction. * - *

            If encryption is set for a given direction without also providing an SPI for that - * direction, creation of an IpSecTransform will fail upon calling a build() method. + *

            If encryption is set for a direction without also providing an SPI for that direction, + * creation of an {@code IpSecTransform} will fail when attempting to build the transform. * - *

            Authenticated encryption is mutually exclusive with encryption and authentication. + *

            Encryption is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ public IpSecTransform.Builder setEncryption( @TransformDirection int direction, IpSecAlgorithm algo) { + // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. mConfig.setEncryption(direction, algo); return this; } /** - * Add an authentication/integrity algorithm to the transform. + * Set the authentication (integrity) algorithm for the given direction. * - *

            If authentication is set for a given direction without also providing an SPI for that - * direction, creation of an IpSecTransform will fail upon calling a build() method. + *

            If authentication is set for a direction without also providing an SPI for that + * direction, creation of an {@code IpSecTransform} will fail when attempting to build the + * transform. * - *

            Authenticated encryption is mutually exclusive with encryption and authentication. + *

            Authentication is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ public IpSecTransform.Builder setAuthentication( @TransformDirection int direction, IpSecAlgorithm algo) { + // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. mConfig.setAuthentication(direction, algo); return this; } /** - * Add an authenticated encryption algorithm to the transform for the given direction. + * Set the authenticated encryption algorithm for the given direction. * *

            If an authenticated encryption algorithm is set for a given direction without also - * providing an SPI for that direction, creation of an IpSecTransform will fail upon calling - * a build() method. + * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when + * attempting to build the transform. * *

            The Authenticated Encryption (AE) class of algorithms are also known as Authenticated * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as - * referred to in RFC 4301) + * referred to in RFC 4301). * *

            Authenticated encryption is mutually exclusive with encryption and authentication. * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * be applied. */ @@ -333,19 +335,16 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Set the SPI, which uniquely identifies a particular IPsec session from others. Because - * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a - * given destination address. + * Set the SPI for the given direction. * - *

            Care should be chosen when selecting an SPI to ensure that is is as unique as - * possible. To reserve a value call {@link IpSecManager#reserveSecurityParameterIndex(int, - * InetAddress, int)}. Otherwise, SPI collisions would prevent a transform from being - * activated. IpSecManager#reserveSecurityParameterIndex(int, InetAddres$s, int)}. + *

            Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies + * packets to a given destination address. To prevent SPI collisions, values should be + * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}. * - *

            Unless an SPI is set for a given direction, traffic in that direction will be - * sent/received without any IPsec applied. + *

            If the SPI and algorithms are omitted for one direction, traffic in that direction + * will not be encrypted or authenticated. * - * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT} + * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed * traffic */ @@ -356,11 +355,10 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Specify the network on which this transform will emit its traffic; (otherwise it will - * emit on the default network). + * Set the {@link Network} which will carry tunneled traffic. * - *

            Restricts the transformed traffic to a particular {@link Network}. This is required in - * tunnel mode. + *

            Restricts the transformed traffic to a particular {@link Network}. This is required + * for tunnel mode, otherwise tunneled traffic would be sent on the default network. * * @hide */ @@ -371,15 +369,18 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Add UDP encapsulation to an IPv4 transform + * Add UDP encapsulation to an IPv4 transform. * - *

            This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for - * details on how UDP should be applied to IPsec. + *

            This allows IPsec traffic to pass through a NAT. * - * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and - * receiving encapsulating traffic. - * @param remotePort the UDP port number of the remote that will send and receive - * encapsulated traffic. In the case of IKE, this is likely port 4500. + * @see RFC 3948, UDP Encapsulation of IPsec + * ESP Packets + * @see RFC 7296 section 2.23, + * NAT Traversal of IKEv2 + * + * @param localSocket a socket for sending and receiving encapsulated traffic + * @param remotePort the UDP port number of the remote host that will send and receive + * encapsulated traffic. In the case of IKEv2, this should be port 4500. */ public IpSecTransform.Builder setIpv4Encapsulation( IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { @@ -393,12 +394,15 @@ public final class IpSecTransform implements AutoCloseable { // TODO: Probably a better exception to throw for NATTKeepalive failure // TODO: Specify the needed NATT keepalive permission. /** - * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded - * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot - * be activated, then the transform will fail to activate and throw an IOException. + * Set NAT-T keepalives to be sent with a given interval. + * + *

            This will set power-efficient keepalive packets to be sent by the system. If NAT-T + * keepalive is requested but cannot be activated, then creation of an {@link + * IpSecTransform} will fail when calling the build method. + * + * @param intervalSeconds the maximum number of seconds between keepalive packets. Must be + * between 20s and 3600s. * - * @param intervalSeconds the maximum number of seconds between keepalive packets, no less - * than 20s and no more than 3600s. * @hide */ @SystemApi @@ -408,36 +412,29 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform. - * Some parameters have interdependencies that are checked at build time. If a well-formed - * transform cannot be created from the supplied parameters, this method will throw an - * Exception. + * Build a transport mode {@link IpSecTransform}. * - *

            Upon a successful return from this call, the provided IpSecTransform will be active - * and may be applied to sockets. If too many IpSecTransform objects are active for a given - * user this operation will fail and throw ResourceUnavailableException. To avoid these - * exceptions, unused Transform objects must be cleaned up by calling {@link - * IpSecTransform#close()} when they are no longer needed. + *

            This builds and activates a transport mode transform. Note that an active transform + * will not affect any network traffic until it has been applied to one or more sockets. * - * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this - * socket will cause the transform to be applied. - *

            Note that an active transform will not impact any network traffic until it has - * been applied to one or more Sockets. Calling this method is a necessary precondition - * for applying it to a socket, but is not sufficient to actually apply IPsec. + * @see IpSecManager#applyTransportModeTransform + * + * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use + * this transform * @throws IllegalArgumentException indicating that a particular combination of transform - * properties is invalid. - * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms - * may be allocated - * @throws SpiUnavailableException if the SPI collides with an existing transform - * (unlikely). - * @throws ResourceUnavailableException if the current user currently has exceeded the - * number of allowed active transforms. + * properties is invalid + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are + * active + * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI + * collides with an existing transform + * @throws IOException indicating other errors */ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { mConfig.setMode(MODE_TRANSPORT); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); + // FIXME: modifying a builder after calling build can change the built transform. return new IpSecTransform(mContext, mConfig).activate(); } @@ -465,9 +462,9 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Create a new IpSecTransform.Builder to construct an IpSecTransform + * Create a new IpSecTransform.Builder. * - * @param context current Context + * @param context current context */ public Builder(@NonNull Context context) { Preconditions.checkNotNull(context); From 7175f27cbe603e241d3c16ab34c1a304381350ee Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 9 Nov 2017 16:49:33 -0800 Subject: [PATCH 0432/1150] Validate IpSecAlgorithm Length Improve the Validation of IpSecAlgorithm by explicitly checking the length in addition to the truncation length (previously an oversight). In addition, we now check the lengths during un-parceling, which will catch someone maliciously manually building a parcel and passing it, bypassing the checks in the constructor. Bug: 68780091 Test: runtest -x IpSecAlgorithmTest.java Change-Id: I8172762617264d34f47d5144336464510f07a701 --- core/java/android/net/IpSecAlgorithm.java | 72 ++++++++++++++++------- 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index d6e62cf1f8..f82627b942 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -21,6 +21,7 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import java.lang.annotation.Retention; @@ -34,6 +35,8 @@ import java.util.Arrays; * Internet Protocol */ public final class IpSecAlgorithm implements Parcelable { + private static final String TAG = "IpSecAlgorithm"; + /** * AES-CBC Encryption/Ciphering Algorithm. * @@ -45,6 +48,7 @@ public final class IpSecAlgorithm implements Parcelable { * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in * new applications and is provided for legacy compatibility with 3gpp infrastructure. * + *

            Keys for this algorithm must be 128 bits in length. *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. */ public static final String AUTH_HMAC_MD5 = "hmac(md5)"; @@ -53,6 +57,7 @@ public final class IpSecAlgorithm implements Parcelable { * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in * new applications and is provided for legacy compatibility with 3gpp infrastructure. * + *

            Keys for this algorithm must be 160 bits in length. *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. */ public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; @@ -60,6 +65,7 @@ public final class IpSecAlgorithm implements Parcelable { /** * SHA256 HMAC Authentication/Integrity Algorithm. * + *

            Keys for this algorithm must be 256 bits in length. *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. */ public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -67,6 +73,7 @@ public final class IpSecAlgorithm implements Parcelable { /** * SHA384 HMAC Authentication/Integrity Algorithm. * + *

            Keys for this algorithm must be 384 bits in length. *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. */ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; @@ -74,6 +81,7 @@ public final class IpSecAlgorithm implements Parcelable { /** * SHA512 HMAC Authentication/Integrity Algorithm. * + *

            Keys for this algorithm must be 512 bits in length. *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; @@ -130,12 +138,10 @@ public final class IpSecAlgorithm implements Parcelable { * @param truncLenBits number of bits of output hash to use. */ public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { - if (!isTruncationLengthValid(algorithm, truncLenBits)) { - throw new IllegalArgumentException("Unknown algorithm or invalid length"); - } mName = algorithm; mKey = key.clone(); - mTruncLenBits = Math.min(truncLenBits, key.length * 8); + mTruncLenBits = truncLenBits; + checkValidOrThrow(mName, mKey.length * 8, mTruncLenBits); } /** Get the algorithm name */ @@ -169,7 +175,11 @@ public final class IpSecAlgorithm implements Parcelable { public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecAlgorithm createFromParcel(Parcel in) { - return new IpSecAlgorithm(in); + final String name = in.readString(); + final byte[] key = in.createByteArray(); + final int truncLenBits = in.readInt(); + + return new IpSecAlgorithm(name, key, truncLenBits); } public IpSecAlgorithm[] newArray(int size) { @@ -177,30 +187,47 @@ public final class IpSecAlgorithm implements Parcelable { } }; - private IpSecAlgorithm(Parcel in) { - mName = in.readString(); - mKey = in.createByteArray(); - mTruncLenBits = in.readInt(); - } + private static void checkValidOrThrow(String name, int keyLen, int truncLen) { + boolean isValidLen = true; + boolean isValidTruncLen = true; - private static boolean isTruncationLengthValid(String algo, int truncLenBits) { - switch (algo) { + switch(name) { case CRYPT_AES_CBC: - return (truncLenBits == 128 || truncLenBits == 192 || truncLenBits == 256); + isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256; + break; case AUTH_HMAC_MD5: - return (truncLenBits >= 96 && truncLenBits <= 128); + isValidLen = keyLen == 128; + isValidTruncLen = truncLen >= 96 && truncLen <= 128; + break; case AUTH_HMAC_SHA1: - return (truncLenBits >= 96 && truncLenBits <= 160); + isValidLen = keyLen == 160; + isValidTruncLen = truncLen >= 96 && truncLen <= 160; + break; case AUTH_HMAC_SHA256: - return (truncLenBits >= 96 && truncLenBits <= 256); + isValidLen = keyLen == 256; + isValidTruncLen = truncLen >= 96 && truncLen <= 256; + break; case AUTH_HMAC_SHA384: - return (truncLenBits >= 192 && truncLenBits <= 384); + isValidLen = keyLen == 384; + isValidTruncLen = truncLen >= 192 && truncLen <= 384; + break; case AUTH_HMAC_SHA512: - return (truncLenBits >= 256 && truncLenBits <= 512); + isValidLen = keyLen == 512; + isValidTruncLen = truncLen >= 256 && truncLen <= 512; + break; case AUTH_CRYPT_AES_GCM: - return (truncLenBits == 64 || truncLenBits == 96 || truncLenBits == 128); + // The keying material for GCM is a key plus a 32-bit salt + isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; + break; default: - return false; + throw new IllegalArgumentException("Couldn't find an algorithm: " + name); + } + + if (!isValidLen) { + throw new IllegalArgumentException("Invalid key material keyLength: " + keyLen); + } + if (!isValidTruncLen) { + throw new IllegalArgumentException("Invalid truncation keyLength: " + truncLen); } } @@ -217,8 +244,9 @@ public final class IpSecAlgorithm implements Parcelable { .toString(); } - /** package */ - static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) { + /** @hide */ + @VisibleForTesting + public static boolean equals(IpSecAlgorithm lhs, IpSecAlgorithm rhs) { if (lhs == null || rhs == null) return (lhs == rhs); return (lhs.mName.equals(rhs.mName) && Arrays.equals(lhs.mKey, rhs.mKey) From 152b263678b431d3e666ffa322827d608faf51f2 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 29 Nov 2017 11:18:23 -0700 Subject: [PATCH 0433/1150] API for apps to tag sockets with their own UID. This enables app A to create a socket, pass it to app B, and have app B accept blame for the traffic performed on that socket. Also adds helpful public APIs for tagging raw FileDescriptor sockets instead of making developers go through shady SocketImpl wrappers. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AppSecurityTests#testAppFailAccessPrivateData Bug: 63932076 Change-Id: I08925c843974675fc82e4080cec2eaab9ab7cd41 --- core/java/android/net/TrafficStats.java | 39 +++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index c339856f43..954e59c2c4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; @@ -30,6 +31,8 @@ import com.android.server.NetworkManagementSocketTagger; import dalvik.system.SocketTagger; +import java.io.FileDescriptor; +import java.io.IOException; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -263,15 +266,26 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } + /** + * Set specific UID to use when accounting {@link Socket} traffic + * originating from the current thread as the calling UID. Designed for use + * when another application is performing operations on your behalf. + *

            + * Changes only take effect during subsequent calls to + * {@link #tagSocket(Socket)}. + */ + public static void setThreadStatsUidSelf() { + setThreadStatsUid(android.os.Process.myUid()); + } + /** * Clear any active UID set to account {@link Socket} traffic originating * from the current thread. * * @see #setThreadStatsUid(int) - * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @SuppressLint("Doclava125") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } @@ -315,6 +329,27 @@ public class TrafficStats { SocketTagger.get().untag(socket); } + /** + * Tag the given {@link FileDescriptor} socket with any statistics + * parameters active for the current thread. Subsequent calls always replace + * any existing parameters. When finished, call + * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics + * parameters. + * + * @see #setThreadStatsTag(int) + */ + public static void tagFileDescriptor(FileDescriptor fd) throws IOException { + SocketTagger.get().tag(fd); + } + + /** + * Remove any statistics parameters from the given {@link FileDescriptor} + * socket. + */ + public static void untagFileDescriptor(FileDescriptor fd) throws IOException { + SocketTagger.get().untag(fd); + } + /** * Start profiling data usage for current UID. Only one profiling session * can be active at a time. From f33f4845b3ca71f9962ef2aedad77942b3c2d1c0 Mon Sep 17 00:00:00 2001 From: Jonathan Basseri Date: Thu, 16 Nov 2017 10:58:01 -0800 Subject: [PATCH 0434/1150] Use consistent naming for allocating SPI. Throughout the IPsec code (API, system server, netd) we use "reserve" SPI and "allocate" SPI interchangeably. This renames to use "allocate" everywhere for self-consistency and consistency with the kernel (ALLOCSPI). In javadoc, I am leaving the word "reserve" in several places because it is still an accurate description of how the method behaves. Bug: 69128142 Test: TreeHugger should be enough Change-Id: I8ea603b4612303b0393beef04032671fa53d2106 --- core/java/android/net/IIpSecService.aidl | 2 +- core/java/android/net/IpSecManager.java | 59 +++++++++++-------- core/java/android/net/IpSecTransform.java | 22 +++---- .../java/com/android/server/IpSecService.java | 6 +- 4 files changed, 45 insertions(+), 44 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 0b1ea98f2e..d9b57db180 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -30,7 +30,7 @@ import android.os.ParcelFileDescriptor; */ interface IIpSecService { - IpSecSpiResponse reserveSecurityParameterIndex( + IpSecSpiResponse allocateSecurityParameterIndex( int direction, in String remoteAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index a9e60ec88a..6a4b891478 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -46,7 +46,7 @@ import java.net.Socket; * to create a VPN should use {@link VpnService}. * * @see RFC 4301, Security Architecture for the - * Internet Protocol + * Internet Protocol */ @SystemService(Context.IPSEC_SERVICE) public final class IpSecManager { @@ -59,8 +59,7 @@ public final class IpSecManager { * * @hide */ - @TestApi - public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; + @TestApi public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; /** @hide */ public interface Status { @@ -78,7 +77,7 @@ public final class IpSecManager { *

            The combination of remote {@code InetAddress} and SPI must be unique across all apps on * one device. If this error is encountered, a new SPI is required before a transform may be * created. This error can be avoided by calling {@link - * IpSecManager#reserveSecurityParameterIndex}. + * IpSecManager#allocateSecurityParameterIndex}. */ public static final class SpiUnavailableException extends AndroidException { private final int mSpi; @@ -121,7 +120,7 @@ public final class IpSecManager { * This class represents a reserved SPI. * *

            Objects of this type are used to track reserved security parameter indices. They can be - * obtained by calling {@link IpSecManager#reserveSecurityParameterIndex} and must be released + * obtained by calling {@link IpSecManager#allocateSecurityParameterIndex} and must be released * by calling {@link #close()} when they are no longer needed. */ public static final class SecurityParameterIndex implements AutoCloseable { @@ -170,7 +169,7 @@ public final class IpSecManager { mRemoteAddress = remoteAddress; try { IpSecSpiResponse result = - mService.reserveSecurityParameterIndex( + mService.allocateSecurityParameterIndex( direction, remoteAddress.getHostAddress(), spi, new Binder()); if (result == null) { @@ -228,7 +227,7 @@ public final class IpSecManager { * for this user * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved */ - public SecurityParameterIndex reserveSecurityParameterIndex( + public SecurityParameterIndex allocateSecurityParameterIndex( int direction, InetAddress remoteAddress) throws ResourceUnavailableException { try { return new SecurityParameterIndex( @@ -255,7 +254,7 @@ public final class IpSecManager { * for this user * @throws SpiUnavailableException indicating that the requested SPI could not be reserved */ - public SecurityParameterIndex reserveSecurityParameterIndex( + public SecurityParameterIndex allocateSecurityParameterIndex( int direction, InetAddress remoteAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { @@ -273,16 +272,18 @@ public final class IpSecManager { * unprotected traffic can resume on that socket. * *

            For security reasons, the destination address of any traffic on the socket must match the - * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any + * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * - *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform - * will be removed. However, inbound traffic on the old transform will continue to be decrypted - * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap - * allows rekey procedures where both transforms are valid until both endpoints are using the - * new transform and all in-flight packets have been received. + *

            Rekey Procedure

            + * + *

            When applying a new tranform to a socket, the previous transform will be removed. However, + * inbound traffic on the old transform will continue to be decrypted until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures + * where both transforms are valid until both endpoints are using the new transform and all + * in-flight packets have been received. * * @param socket a stream socket * @param transform a transport mode {@code IpSecTransform} @@ -310,11 +311,13 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * - *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform - * will be removed. However, inbound traffic on the old transform will continue to be decrypted - * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap - * allows rekey procedures where both transforms are valid until both endpoints are using the - * new transform and all in-flight packets have been received. + *

            Rekey Procedure

            + * + *

            When applying a new tranform to a socket, the previous transform will be removed. However, + * inbound traffic on the old transform will continue to be decrypted until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures + * where both transforms are valid until both endpoints are using the new transform and all + * in-flight packets have been received. * * @param socket a datagram socket * @param transform a transport mode {@code IpSecTransform} @@ -342,11 +345,13 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. * - *

            Rekey Procedure

            When applying a new tranform to a socket, the previous transform - * will be removed. However, inbound traffic on the old transform will continue to be decrypted - * until that transform is deallocated by calling {@link IpSecTransform#close()}. This overlap - * allows rekey procedures where both transforms are valid until both endpoints are using the - * new transform and all in-flight packets have been received. + *

            Rekey Procedure

            + * + *

            When applying a new tranform to a socket, the previous transform will be removed. However, + * inbound traffic on the old transform will continue to be decrypted until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures + * where both transforms are valid until both endpoints are using the new transform and all + * in-flight packets have been received. * * @param socket a socket file descriptor * @param transform a transport mode {@code IpSecTransform} @@ -379,7 +384,8 @@ public final class IpSecManager { * Applications should probably not use this API directly. Instead, they should use {@link * VpnService} to provide VPN capability in a more generic fashion. * - * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. + *

            TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. + * * @param net a {@link Network} that will be tunneled via IP Sec. * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. * @hide @@ -469,7 +475,8 @@ public final class IpSecManager { * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is * lost, all traffic will drop. * - * TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. + *

            TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. + * * @param net a network that currently has transform applied to it. * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given * network diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index cda4ec762c..7cd742b417 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -47,7 +47,7 @@ import java.net.InetAddress; * system resources. * * @see RFC 4301, Security Architecture for the - * Internet Protocol + * Internet Protocol */ public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; @@ -116,8 +116,7 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Checks the result status and throws an appropriate exception if - * the status is not Status.OK. + * Checks the result status and throws an appropriate exception if the status is not Status.OK. */ private void checkResultStatus(int status) throws IOException, IpSecManager.ResourceUnavailableException, @@ -267,9 +266,7 @@ public final class IpSecTransform implements AutoCloseable { return; } - /** - * This class is used to build {@link IpSecTransform} objects. - */ + /** This class is used to build {@link IpSecTransform} objects. */ public static class Builder { private Context mContext; private IpSecConfig mConfig; @@ -339,7 +336,7 @@ public final class IpSecTransform implements AutoCloseable { * *

            Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies * packets to a given destination address. To prevent SPI collisions, values should be - * reserved by calling {@link IpSecManager#reserveSecurityParameterIndex}. + * reserved by calling {@link IpSecManager#allocateSecurityParameterIndex}. * *

            If the SPI and algorithms are omitted for one direction, traffic in that direction * will not be encrypted or authenticated. @@ -374,10 +371,9 @@ public final class IpSecTransform implements AutoCloseable { *

            This allows IPsec traffic to pass through a NAT. * * @see RFC 3948, UDP Encapsulation of IPsec - * ESP Packets + * ESP Packets * @see RFC 7296 section 2.23, - * NAT Traversal of IKEv2 - * + * NAT Traversal of IKEv2 * @param localSocket a socket for sending and receiving encapsulated traffic * @param remotePort the UDP port number of the remote host that will send and receive * encapsulated traffic. In the case of IKEv2, this should be port 4500. @@ -402,7 +398,6 @@ public final class IpSecTransform implements AutoCloseable { * * @param intervalSeconds the maximum number of seconds between keepalive packets. Must be * between 20s and 3600s. - * * @hide */ @SystemApi @@ -418,7 +413,6 @@ public final class IpSecTransform implements AutoCloseable { * will not affect any network traffic until it has been applied to one or more sockets. * * @see IpSecManager#applyTransportModeTransform - * * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use * this transform * @throws IllegalArgumentException indicating that a particular combination of transform @@ -453,8 +447,8 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform buildTunnelModeTransform( InetAddress localAddress, InetAddress remoteAddress) { - //FIXME: argument validation here - //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); + // FIXME: argument validation here + // throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); mConfig.setLocalAddress(localAddress.getHostAddress()); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setMode(MODE_TUNNEL); diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 1154fbe609..72d2c4d608 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -672,15 +672,15 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Invalid Direction: " + direction); } - @Override /** Get a new SPI and maintain the reservation in the system server */ - public synchronized IpSecSpiResponse reserveSecurityParameterIndex( + @Override + public synchronized IpSecSpiResponse allocateSecurityParameterIndex( int direction, String remoteAddress, int requestedSpi, IBinder binder) throws RemoteException { checkDirection(direction); checkInetAddress(remoteAddress); /* requestedSpi can be anything in the int range, so no check is needed. */ - checkNotNull(binder, "Null Binder passed to reserveSecurityParameterIndex"); + checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); int resourceId = mNextResourceId.getAndIncrement(); From 59c8818d6d8d91927335b486700f109727371203 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 26 Oct 2017 19:41:43 -0700 Subject: [PATCH 0435/1150] Add reference counted resources to IpSecService This patch adds (but does not enable the usage of) RefcountedResource objects to IpSecService, with tests to ensure correct function. This is patch 1 of a series of patches to refactor the resource management systems in IpSecService. RefcountedResource objects allow for management of acyclical dependency trees, ensuring eventual cleanup when resources are no longer used. This cleanup may be triggered by binder death or by explicit user action. Bug: 63409385 Test: New tests written in IpSecServiceRefcountedResourceTest, explicitly testing the RefcountedResource class Change-Id: Ib5be7482b2ef5f1c8dec9be68f15e90d8b3aba6d --- .../java/com/android/server/IpSecService.java | 219 ++++++++++++++++-- 1 file changed, 199 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 1154fbe609..92db7cc834 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -57,11 +57,23 @@ import java.io.PrintWriter; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import libcore.io.IoUtils; -/** @hide */ +/** + * A service to manage multiple clients that want to access the IpSec API. The service is + * responsible for maintaining a list of clients and managing the resources (and related quotas) + * that each of them own. + * + *

            Synchronization in IpSecService is done on all entrypoints due to potential race conditions at + * the kernel/xfrm level. Further, this allows the simplifying assumption to be made that only one + * thread is ever running at a time. + * + * @hide + */ public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); @@ -92,15 +104,15 @@ public class IpSecService extends IIpSecService.Stub { private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); @GuardedBy("this") - private final ManagedResourceArray mSpiRecords = new ManagedResourceArray<>(); + private final KernelResourceArray mSpiRecords = new KernelResourceArray<>(); @GuardedBy("this") - private final ManagedResourceArray mTransformRecords = - new ManagedResourceArray<>(); + private final KernelResourceArray mTransformRecords = + new KernelResourceArray<>(); @GuardedBy("this") - private final ManagedResourceArray mUdpSocketRecords = - new ManagedResourceArray<>(); + private final KernelResourceArray mUdpSocketRecords = + new KernelResourceArray<>(); interface IpSecServiceConfiguration { INetd getNetdInstance() throws RemoteException; @@ -120,6 +132,173 @@ public class IpSecService extends IIpSecService.Stub { private final IpSecServiceConfiguration mSrvConfig; + /** + * Interface for user-reference and kernel-resource cleanup. + * + *

            This interface must be implemented for a resource to be reference counted. + */ + @VisibleForTesting + public interface IResource { + /** + * Invalidates a IResource object, ensuring it is invalid for the purposes of allocating new + * objects dependent on it. + * + *

            Implementations of this method are expected to remove references to the IResource + * object from the IpSecService's tracking arrays. The removal from the arrays ensures that + * the resource is considered invalid for user access or allocation or use in other + * resources. + * + *

            References to the IResource object may be held by other RefcountedResource objects, + * and as such, the kernel resources and quota may not be cleaned up. + */ + void invalidate() throws RemoteException; + + /** + * Releases underlying resources and related quotas. + * + *

            Implementations of this method are expected to remove all system resources that are + * tracked by the IResource object. Due to other RefcountedResource objects potentially + * having references to the IResource object, releaseKernelResources may not always be + * called from releaseIfUnreferencedRecursively(). + */ + void freeUnderlyingResources() throws RemoteException; + } + + /** + * RefcountedResource manages references and dependencies in an exclusively acyclic graph. + * + *

            RefcountedResource implements both explicit and implicit resource management. Creating a + * RefcountedResource object creates an explicit reference that must be freed by calling + * userRelease(). Additionally, adding this object as a child of another RefcountedResource + * object will add an implicit reference. + * + *

            Resources are cleaned up when all references, both implicit and explicit, are released + * (ie, when userRelease() is called and when all parents have called releaseReference() on this + * object.) + */ + @VisibleForTesting + public class RefcountedResource implements IBinder.DeathRecipient { + private final T mResource; + private final List mChildren; + int mRefCount = 1; // starts at 1 for user's reference. + IBinder mBinder; + + RefcountedResource(T resource, IBinder binder, RefcountedResource... children) { + synchronized (IpSecService.this) { + this.mResource = resource; + this.mChildren = new ArrayList<>(children.length); + this.mBinder = binder; + + for (RefcountedResource child : children) { + mChildren.add(child); + child.mRefCount++; + } + + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + } + + /** + * If the Binder object dies, this function is called to free the system resources that are + * being managed by this record and to subsequently release this record for garbage + * collection + */ + @Override + public void binderDied() { + synchronized (IpSecService.this) { + try { + userRelease(); + } catch (Exception e) { + Log.e(TAG, "Failed to release resource: " + e); + } + } + } + + public T getResource() { + return mResource; + } + + /** + * Unlinks from binder and performs IpSecService resource cleanup (removes from resource + * arrays) + * + *

            If this method has been previously called, the RefcountedResource's binder field will + * be null, and the method will return without performing the cleanup a second time. + * + *

            Note that calling this function does not imply that kernel resources will be freed at + * this time, or that the related quota will be returned. Such actions will only be + * performed upon the reference count reaching zero. + */ + @GuardedBy("IpSecService.this") + public void userRelease() throws RemoteException { + // Prevent users from putting reference counts into a bad state by calling + // userRelease() multiple times. + if (mBinder == null) { + return; + } + + mBinder.unlinkToDeath(this, 0); + mBinder = null; + + mResource.invalidate(); + + releaseReference(); + } + + /** + * Removes a reference to this resource. If the resultant reference count is zero, the + * underlying resources are freed, and references to all child resources are also dropped + * recursively (resulting in them freeing their resources and children, etcetera) + * + *

            This method also sets the reference count to an invalid value (-1) to signify that it + * has been fully released. Any subsequent calls to this method will result in an + * IllegalStateException being thrown due to resource already having been previously + * released + */ + @VisibleForTesting + @GuardedBy("IpSecService.this") + public void releaseReference() throws RemoteException { + mRefCount--; + + if (mRefCount > 0) { + return; + } else if (mRefCount < 0) { + throw new IllegalStateException( + "Invalid operation - resource has already been released."); + } + + // Cleanup own resources + mResource.freeUnderlyingResources(); + + // Cleanup child resources as needed + for (RefcountedResource child : mChildren) { + child.releaseReference(); + } + + // Enforce that resource cleanup can only be called once + // By decrementing the refcount (from 0 to -1), the next call will throw an + // IllegalStateException - it has already been released fully. + mRefCount--; + } + + @Override + public String toString() { + return new StringBuilder() + .append("{mResource=") + .append(mResource) + .append(", mRefCount=") + .append(mRefCount) + .append(", mChildren=") + .append(mChildren) + .append("}") + .toString(); + } + } + /* Very simple counting class that looks much like a counting semaphore */ public static class ResourceTracker { private final int mMax; @@ -211,13 +390,13 @@ public class IpSecService extends IIpSecService.Stub { private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker(); /** - * The ManagedResource class provides a facility to cleanly and reliably release system - * resources. It relies on two things: an IBinder that allows ManagedResource to automatically + * The KernelResource class provides a facility to cleanly and reliably release system + * resources. It relies on two things: an IBinder that allows KernelResource to automatically * clean up in the event that the Binder dies and a user-provided resourceId that should * uniquely identify the managed resource. To use this class, the user should implement the * releaseResources() method that is responsible for releasing system resources when invoked. */ - private abstract class ManagedResource implements IBinder.DeathRecipient { + private abstract class KernelResource implements IBinder.DeathRecipient { final int pid; final int uid; private IBinder mBinder; @@ -225,7 +404,7 @@ public class IpSecService extends IIpSecService.Stub { private AtomicInteger mReferenceCount = new AtomicInteger(0); - ManagedResource(int resourceId, IBinder binder) { + KernelResource(int resourceId, IBinder binder) { super(); if (resourceId == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); @@ -341,7 +520,7 @@ public class IpSecService extends IIpSecService.Stub { /** * Minimal wrapper around SparseArray that performs ownership validation on element accesses. */ - private class ManagedResourceArray { + private class KernelResourceArray { SparseArray mArray = new SparseArray<>(); T getAndCheckOwner(int key) { @@ -369,7 +548,7 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class TransformRecord extends ManagedResource { + private final class TransformRecord extends KernelResource { private final IpSecConfig mConfig; private final SpiRecord[] mSpis; private final UdpSocketRecord mSocket; @@ -456,7 +635,7 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class SpiRecord extends ManagedResource { + private final class SpiRecord extends KernelResource { private final int mDirection; private final String mLocalAddress; private final String mRemoteAddress; @@ -544,7 +723,7 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class UdpSocketRecord extends ManagedResource { + private final class UdpSocketRecord extends KernelResource { private FileDescriptor mSocket; private final int mPort; @@ -718,8 +897,8 @@ public class IpSecService extends IIpSecService.Stub { /* This method should only be called from Binder threads. Do not call this from * within the system server as it will crash the system on failure. */ - private synchronized void releaseManagedResource( - ManagedResourceArray resArray, int resourceId, String typeName) + private synchronized void releaseKernelResource( + KernelResourceArray resArray, int resourceId, String typeName) throws RemoteException { // We want to non-destructively get so that we can check credentials before removing // this from the records. @@ -737,7 +916,7 @@ public class IpSecService extends IIpSecService.Stub { /** Release a previously allocated SPI that has been registered with the system server */ @Override public void releaseSecurityParameterIndex(int resourceId) throws RemoteException { - releaseManagedResource(mSpiRecords, resourceId, "SecurityParameterIndex"); + releaseKernelResource(mSpiRecords, resourceId, "SecurityParameterIndex"); } /** @@ -827,7 +1006,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { - releaseManagedResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); + releaseKernelResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); } /** @@ -974,7 +1153,7 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public void deleteTransportModeTransform(int resourceId) throws RemoteException { - releaseManagedResource(mTransformRecords, resourceId, "IpSecTransform"); + releaseKernelResource(mTransformRecords, resourceId, "IpSecTransform"); } /** @@ -984,7 +1163,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTransportModeTransform( ParcelFileDescriptor socket, int resourceId) throws RemoteException { - // Synchronize liberally here because we are using ManagedResources in this block + // Synchronize liberally here because we are using KernelResources in this block TransformRecord info; // FIXME: this code should be factored out into a security check + getter info = mTransformRecords.getAndCheckOwner(resourceId); From eea9cff0d15c9d9dbcc7ec56cd3a6c59f1197bbc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 16 Nov 2017 15:27:22 -0800 Subject: [PATCH 0436/1150] Convert IpSecService resources to use refcounting This is part 2 of 2 of the refcounting refactor for IpSecService resources. Switched ManagedResources to use RefcountedResource structure for managing reference counts and eventual cleanup. Further, resource arrays and quota management have been aggregated into a UserRecord for better isolation. UID access checking has been similarly moved into the UserRecordTracker, and resourceId checking has been rolled into RefcountedResourceArray's accessor methods. Bug: 63409385 Test: CTS, all unit tests run on aosp_marlin-eng, new tests added Change-Id: Iee52dd1c9d2583bb6bfaf65be87569e9d50a5b63 --- .../java/com/android/server/IpSecService.java | 472 +++++++++--------- 1 file changed, 227 insertions(+), 245 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 92db7cc834..2116d9a818 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -103,17 +103,6 @@ public class IpSecService extends IIpSecService.Stub { /** Should be a never-repeating global ID for resources */ private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); - @GuardedBy("this") - private final KernelResourceArray mSpiRecords = new KernelResourceArray<>(); - - @GuardedBy("this") - private final KernelResourceArray mTransformRecords = - new KernelResourceArray<>(); - - @GuardedBy("this") - private final KernelResourceArray mUdpSocketRecords = - new KernelResourceArray<>(); - interface IpSecServiceConfiguration { INetd getNetdInstance() throws RemoteException; @@ -158,7 +147,7 @@ public class IpSecService extends IIpSecService.Stub { * *

            Implementations of this method are expected to remove all system resources that are * tracked by the IResource object. Due to other RefcountedResource objects potentially - * having references to the IResource object, releaseKernelResources may not always be + * having references to the IResource object, freeUnderlyingResources may not always be * called from releaseIfUnreferencedRecursively(). */ void freeUnderlyingResources() throws RemoteException; @@ -204,7 +193,7 @@ public class IpSecService extends IIpSecService.Stub { /** * If the Binder object dies, this function is called to free the system resources that are - * being managed by this record and to subsequently release this record for garbage + * being tracked by this record and to subsequently release this record for garbage * collection */ @Override @@ -300,7 +289,8 @@ public class IpSecService extends IIpSecService.Stub { } /* Very simple counting class that looks much like a counting semaphore */ - public static class ResourceTracker { + @VisibleForTesting + static class ResourceTracker { private final int mMax; int mCurrent; @@ -309,18 +299,18 @@ public class IpSecService extends IIpSecService.Stub { mCurrent = 0; } - synchronized boolean isAvailable() { + boolean isAvailable() { return (mCurrent < mMax); } - synchronized void take() { + void take() { if (!isAvailable()) { Log.wtf(TAG, "Too many resources allocated!"); } mCurrent++; } - synchronized void give() { + void give() { if (mCurrent <= 0) { Log.wtf(TAG, "We've released this resource too many times"); } @@ -339,40 +329,70 @@ public class IpSecService extends IIpSecService.Stub { } } - private static final class UserQuotaTracker { - /* Maximum number of UDP Encap Sockets that a single UID may possess */ + @VisibleForTesting + static final class UserRecord { + /* Type names */ + public static final String TYPENAME_SPI = "SecurityParameterIndex"; + public static final String TYPENAME_TRANSFORM = "IpSecTransform"; + public static final String TYPENAME_ENCAP_SOCKET = "UdpEncapSocket"; + + /* Maximum number of each type of resource that a single UID may possess */ public static final int MAX_NUM_ENCAP_SOCKETS = 2; - - /* Maximum number of IPsec Transforms that a single UID may possess */ public static final int MAX_NUM_TRANSFORMS = 4; - - /* Maximum number of IPsec Transforms that a single UID may possess */ public static final int MAX_NUM_SPIS = 8; - /* Record for one users's IpSecService-managed objects */ - public static class UserRecord { - public final ResourceTracker socket = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); - public final ResourceTracker transform = new ResourceTracker(MAX_NUM_TRANSFORMS); - public final ResourceTracker spi = new ResourceTracker(MAX_NUM_SPIS); + final RefcountedResourceArray mSpiRecords = + new RefcountedResourceArray<>(TYPENAME_SPI); + final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); - @Override - public String toString() { - return new StringBuilder() - .append("{socket=") - .append(socket) - .append(", transform=") - .append(transform) - .append(", spi=") - .append(spi) - .append("}") - .toString(); - } + final RefcountedResourceArray mTransformRecords = + new RefcountedResourceArray<>(TYPENAME_TRANSFORM); + final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); + + final RefcountedResourceArray mEncapSocketRecords = + new RefcountedResourceArray<>(TYPENAME_ENCAP_SOCKET); + final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); + + void removeSpiRecord(int resourceId) { + mSpiRecords.remove(resourceId); } + void removeTransformRecord(int resourceId) { + mTransformRecords.remove(resourceId); + } + + void removeEncapSocketRecord(int resourceId) { + mEncapSocketRecords.remove(resourceId); + } + + @Override + public String toString() { + return new StringBuilder() + .append("{mSpiQuotaTracker=") + .append(mSpiQuotaTracker) + .append(", mTransformQuotaTracker=") + .append(mTransformQuotaTracker) + .append(", mSocketQuotaTracker=") + .append(mSocketQuotaTracker) + .append(", mSpiRecords=") + .append(mSpiRecords) + .append(", mTransformRecords=") + .append(mTransformRecords) + .append(", mEncapSocketRecords=") + .append(mEncapSocketRecords) + .append("}") + .toString(); + } + } + + @VisibleForTesting + static final class UserResourceTracker { private final SparseArray mUserRecords = new SparseArray<>(); - /* a never-fail getter so that we can populate the list of UIDs as-needed */ - public synchronized UserRecord getUserRecord(int uid) { + /** Never-fail getter that populates the list of UIDs as-needed */ + public UserRecord getUserRecord(int uid) { + checkCallerUid(uid); + UserRecord r = mUserRecords.get(uid); if (r == null) { r = new UserRecord(); @@ -381,122 +401,56 @@ public class IpSecService extends IIpSecService.Stub { return r; } + /** Safety method; guards against access of other user's UserRecords */ + private void checkCallerUid(int uid) { + if (uid != Binder.getCallingUid() + && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { + throw new SecurityException("Attempted access of unowned resources"); + } + } + @Override public String toString() { return mUserRecords.toString(); } } - private final UserQuotaTracker mUserQuotaTracker = new UserQuotaTracker(); + @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker(); /** - * The KernelResource class provides a facility to cleanly and reliably release system - * resources. It relies on two things: an IBinder that allows KernelResource to automatically - * clean up in the event that the Binder dies and a user-provided resourceId that should - * uniquely identify the managed resource. To use this class, the user should implement the - * releaseResources() method that is responsible for releasing system resources when invoked. + * The KernelResourceRecord class provides a facility to cleanly and reliably track system + * resources. It relies on a provided resourceId that should uniquely identify the kernel + * resource. To use this class, the user should implement the invalidate() and + * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource + * tracking arrays and kernel resources, respectively */ - private abstract class KernelResource implements IBinder.DeathRecipient { + private abstract class KernelResourceRecord implements IResource { final int pid; final int uid; - private IBinder mBinder; - protected int mResourceId; + protected final int mResourceId; - private AtomicInteger mReferenceCount = new AtomicInteger(0); - - KernelResource(int resourceId, IBinder binder) { + KernelResourceRecord(int resourceId) { super(); if (resourceId == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); } - mBinder = binder; mResourceId = resourceId; pid = Binder.getCallingPid(); uid = Binder.getCallingUid(); getResourceTracker().take(); - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } } - public void addReference() { - mReferenceCount.incrementAndGet(); + @Override + public abstract void invalidate() throws RemoteException; + + /** Convenience method; retrieves the user resource record for the stored UID. */ + protected UserRecord getUserRecord() { + return mUserResourceTracker.getUserRecord(uid); } - public void removeReference() { - if (mReferenceCount.decrementAndGet() < 0) { - Log.wtf(TAG, "Programming error: negative reference count"); - } - } - - public boolean isReferenced() { - return (mReferenceCount.get() > 0); - } - - /** - * Ensures that the caller is either the owner of this resource or has the system UID and - * throws a SecurityException otherwise. - */ - public void checkOwnerOrSystem() { - if (uid != Binder.getCallingUid() - && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { - throw new SecurityException("Only the owner may access managed resources!"); - } - } - - /** - * When this record is no longer needed for managing system resources this function should - * clean up all system resources and nullify the record. This function shall perform all - * necessary cleanup of the resources managed by this record. - * - *

            NOTE: this function verifies ownership before allowing resources to be freed. - */ - public final void release() throws RemoteException { - synchronized (IpSecService.this) { - if (isReferenced()) { - throw new IllegalStateException( - "Cannot release a resource that has active references!"); - } - - if (mResourceId == INVALID_RESOURCE_ID) { - return; - } - - releaseResources(); - getResourceTracker().give(); - if (mBinder != null) { - mBinder.unlinkToDeath(this, 0); - } - mBinder = null; - - mResourceId = INVALID_RESOURCE_ID; - } - } - - /** - * If the Binder object dies, this function is called to free the system resources that are - * being managed by this record and to subsequently release this record for garbage - * collection - */ - public final void binderDied() { - try { - release(); - } catch (Exception e) { - Log.e(TAG, "Failed to release resource: " + e); - } - } - - /** - * Implement this method to release all system resources that are being protected by this - * record. Once the resources are released, the record should be invalidated and no longer - * used by calling release(). This should NEVER be called directly. - * - *

            Calls to this are always guarded by IpSecService#this - */ - protected abstract void releaseResources() throws RemoteException; + @Override + public abstract void freeUnderlyingResources() throws RemoteException; /** Get the resource tracker for this resource */ protected abstract ResourceTracker getResourceTracker(); @@ -510,30 +464,52 @@ public class IpSecService extends IIpSecService.Stub { .append(pid) .append(", uid=") .append(uid) - .append(", mReferenceCount=") - .append(mReferenceCount.get()) .append("}") .toString(); } }; + // TODO: Move this to right after RefcountedResource. With this here, Gerrit was showing many + // more things as changed. /** - * Minimal wrapper around SparseArray that performs ownership validation on element accesses. + * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing. + * + *

            RefcountedResourceArray prevents null insertions, and throws an IllegalArgumentException + * if a key is not found during a retrieval process. */ - private class KernelResourceArray { - SparseArray mArray = new SparseArray<>(); + static class RefcountedResourceArray { + SparseArray> mArray = new SparseArray<>(); + private final String mTypeName; - T getAndCheckOwner(int key) { - T val = mArray.get(key); - // The value should never be null unless the resource doesn't exist - // (since we do not allow null resources to be added). - if (val != null) { - val.checkOwnerOrSystem(); - } - return val; + public RefcountedResourceArray(String typeName) { + this.mTypeName = typeName; } - void put(int key, T obj) { + /** + * Accessor method to get inner resource object. + * + * @throws IllegalArgumentException if no resource with provided key is found. + */ + T getResourceOrThrow(int key) { + return getRefcountedResourceOrThrow(key).getResource(); + } + + /** + * Accessor method to get reference counting wrapper. + * + * @throws IllegalArgumentException if no resource with provided key is found. + */ + RefcountedResource getRefcountedResourceOrThrow(int key) { + RefcountedResource resource = mArray.get(key); + if (resource == null) { + throw new IllegalArgumentException( + String.format("No such %s found for given id: %d", mTypeName, key)); + } + + return resource; + } + + void put(int key, RefcountedResource obj) { checkNotNull(obj, "Null resources cannot be added"); mArray.put(key, obj); } @@ -548,30 +524,17 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class TransformRecord extends KernelResource { + private final class TransformRecord extends KernelResourceRecord { private final IpSecConfig mConfig; private final SpiRecord[] mSpis; - private final UdpSocketRecord mSocket; + private final EncapSocketRecord mSocket; TransformRecord( - int resourceId, - IBinder binder, - IpSecConfig config, - SpiRecord[] spis, - UdpSocketRecord socket) { - super(resourceId, binder); + int resourceId, IpSecConfig config, SpiRecord[] spis, EncapSocketRecord socket) { + super(resourceId); mConfig = config; mSpis = spis; mSocket = socket; - - for (int direction : DIRECTIONS) { - mSpis[direction].addReference(); - mSpis[direction].setOwnedByTransform(); - } - - if (mSocket != null) { - mSocket.addReference(); - } } public IpSecConfig getConfig() { @@ -584,7 +547,7 @@ public class IpSecService extends IIpSecService.Stub { /** always guarded by IpSecService#this */ @Override - protected void releaseResources() { + public void freeUnderlyingResources() { for (int direction : DIRECTIONS) { int spi = mSpis[direction].getSpi(); try { @@ -603,17 +566,17 @@ public class IpSecService extends IIpSecService.Stub { } } - for (int direction : DIRECTIONS) { - mSpis[direction].removeReference(); - } - - if (mSocket != null) { - mSocket.removeReference(); - } + getResourceTracker().give(); } + @Override + public void invalidate() throws RemoteException { + getUserRecord().removeTransformRecord(mResourceId); + } + + @Override protected ResourceTracker getResourceTracker() { - return mUserQuotaTracker.getUserRecord(this.uid).transform; + return getUserRecord().mTransformQuotaTracker; } @Override @@ -635,7 +598,7 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class SpiRecord extends KernelResource { + private final class SpiRecord extends KernelResourceRecord { private final int mDirection; private final String mLocalAddress; private final String mRemoteAddress; @@ -645,12 +608,11 @@ public class IpSecService extends IIpSecService.Stub { SpiRecord( int resourceId, - IBinder binder, int direction, String localAddress, String remoteAddress, int spi) { - super(resourceId, binder); + super(resourceId); mDirection = direction; mLocalAddress = localAddress; mRemoteAddress = remoteAddress; @@ -659,7 +621,7 @@ public class IpSecService extends IIpSecService.Stub { /** always guarded by IpSecService#this */ @Override - protected void releaseResources() { + public void freeUnderlyingResources() { if (mOwnedByTransform) { Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); // Because SPIs are "handed off" to transform, objects, they should never be @@ -682,11 +644,8 @@ public class IpSecService extends IIpSecService.Stub { } mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - } - @Override - protected ResourceTracker getResourceTracker() { - return mUserQuotaTracker.getUserRecord(this.uid).spi; + getResourceTracker().give(); } public int getSpi() { @@ -702,6 +661,16 @@ public class IpSecService extends IIpSecService.Stub { mOwnedByTransform = true; } + @Override + public void invalidate() throws RemoteException { + getUserRecord().removeSpiRecord(mResourceId); + } + + @Override + protected ResourceTracker getResourceTracker() { + return getUserRecord().mSpiQuotaTracker; + } + @Override public String toString() { StringBuilder strBuilder = new StringBuilder(); @@ -723,27 +692,24 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class UdpSocketRecord extends KernelResource { + private final class EncapSocketRecord extends KernelResourceRecord { private FileDescriptor mSocket; private final int mPort; - UdpSocketRecord(int resourceId, IBinder binder, FileDescriptor socket, int port) { - super(resourceId, binder); + EncapSocketRecord(int resourceId, FileDescriptor socket, int port) { + super(resourceId); mSocket = socket; mPort = port; } /** always guarded by IpSecService#this */ @Override - protected void releaseResources() { + public void freeUnderlyingResources() { Log.d(TAG, "Closing port " + mPort); IoUtils.closeQuietly(mSocket); mSocket = null; - } - @Override - protected ResourceTracker getResourceTracker() { - return mUserQuotaTracker.getUserRecord(this.uid).socket; + getResourceTracker().give(); } public int getPort() { @@ -754,6 +720,16 @@ public class IpSecService extends IIpSecService.Stub { return mSocket; } + @Override + protected ResourceTracker getResourceTracker() { + return getUserRecord().mSocketQuotaTracker; + } + + @Override + public void invalidate() { + getUserRecord().removeEncapSocketRecord(mResourceId); + } + @Override public String toString() { return new StringBuilder() @@ -861,13 +837,14 @@ public class IpSecService extends IIpSecService.Stub { /* requestedSpi can be anything in the int range, so no check is needed. */ checkNotNull(binder, "Null Binder passed to reserveSecurityParameterIndex"); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); int resourceId = mNextResourceId.getAndIncrement(); int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; String localAddress = ""; try { - if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).spi.isAvailable()) { + if (!userRecord.mSpiQuotaTracker.isAvailable()) { return new IpSecSpiResponse( IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } @@ -881,9 +858,11 @@ public class IpSecService extends IIpSecService.Stub { remoteAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); - mSpiRecords.put( + userRecord.mSpiRecords.put( resourceId, - new SpiRecord(resourceId, binder, direction, localAddress, remoteAddress, spi)); + new RefcountedResource( + new SpiRecord(resourceId, direction, localAddress, remoteAddress, spi), + binder)); } catch (ServiceSpecificException e) { // TODO: Add appropriate checks when other ServiceSpecificException types are supported return new IpSecSpiResponse( @@ -897,26 +876,17 @@ public class IpSecService extends IIpSecService.Stub { /* This method should only be called from Binder threads. Do not call this from * within the system server as it will crash the system on failure. */ - private synchronized void releaseKernelResource( - KernelResourceArray resArray, int resourceId, String typeName) + private void releaseResource(RefcountedResourceArray resArray, int resourceId) throws RemoteException { - // We want to non-destructively get so that we can check credentials before removing - // this from the records. - T record = resArray.getAndCheckOwner(resourceId); - if (record == null) { - throw new IllegalArgumentException( - typeName + " " + resourceId + " is not available to be deleted"); - } - - record.release(); - resArray.remove(resourceId); + resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); } /** Release a previously allocated SPI that has been registered with the system server */ @Override - public void releaseSecurityParameterIndex(int resourceId) throws RemoteException { - releaseKernelResource(mSpiRecords, resourceId, "SecurityParameterIndex"); + public synchronized void releaseSecurityParameterIndex(int resourceId) throws RemoteException { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + releaseResource(userRecord.mSpiRecords, resourceId); } /** @@ -969,10 +939,11 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { - if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).socket.isAvailable()) { + if (!userRecord.mSocketQuotaTracker.isAvailable()) { return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } @@ -991,8 +962,10 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mUdpSocketRecords.put( - resourceId, new UdpSocketRecord(resourceId, binder, sockFd, port)); + userRecord.mEncapSocketRecords.put( + resourceId, + new RefcountedResource( + new EncapSocketRecord(resourceId, sockFd, port), binder)); return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd); } catch (IOException | ErrnoException e) { IoUtils.closeQuietly(sockFd); @@ -1004,9 +977,9 @@ public class IpSecService extends IIpSecService.Stub { /** close a socket that has been been allocated by and registered with the system server */ @Override - public void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { - - releaseKernelResource(mUdpSocketRecords, resourceId, "UdpEncapsulationSocket"); + public synchronized void closeUdpEncapsulationSocket(int resourceId) throws RemoteException { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + releaseResource(userRecord.mEncapSocketRecords, resourceId); } /** @@ -1014,6 +987,8 @@ public class IpSecService extends IIpSecService.Stub { * IllegalArgumentException if they are not. */ private void checkIpSecConfig(IpSecConfig config) { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + if (config.getLocalAddress() == null) { throw new IllegalArgumentException("Invalid null Local InetAddress"); } @@ -1042,12 +1017,9 @@ public class IpSecService extends IIpSecService.Stub { break; case IpSecTransform.ENCAP_ESPINUDP: case IpSecTransform.ENCAP_ESPINUDP_NON_IKE: - if (mUdpSocketRecords.getAndCheckOwner( - config.getEncapSocketResourceId()) == null) { - throw new IllegalStateException( - "No Encapsulation socket for Resource Id: " - + config.getEncapSocketResourceId()); - } + // Retrieve encap socket record; will throw IllegalArgumentException if not found + userRecord.mEncapSocketRecords.getResourceOrThrow( + config.getEncapSocketResourceId()); int port = config.getEncapRemotePort(); if (port <= 0 || port > 0xFFFF) { @@ -1071,9 +1043,8 @@ public class IpSecService extends IIpSecService.Stub { + " exclusive with other Authentication or Encryption algorithms"); } - if (mSpiRecords.getAndCheckOwner(config.getSpiResourceId(direction)) == null) { - throw new IllegalStateException("No SPI for specified Resource Id"); - } + // Retrieve SPI record; will throw IllegalArgumentException if not found + userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction)); } } @@ -1090,16 +1061,27 @@ public class IpSecService extends IIpSecService.Stub { checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransportModeTransform"); int resourceId = mNextResourceId.getAndIncrement(); - if (!mUserQuotaTracker.getUserRecord(Binder.getCallingUid()).transform.isAvailable()) { + + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + + // Avoid resizing by creating a dependency array of min-size 3 (1 UDP encap + 2 SPIs) + List dependencies = new ArrayList<>(3); + + if (!userRecord.mTransformQuotaTracker.isAvailable()) { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; int encapType, encapLocalPort = 0, encapRemotePort = 0; - UdpSocketRecord socketRecord = null; + EncapSocketRecord socketRecord = null; encapType = c.getEncapType(); if (encapType != IpSecTransform.ENCAP_NONE) { - socketRecord = mUdpSocketRecords.getAndCheckOwner(c.getEncapSocketResourceId()); + RefcountedResource refcountedSocketRecord = + userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow( + c.getEncapSocketResourceId()); + dependencies.add(refcountedSocketRecord); + + socketRecord = refcountedSocketRecord.getResource(); encapLocalPort = socketRecord.getPort(); encapRemotePort = c.getEncapRemotePort(); } @@ -1109,7 +1091,12 @@ public class IpSecService extends IIpSecService.Stub { IpSecAlgorithm crypt = c.getEncryption(direction); IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction); - spis[direction] = mSpiRecords.getAndCheckOwner(c.getSpiResourceId(direction)); + RefcountedResource refcountedSpiRecord = + userRecord.mSpiRecords.getRefcountedResourceOrThrow( + c.getSpiResourceId(direction)); + dependencies.add(refcountedSpiRecord); + + spis[direction] = refcountedSpiRecord.getResource(); int spi = spis[direction].getSpi(); try { mSrvConfig @@ -1140,8 +1127,12 @@ public class IpSecService extends IIpSecService.Stub { } } // Both SAs were created successfully, time to construct a record and lock it away - mTransformRecords.put( - resourceId, new TransformRecord(resourceId, binder, c, spis, socketRecord)); + userRecord.mTransformRecords.put( + resourceId, + new RefcountedResource( + new TransformRecord(resourceId, c, spis, socketRecord), + binder, + dependencies.toArray(new RefcountedResource[dependencies.size()]))); return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); } @@ -1152,8 +1143,9 @@ public class IpSecService extends IIpSecService.Stub { * other reasons. */ @Override - public void deleteTransportModeTransform(int resourceId) throws RemoteException { - releaseKernelResource(mTransformRecords, resourceId, "IpSecTransform"); + public synchronized void deleteTransportModeTransform(int resourceId) throws RemoteException { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + releaseResource(userRecord.mTransformRecords, resourceId); } /** @@ -1163,14 +1155,10 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTransportModeTransform( ParcelFileDescriptor socket, int resourceId) throws RemoteException { - // Synchronize liberally here because we are using KernelResources in this block - TransformRecord info; - // FIXME: this code should be factored out into a security check + getter - info = mTransformRecords.getAndCheckOwner(resourceId); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - if (info == null) { - throw new IllegalArgumentException("Transform " + resourceId + " is not active"); - } + // Get transform record; if no transform is found, will throw IllegalArgumentException + TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); // TODO: make this a function. if (info.pid != getCallingPid() || info.uid != getCallingUid()) { @@ -1202,7 +1190,7 @@ public class IpSecService extends IIpSecService.Stub { * used: reserved for future improved input validation. */ @Override - public void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) + public synchronized void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) throws RemoteException { try { mSrvConfig @@ -1221,13 +1209,7 @@ public class IpSecService extends IIpSecService.Stub { pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); - pw.println("mUserQuotaTracker:"); - pw.println(mUserQuotaTracker); - pw.println("mTransformRecords:"); - pw.println(mTransformRecords); - pw.println("mUdpSocketRecords:"); - pw.println(mUdpSocketRecords); - pw.println("mSpiRecords:"); - pw.println(mSpiRecords); + pw.println("mUserResourceTracker:"); + pw.println(mUserResourceTracker); } } From 2dc65324056784824acfb4c5eda00ba5191c8083 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 13 Dec 2017 20:05:05 -0700 Subject: [PATCH 0437/1150] Add more IntDef prefixes for auto-documenting. Test: builds, boots Bug: 70177949 Exempt-From-Owner-Approval: annotation-only changes Change-Id: I76dde6054e06f52240bd4b1a0f196dcb74623608 --- core/java/android/app/usage/NetworkStats.java | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 222e9a0e5e..2e44a630b0 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -129,7 +129,11 @@ public final class NetworkStats implements AutoCloseable { */ public static class Bucket { /** @hide */ - @IntDef({STATE_ALL, STATE_DEFAULT, STATE_FOREGROUND}) + @IntDef(prefix = { "STATE_" }, value = { + STATE_ALL, + STATE_DEFAULT, + STATE_FOREGROUND + }) @Retention(RetentionPolicy.SOURCE) public @interface State {} @@ -164,7 +168,11 @@ public final class NetworkStats implements AutoCloseable { public static final int UID_TETHERING = TrafficStats.UID_TETHERING; /** @hide */ - @IntDef({METERED_ALL, METERED_NO, METERED_YES}) + @IntDef(prefix = { "METERED_" }, value = { + METERED_ALL, + METERED_NO, + METERED_YES + }) @Retention(RetentionPolicy.SOURCE) public @interface Metered {} @@ -187,7 +195,11 @@ public final class NetworkStats implements AutoCloseable { public static final int METERED_YES = 0x2; /** @hide */ - @IntDef({ROAMING_ALL, ROAMING_NO, ROAMING_YES}) + @IntDef(prefix = { "ROAMING_" }, value = { + ROAMING_ALL, + ROAMING_NO, + ROAMING_YES + }) @Retention(RetentionPolicy.SOURCE) public @interface Roaming {} From f5c1f305278e13c9f88633526bc3bb1d6e62fdde Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 29 Nov 2017 11:18:23 -0700 Subject: [PATCH 0438/1150] [CHERRY-PICK] API for apps to tag sockets with their own UID. This enables app A to create a socket, pass it to app B, and have app B accept blame for the traffic performed on that socket. Also adds helpful public APIs for tagging raw FileDescriptor sockets instead of making developers go through shady SocketImpl wrappers. Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AppSecurityTests#testAppFailAccessPrivateData Bug: 63932076 Change-Id: I08925c843974675fc82e4080cec2eaab9ab7cd41 Merged-In: I08925c843974675fc82e4080cec2eaab9ab7cd41 (cherry picked from commit 152b263678b431d3e666ffa322827d608faf51f2) --- core/java/android/net/TrafficStats.java | 39 +++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index c339856f43..954e59c2c4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.RequiresPermission; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.DownloadManager; import android.app.backup.BackupManager; @@ -30,6 +31,8 @@ import com.android.server.NetworkManagementSocketTagger; import dalvik.system.SocketTagger; +import java.io.FileDescriptor; +import java.io.IOException; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -263,15 +266,26 @@ public class TrafficStats { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } + /** + * Set specific UID to use when accounting {@link Socket} traffic + * originating from the current thread as the calling UID. Designed for use + * when another application is performing operations on your behalf. + *

            + * Changes only take effect during subsequent calls to + * {@link #tagSocket(Socket)}. + */ + public static void setThreadStatsUidSelf() { + setThreadStatsUid(android.os.Process.myUid()); + } + /** * Clear any active UID set to account {@link Socket} traffic originating * from the current thread. * * @see #setThreadStatsUid(int) - * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @SuppressLint("Doclava125") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } @@ -315,6 +329,27 @@ public class TrafficStats { SocketTagger.get().untag(socket); } + /** + * Tag the given {@link FileDescriptor} socket with any statistics + * parameters active for the current thread. Subsequent calls always replace + * any existing parameters. When finished, call + * {@link #untagFileDescriptor(FileDescriptor)} to remove statistics + * parameters. + * + * @see #setThreadStatsTag(int) + */ + public static void tagFileDescriptor(FileDescriptor fd) throws IOException { + SocketTagger.get().tag(fd); + } + + /** + * Remove any statistics parameters from the given {@link FileDescriptor} + * socket. + */ + public static void untagFileDescriptor(FileDescriptor fd) throws IOException { + SocketTagger.get().untag(fd); + } + /** * Start profiling data usage for current UID. Only one profiling session * can be active at a time. From 8231eaffb0374f2f62e9ee492c98916ec1f02255 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Sun, 3 Dec 2017 19:42:36 -0800 Subject: [PATCH 0439/1150] [ipsec-qtaguid] Tag sockets upon creation of encap sockets Added calls to tag encap sockets to that of the UID for which the encap socket is being created on behalf of. This ensures that all data accounting generated for the UDP-encap-ESP socket is correctly billed to the right UID. Bug: 62994731 Test: New tests added to IpSecServiceTest.java, passing Change-Id: I15365ea9c982fd7b4e3cdeff314ddfba2289c86e --- core/java/android/net/TrafficStats.java | 27 ++++++++++++ .../java/com/android/server/IpSecService.java | 41 ++++++++++++++++++- 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 954e59c2c4..d701550817 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; @@ -154,6 +155,8 @@ public class TrafficStats { private static Object sProfilingLock = new Object(); + private static final String LOOPBACK_IFACE = "lo"; + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -542,6 +545,30 @@ public class TrafficStats { return nativeGetIfaceStat(iface, TYPE_RX_BYTES); } + /** {@hide} */ + @TestApi + public static long getLoopbackTxPackets() { + return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_PACKETS); + } + + /** {@hide} */ + @TestApi + public static long getLoopbackRxPackets() { + return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_PACKETS); + } + + /** {@hide} */ + @TestApi + public static long getLoopbackTxBytes() { + return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_BYTES); + } + + /** {@hide} */ + @TestApi + public static long getLoopbackRxBytes() { + return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_BYTES); + } + /** * Return number of packets transmitted since device boot. Counts packets * across all network interfaces, and always increases monotonically since diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index e9eb3b3c46..a764808368 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -34,6 +34,7 @@ import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecUdpEncapResponse; import android.net.NetworkUtils; +import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; @@ -120,6 +121,7 @@ public class IpSecService extends IIpSecService.Stub { } private final IpSecServiceConfiguration mSrvConfig; + final UidFdTagger mUidFdTagger; /** * Interface for user-reference and kernel-resource cleanup. @@ -762,8 +764,23 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { + this(context, config, (fd, uid) -> { + try{ + TrafficStats.setThreadStatsUid(uid); + TrafficStats.tagFileDescriptor(fd); + } finally { + TrafficStats.clearThreadStatsUid(); + } + }); + } + + /** @hide */ + @VisibleForTesting + public IpSecService( + Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; mSrvConfig = config; + mUidFdTagger = uidFdTagger; } public void systemReady() { @@ -924,6 +941,26 @@ public class IpSecService extends IIpSecService.Stub { throw new IOException("Failed " + MAX_PORT_BIND_ATTEMPTS + " attempts to bind to a port"); } + /** + * Functional interface to do traffic tagging of given sockets to UIDs. + * + *

            Specifically used by openUdpEncapsulationSocket to ensure data usage on the UDP encap + * sockets are billed to the UID that the UDP encap socket was created on behalf of. + * + *

            Separate class so that the socket tagging logic can be mocked; TrafficStats uses static + * methods that cannot be easily mocked/tested. + */ + @VisibleForTesting + public interface UidFdTagger { + /** + * Sets socket tag to assign all traffic to the provided UID. + * + *

            Since the socket is created on behalf of an unprivileged application, all traffic + * should be accounted to the UID of the unprivileged application. + */ + public void tag(FileDescriptor fd, int uid) throws IOException; + } + /** * Open a socket via the system server and bind it to the specified port (random if port=0). * This will return a PFD to the user that represent a bound UDP socket. The system server will @@ -939,7 +976,8 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); int resourceId = mNextResourceId.getAndIncrement(); FileDescriptor sockFd = null; try { @@ -948,6 +986,7 @@ public class IpSecService extends IIpSecService.Stub { } sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + mUidFdTagger.tag(sockFd, callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); From d8d9ba425902040e763e224851a5ebea61f3e4df Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 6 Dec 2017 21:56:35 -0800 Subject: [PATCH 0440/1150] [ipsec-doze] Add fchown to IpSecService to support doze Encap sockets are currently created as the system server, and should be fchown'd to the user for whom it was created on behalf of. Bug: 62994731 Test: New tests added and run to IpSecService Change-Id: Icc49e709ae588981e69765fdb77537d7ffbac5fe --- .../core/java/com/android/server/IpSecService.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a764808368..d3ab1259c9 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -988,12 +988,6 @@ public class IpSecService extends IIpSecService.Stub { sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); mUidFdTagger.tag(sockFd, callingUid); - if (port != 0) { - Log.v(TAG, "Binding to port " + port); - Os.bind(sockFd, INADDR_ANY, port); - } else { - port = bindToRandomPort(sockFd); - } // This code is common to both the unspecified and specified port cases Os.setsockoptInt( sockFd, @@ -1001,6 +995,14 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); + mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(sockFd, callingUid); + if (port != 0) { + Log.v(TAG, "Binding to port " + port); + Os.bind(sockFd, INADDR_ANY, port); + } else { + port = bindToRandomPort(sockFd); + } + userRecord.mEncapSocketRecords.put( resourceId, new RefcountedResource( From 65b99191e6f665ee5c3424da4010ed536f94f75c Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 14 Nov 2017 17:54:17 -0800 Subject: [PATCH 0441/1150] Use NetworkStatsService to get stats for apps Move the native implementation of TrafficStats to NetworkStatsService and apps need to get the NetworkStatsService binder interface from system_server in order to get the network usage stats since boot. This implementation can hide the detail of retrieving network traffic information from apps and the NetworkStatsService can choose which methoed it use to get the data depending on the kernel version of the device. Bug: 30950746 Test: CtsNetTestCases -t android.net.cts.TrafficStatsTest Change-Id: I53bbefd19aa0b783b9b4b42ea4d76db3e9ec07a3 --- .../android/net/INetworkStatsService.aidl | 9 ++ core/java/android/net/TrafficStats.java | 114 ++++++++++++++---- .../server/net/NetworkStatsService.java | 26 ++++ ...android_server_net_NetworkStatsService.cpp | 22 +++- 4 files changed, 146 insertions(+), 25 deletions(-) rename core/jni/android_net_TrafficStats.cpp => services/core/jni/com_android_server_net_NetworkStatsService.cpp (80%) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 91801127fd..95e7f6031c 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -67,4 +67,13 @@ interface INetworkStatsService { /** Unregisters a callback on data usage. */ void unregisterUsageRequest(in DataUsageRequest request); + /** Get the uid stats information since boot */ + long getUidStats(int uid, int type); + + /** Get the iface stats information since boot */ + long getIfaceStats(String iface, int type); + + /** Get the total network stats information since boot */ + long getTotalStats(int type); + } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index d701550817..196a3bc9c8 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -505,7 +505,12 @@ public class TrafficStats { public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { - final long stat = nativeGetIfaceStat(iface, TYPE_TCP_RX_PACKETS); + long stat = UNSUPPORTED; + try { + stat = getStatsService().getIfaceStats(iface, TYPE_TCP_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } if (stat != UNSUPPORTED) { total += stat; } @@ -517,7 +522,12 @@ public class TrafficStats { public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { - final long stat = nativeGetIfaceStat(iface, TYPE_TCP_TX_PACKETS); + long stat = UNSUPPORTED; + try { + stat = getStatsService().getIfaceStats(iface, TYPE_TCP_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } if (stat != UNSUPPORTED) { total += stat; } @@ -527,46 +537,78 @@ public class TrafficStats { /** {@hide} */ public static long getTxPackets(String iface) { - return nativeGetIfaceStat(iface, TYPE_TX_PACKETS); + try { + return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ public static long getRxPackets(String iface) { - return nativeGetIfaceStat(iface, TYPE_RX_PACKETS); + try { + return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ public static long getTxBytes(String iface) { - return nativeGetIfaceStat(iface, TYPE_TX_BYTES); + try { + return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ public static long getRxBytes(String iface) { - return nativeGetIfaceStat(iface, TYPE_RX_BYTES); + try { + return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ @TestApi public static long getLoopbackTxPackets() { - return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_PACKETS); + try { + return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ @TestApi public static long getLoopbackRxPackets() { - return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_PACKETS); + try { + return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ @TestApi public static long getLoopbackTxBytes() { - return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_TX_BYTES); + try { + return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** {@hide} */ @TestApi public static long getLoopbackRxBytes() { - return nativeGetIfaceStat(LOOPBACK_IFACE, TYPE_RX_BYTES); + try { + return getStatsService().getIfaceStats(LOOPBACK_IFACE, TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -579,7 +621,11 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxPackets() { - return nativeGetTotalStat(TYPE_TX_PACKETS); + try { + return getStatsService().getTotalStats(TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -592,7 +638,11 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxPackets() { - return nativeGetTotalStat(TYPE_RX_PACKETS); + try { + return getStatsService().getTotalStats(TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -605,7 +655,11 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalTxBytes() { - return nativeGetTotalStat(TYPE_TX_BYTES); + try { + return getStatsService().getTotalStats(TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -618,7 +672,11 @@ public class TrafficStats { * return {@link #UNSUPPORTED} on devices where statistics aren't available. */ public static long getTotalRxBytes() { - return nativeGetTotalStat(TYPE_RX_BYTES); + try { + return getStatsService().getTotalStats(TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -644,7 +702,11 @@ public class TrafficStats { // unsupported value. The real filtering is done at the kernel level. final int callingUid = android.os.Process.myUid(); if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - return nativeGetUidStat(uid, TYPE_TX_BYTES); + try { + return getStatsService().getUidStats(uid, TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } else { return UNSUPPORTED; } @@ -673,7 +735,11 @@ public class TrafficStats { // unsupported value. The real filtering is done at the kernel level. final int callingUid = android.os.Process.myUid(); if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - return nativeGetUidStat(uid, TYPE_RX_BYTES); + try { + return getStatsService().getUidStats(uid, TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } else { return UNSUPPORTED; } @@ -702,7 +768,11 @@ public class TrafficStats { // unsupported value. The real filtering is done at the kernel level. final int callingUid = android.os.Process.myUid(); if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - return nativeGetUidStat(uid, TYPE_TX_PACKETS); + try { + return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } else { return UNSUPPORTED; } @@ -731,7 +801,11 @@ public class TrafficStats { // unsupported value. The real filtering is done at the kernel level. final int callingUid = android.os.Process.myUid(); if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - return nativeGetUidStat(uid, TYPE_RX_PACKETS); + try { + return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } else { return UNSUPPORTED; } @@ -859,8 +933,4 @@ public class TrafficStats { private static final int TYPE_TX_PACKETS = 3; private static final int TYPE_TCP_RX_PACKETS = 4; private static final int TYPE_TCP_TX_PACKETS = 5; - - private static native long nativeGetTotalStat(int type); - private static native long nativeGetIfaceStat(String iface, int type); - private static native long nativeGetUidStat(int uid, int type); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3af5265e6f..db61ef5cd9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -873,6 +873,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @Override + public long getUidStats(int uid, int type) { + return nativeGetUidStat(uid, type); + } + + @Override + public long getIfaceStats(String iface, int type) { + return nativeGetIfaceStat(iface, type); + } + + @Override + public long getTotalStats(int type) { + return nativeGetTotalStat(type); + } + /** * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to * reflect current {@link #mPersistThreshold} value. Always defers to @@ -1626,4 +1641,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); } } + + private static int TYPE_RX_BYTES; + private static int TYPE_RX_PACKETS; + private static int TYPE_TX_BYTES; + private static int TYPE_TX_PACKETS; + private static int TYPE_TCP_RX_PACKETS; + private static int TYPE_TCP_TX_PACKETS; + + private static native long nativeGetTotalStat(int type); + private static native long nativeGetIfaceStat(String iface, int type); + private static native long nativeGetUidStat(int uid, int type); } diff --git a/core/jni/android_net_TrafficStats.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp similarity index 80% rename from core/jni/android_net_TrafficStats.cpp rename to services/core/jni/com_android_server_net_NetworkStatsService.cpp index d0c237da07..8de24e5565 100644 --- a/core/jni/android_net_TrafficStats.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#define LOG_TAG "TrafficStats" +#define LOG_TAG "NetworkStatsNative" #include #include @@ -191,8 +191,24 @@ static const JNINativeMethod gMethods[] = { {"nativeGetUidStat", "(II)J", (void*) getUidStat}, }; -int register_android_net_TrafficStats(JNIEnv* env) { - return RegisterMethodsOrDie(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); +int register_android_server_net_NetworkStatsService(JNIEnv* env) { + jclass netStatsService = env->FindClass("com/android/server/net/NetworkStatsService"); + jfieldID rxBytesId = env->GetStaticFieldID(netStatsService, "TYPE_RX_BYTES", "I"); + jfieldID rxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_RX_PACKETS", "I"); + jfieldID txBytesId = env->GetStaticFieldID(netStatsService, "TYPE_TX_BYTES", "I"); + jfieldID txPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TX_PACKETS", "I"); + jfieldID tcpRxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_RX_PACKETS", "I"); + jfieldID tcpTxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_TX_PACKETS", "I"); + + env->SetStaticIntField(netStatsService, rxBytesId, RX_BYTES); + env->SetStaticIntField(netStatsService, rxPacketsId, RX_PACKETS); + env->SetStaticIntField(netStatsService, txBytesId, TX_BYTES); + env->SetStaticIntField(netStatsService, txPacketsId, TX_PACKETS); + env->SetStaticIntField(netStatsService, tcpRxPacketsId, TCP_RX_PACKETS); + env->SetStaticIntField(netStatsService, tcpTxPacketsId, TCP_TX_PACKETS); + + return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods, + NELEM(gMethods)); } } From 860d1ee24786f6eed7528cb96d3c391f677d8262 Mon Sep 17 00:00:00 2001 From: Tetsutoki Shiozawa Date: Fri, 27 Oct 2017 14:03:00 +0900 Subject: [PATCH 0442/1150] Definitely abort reconnecting to native daemon during shutdown Symptom: System_server crashed due to unsolved "netd" service. Root cause: My previous patch was not enough for avoiding this crash. a00d4b0 Abort connecting to native daemon during shutdown listenToSocket loop can be finished without throwing exception. Solution: It's better to test shutdown condition before reconnection even though listenToSocket is finished without exception. Bug: 68742327 Change-Id: Ifdfe43d52bef891f55bd7b07cc1aa0fa248a6030 --- .../com/android/server/NativeDaemonConnector.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index b5a8332375..ad02aad6e4 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -134,21 +134,23 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo mCallbackHandler = new Handler(mLooper, this); while (true) { + if (isShuttingDown()) break; try { listenToSocket(); } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); - String shutdownAct = SystemProperties.get( - ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); - if (shutdownAct != null && shutdownAct.length() > 0) { - // The device is in middle of shutdown. - break; - } + if (isShuttingDown()) break; SystemClock.sleep(5000); } } } + private static boolean isShuttingDown() { + String shutdownAct = SystemProperties.get( + ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); + return shutdownAct != null && shutdownAct.length() > 0; + } + @Override public boolean handleMessage(Message msg) { final String event = (String) msg.obj; From 36410728d9184543ecaa4205a546a4c4a31e7ab5 Mon Sep 17 00:00:00 2001 From: manojboopathi Date: Thu, 30 Nov 2017 17:11:49 -0800 Subject: [PATCH 0443/1150] Fix CTS Test Dual Stack Test Passing Issue CTS test should fail if IPV6 Sockets is used on IPV4 address. Unfortunately its been passing fine due to unhandled catch exception. This is fixed in this CL. Bug: 64435904 Test: Ran CTS test to verify ./run_cts.sh Change-Id: I369c1b5baaa64b64feaa3f298e61f46d1200ea17 --- services/core/java/com/android/server/IpSecService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d3ab1259c9..989cb886c1 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -19,6 +19,7 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; @@ -1220,7 +1221,11 @@ public class IpSecService extends IIpSecService.Stub { info.getSpiRecord(direction).getSpi()); } } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception + if (e.errorCode == EINVAL) { + throw new IllegalArgumentException(e.toString()); + } else { + throw e; + } } } From 5149f29b41220be147c1df3aa90a955dc29cb5e4 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 13 Dec 2017 18:51:35 -0800 Subject: [PATCH 0444/1150] IpSec Invalidate the Resource IDs on close() To facilitate error checking we should invalidate the resource IDs of all objects when we close() them. Today, the resource ID is invalidated on the Transform object but not on the SPI or Encap Socket. This CL unifies the behavior. Bug: 70641274 Test: cts - IpSecManagerTest Change-Id: I28caec3e913902c748c6a50b4ef742ccef8b1b09 --- core/java/android/net/IpSecConfig.java | 6 ------ core/java/android/net/IpSecManager.java | 8 +++++--- core/java/android/net/IpSecTransform.java | 17 +++++++++++++++-- 3 files changed, 20 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index e6cd3fc130..f54ceb5c14 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -102,17 +102,11 @@ public final class IpSecConfig implements Parcelable { /** Set the local IP address for Tunnel mode */ public void setLocalAddress(String localAddress) { - if (localAddress == null) { - throw new IllegalArgumentException("localAddress may not be null!"); - } mLocalAddress = localAddress; } /** Set the remote IP address for this IPsec transform */ public void setRemoteAddress(String remoteAddress) { - if (remoteAddress == null) { - throw new IllegalArgumentException("remoteAddress may not be null!"); - } mRemoteAddress = remoteAddress; } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 6a4b891478..34cfa9b215 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -69,7 +69,7 @@ public final class IpSecManager { } /** @hide */ - public static final int INVALID_RESOURCE_ID = 0; + public static final int INVALID_RESOURCE_ID = -1; /** * Thrown to indicate that a requested SPI is in use. @@ -128,7 +128,7 @@ public final class IpSecManager { private final InetAddress mRemoteAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; - private int mResourceId; + private int mResourceId = INVALID_RESOURCE_ID; /** Get the underlying SPI held by this object. */ public int getSpi() { @@ -146,6 +146,7 @@ public final class IpSecManager { public void close() { try { mService.releaseSecurityParameterIndex(mResourceId); + mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -501,7 +502,7 @@ public final class IpSecManager { public static final class UdpEncapsulationSocket implements AutoCloseable { private final ParcelFileDescriptor mPfd; private final IIpSecService mService; - private final int mResourceId; + private int mResourceId = INVALID_RESOURCE_ID; private final int mPort; private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -554,6 +555,7 @@ public final class IpSecManager { public void close() throws IOException { try { mService.closeUdpEncapsulationSocket(mResourceId); + mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 7cd742b417..102ba6d94f 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -347,6 +347,9 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform.Builder setSpi( @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { + if (spi.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid SecurityParameterIndex"); + } mConfig.setSpiResourceId(direction, spi.getResourceId()); return this; } @@ -381,6 +384,9 @@ public final class IpSecTransform implements AutoCloseable { public IpSecTransform.Builder setIpv4Encapsulation( IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { mConfig.setEncapType(ENCAP_ESPINUDP); + if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); + } mConfig.setEncapSocketResourceId(localSocket.getResourceId()); mConfig.setEncapRemotePort(remotePort); return this; @@ -426,6 +432,9 @@ public final class IpSecTransform implements AutoCloseable { public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { + if (remoteAddress == null) { + throw new IllegalArgumentException("Remote address may not be null or empty!"); + } mConfig.setMode(MODE_TRANSPORT); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); // FIXME: modifying a builder after calling build can change the built transform. @@ -447,8 +456,12 @@ public final class IpSecTransform implements AutoCloseable { */ public IpSecTransform buildTunnelModeTransform( InetAddress localAddress, InetAddress remoteAddress) { - // FIXME: argument validation here - // throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation"); + if (localAddress == null) { + throw new IllegalArgumentException("Local address may not be null or empty!"); + } + if (remoteAddress == null) { + throw new IllegalArgumentException("Remote address may not be null or empty!"); + } mConfig.setLocalAddress(localAddress.getHostAddress()); mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setMode(MODE_TUNNEL); From eabfcac87fbdaf8d0ab4549278c36dbea48571f1 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 13 Dec 2017 19:16:33 -0800 Subject: [PATCH 0445/1150] IpSecService - Convert mNextResourceId from AtomicInt to Int The mNextResourceId variable is only accessed within synchronized blocks, so there is no need to use an atomic integer to synchronize it. This eliminates the misleading notion that the variable is accessed outside of guarded blocks, which it is not. Bug: 62279167 Test: cts Change-Id: I815835622659f54d2d2d33b349b17c632ebced8d --- .../java/com/android/server/IpSecService.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 989cb886c1..5c098e3204 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -102,8 +102,14 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; - /** Should be a never-repeating global ID for resources */ - private static AtomicInteger mNextResourceId = new AtomicInteger(0x00FADED0); + /** + * The next non-repeating global ID for tracking resources between users, this service, + * and kernel data structures. Accessing this variable is not thread safe, so it is + * only read or modified within blocks synchronized on IpSecService.this. We want to + * avoid -1 (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). + */ + @GuardedBy("IpSecService.this") + private int mNextResourceId = 1; interface IpSecServiceConfiguration { INetd getNetdInstance() throws RemoteException; @@ -856,7 +862,7 @@ public class IpSecService extends IIpSecService.Stub { checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - int resourceId = mNextResourceId.getAndIncrement(); + final int resourceId = mNextResourceId++; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; String localAddress = ""; @@ -979,7 +985,7 @@ public class IpSecService extends IIpSecService.Stub { int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); - int resourceId = mNextResourceId.getAndIncrement(); + final int resourceId = mNextResourceId++; FileDescriptor sockFd = null; try { if (!userRecord.mSocketQuotaTracker.isAvailable()) { @@ -1102,7 +1108,7 @@ public class IpSecService extends IIpSecService.Stub { IpSecConfig c, IBinder binder) throws RemoteException { checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransportModeTransform"); - int resourceId = mNextResourceId.getAndIncrement(); + final int resourceId = mNextResourceId++; UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From aac9965a8921e3f5837996e130283b3f8a19a2a0 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 6 Nov 2017 20:49:10 -0800 Subject: [PATCH 0446/1150] Add validation to IpSecConfig algorithm setters Adds checks to ensure that users can only set the correct types of algorithms for the Authentication, Encryption and Authenticated Encryption algorithms. Bug: 65223935 Test: Added tests in IpSecConfigTest, and passed on aosp_marlin-eng Change-Id: I462c77d9eb5710b8d03a48866453649d3b6fc6bf --- core/java/android/net/IpSecAlgorithm.java | 25 +++++++++++++ .../java/com/android/server/IpSecService.java | 37 +++++++++++++------ 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index f82627b942..7d752e89e6 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -231,6 +231,31 @@ public final class IpSecAlgorithm implements Parcelable { } } + /** @hide */ + public boolean isAuthentication() { + switch (getName()) { + // Fallthrough + case AUTH_HMAC_MD5: + case AUTH_HMAC_SHA1: + case AUTH_HMAC_SHA256: + case AUTH_HMAC_SHA384: + case AUTH_HMAC_SHA512: + return true; + default: + return false; + } + } + + /** @hide */ + public boolean isEncryption() { + return getName().equals(CRYPT_AES_CBC); + } + + /** @hide */ + public boolean isAead() { + return getName().equals(AUTH_CRYPT_AES_GCM); + } + @Override public String toString() { return new StringBuilder() diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d3ab1259c9..232853898d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -51,6 +51,7 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.IOException; @@ -1023,6 +1024,30 @@ public class IpSecService extends IIpSecService.Stub { releaseResource(userRecord.mEncapSocketRecords, resourceId); } + @VisibleForTesting + void validateAlgorithms(IpSecConfig config, int direction) throws IllegalArgumentException { + IpSecAlgorithm auth = config.getAuthentication(direction); + IpSecAlgorithm crypt = config.getEncryption(direction); + IpSecAlgorithm aead = config.getAuthenticatedEncryption(direction); + + // Validate the algorithm set + Preconditions.checkArgument( + aead != null || crypt != null || auth != null, + "No Encryption or Authentication algorithms specified"); + Preconditions.checkArgument( + auth == null || auth.isAuthentication(), + "Unsupported algorithm for Authentication"); + Preconditions.checkArgument( + crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption"); + Preconditions.checkArgument( + aead == null || aead.isAead(), + "Unsupported algorithm for Authenticated Encryption"); + Preconditions.checkArgument( + aead == null || (auth == null && crypt == null), + "Authenticated Encryption is mutually exclusive with other Authentication " + + "or Encryption algorithms"); + } + /** * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an * IllegalArgumentException if they are not. @@ -1072,17 +1097,7 @@ public class IpSecService extends IIpSecService.Stub { } for (int direction : DIRECTIONS) { - IpSecAlgorithm crypt = config.getEncryption(direction); - IpSecAlgorithm auth = config.getAuthentication(direction); - IpSecAlgorithm authenticatedEncryption = config.getAuthenticatedEncryption(direction); - if (authenticatedEncryption == null && crypt == null && auth == null) { - throw new IllegalArgumentException( - "No Encryption or Authentication algorithms specified"); - } else if (authenticatedEncryption != null && (auth != null || crypt != null)) { - throw new IllegalArgumentException( - "Authenticated Encryption is mutually" - + " exclusive with other Authentication or Encryption algorithms"); - } + validateAlgorithms(config, direction); // Retrieve SPI record; will throw IllegalArgumentException if not found userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction)); From 69f6f06d2abe63e43e03135d29c5dfa533061ddf Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 7 Jan 2018 16:47:31 -0700 Subject: [PATCH 0447/1150] Add DataUnit to clarify SI-vs-IEC units. Mirrors the design of TimeUnit and ChronoUnit which many developers are already familiar with, making it easy to pick up and use. Yes, this is an enum. Bug: 70915728 Test: bit FrameworksCoreTests:android.util.DataUnitTest Change-Id: Id0cfdac5c81ed89c3c9ece23c964acba4a4f8471 --- core/java/android/net/TrafficStats.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 196a3bc9c8..bda720bb6f 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -27,6 +27,7 @@ import android.content.Context; import android.media.MediaPlayer; import android.os.RemoteException; import android.os.ServiceManager; +import android.util.DataUnit; import com.android.server.NetworkManagementSocketTagger; @@ -56,15 +57,20 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - /** @hide */ + /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + @Deprecated public static final long KB_IN_BYTES = 1024; - /** @hide */ + /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + @Deprecated public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; - /** @hide */ + /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + @Deprecated public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; - /** @hide */ + /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + @Deprecated public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; - /** @hide */ + /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + @Deprecated public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; /** From ce6d573795c11a6cd4cd822d8772a01fa5977099 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Fri, 5 Jan 2018 19:25:13 -0800 Subject: [PATCH 0448/1150] Make Transforms Unidirectional Convert the IpSecTransform from being a bi-directional pair of SAs to a unidirectional single SA. This CL also removes the concept of "direction from SAs meaning that a IpSecTransform may now be applied to a socket in either direction. -Make transforms unidirectional -Add Convert allocateSpi() to use destination rather than direction and remote address -Remove directionality from builders for IpSecTransform -Change applyTransportModeTransform() to take a direction in which to apply the transform object. -Additional minor naming updates -Restrict IpSecConfig to only print keys on eng builds -Move DIRECTION constants to IpSecManager -Add sourceAddress parameter to IpSecTransform to provide additional guarantees about the source address of data; (explicit failure rather than implicit failure). -Move SPI to the build() method of IpSecTransform Bug: 71717213 Test: runtest frameworks-net, CTS - IpSecManagerTest Change-Id: I0824b37f443f4b8c62536d9801238c63ed8f2a1c --- core/java/android/net/IIpSecService.aidl | 6 +- core/java/android/net/IpSecAlgorithm.java | 8 +- core/java/android/net/IpSecConfig.java | 183 ++++------ core/java/android/net/IpSecManager.java | 119 +++--- core/java/android/net/IpSecTransform.java | 155 +++----- .../java/com/android/server/IpSecService.java | 338 ++++++++---------- 6 files changed, 371 insertions(+), 438 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index d9b57db180..3fe531fd79 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -31,7 +31,7 @@ import android.os.ParcelFileDescriptor; interface IIpSecService { IpSecSpiResponse allocateSecurityParameterIndex( - int direction, in String remoteAddress, int requestedSpi, in IBinder binder); + in String destinationAddress, int requestedSpi, in IBinder binder); void releaseSecurityParameterIndex(int resourceId); @@ -43,7 +43,7 @@ interface IIpSecService void deleteTransportModeTransform(int transformId); - void applyTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); - void removeTransportModeTransform(in ParcelFileDescriptor socket, int transformId); + void removeTransportModeTransforms(in ParcelFileDescriptor socket, int transformId); } diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7d752e89e6..c69a4d4c0b 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -256,13 +256,19 @@ public final class IpSecAlgorithm implements Parcelable { return getName().equals(AUTH_CRYPT_AES_GCM); } + // Because encryption keys are sensitive and userdebug builds are used by large user pools + // such as beta testers, we only allow sensitive info such as keys on eng builds. + private static boolean isUnsafeBuild() { + return Build.IS_DEBUGGABLE && Build.IS_ENG; + } + @Override public String toString() { return new StringBuilder() .append("{mName=") .append(mName) .append(", mKey=") - .append(Build.IS_DEBUGGABLE ? HexDump.toHexString(mKey) : "") + .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "") .append(", mTruncLenBits=") .append(mTruncLenBits) .append("}") diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index f54ceb5c14..80b0af3373 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -32,59 +32,29 @@ public final class IpSecConfig implements Parcelable { // MODE_TRANSPORT or MODE_TUNNEL private int mMode = IpSecTransform.MODE_TRANSPORT; - // Needs to be valid only for tunnel mode // Preventing this from being null simplifies Java->Native binder - private String mLocalAddress = ""; + private String mSourceAddress = ""; // Preventing this from being null simplifies Java->Native binder - private String mRemoteAddress = ""; + private String mDestinationAddress = ""; // The underlying Network that represents the "gateway" Network // for outbound packets. It may also be used to select packets. private Network mNetwork; - /** - * This class captures the parameters that specifically apply to inbound or outbound traffic. - */ - public static class Flow { - // Minimum requirements for identifying a transform - // SPI identifying the IPsec flow in packet processing - // and a remote IP address - private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; + // Minimum requirements for identifying a transform + // SPI identifying the IPsec SA in packet processing + // and a destination IP address + private int mSpiResourceId = IpSecManager.INVALID_RESOURCE_ID; - // Encryption Algorithm - private IpSecAlgorithm mEncryption; + // Encryption Algorithm + private IpSecAlgorithm mEncryption; - // Authentication Algorithm - private IpSecAlgorithm mAuthentication; + // Authentication Algorithm + private IpSecAlgorithm mAuthentication; - // Authenticated Encryption Algorithm - private IpSecAlgorithm mAuthenticatedEncryption; - - @Override - public String toString() { - return new StringBuilder() - .append("{mSpiResourceId=") - .append(mSpiResourceId) - .append(", mEncryption=") - .append(mEncryption) - .append(", mAuthentication=") - .append(mAuthentication) - .append(", mAuthenticatedEncryption=") - .append(mAuthenticatedEncryption) - .append("}") - .toString(); - } - - static boolean equals(IpSecConfig.Flow lhs, IpSecConfig.Flow rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return (lhs.mSpiResourceId == rhs.mSpiResourceId - && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); - } - } - - private final Flow[] mFlow = new Flow[] {new Flow(), new Flow()}; + // Authenticated Encryption Algorithm + private IpSecAlgorithm mAuthenticatedEncryption; // For tunnel mode IPv4 UDP Encapsulation // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE @@ -100,36 +70,37 @@ public final class IpSecConfig implements Parcelable { mMode = mode; } - /** Set the local IP address for Tunnel mode */ - public void setLocalAddress(String localAddress) { - mLocalAddress = localAddress; + /** Set the source IP addres for this IPsec transform */ + public void setSourceAddress(String sourceAddress) { + mSourceAddress = sourceAddress; } - /** Set the remote IP address for this IPsec transform */ - public void setRemoteAddress(String remoteAddress) { - mRemoteAddress = remoteAddress; + /** Set the destination IP address for this IPsec transform */ + public void setDestinationAddress(String destinationAddress) { + mDestinationAddress = destinationAddress; } - /** Set the SPI for a given direction by resource ID */ - public void setSpiResourceId(int direction, int resourceId) { - mFlow[direction].mSpiResourceId = resourceId; + /** Set the SPI by resource ID */ + public void setSpiResourceId(int resourceId) { + mSpiResourceId = resourceId; } - /** Set the encryption algorithm for a given direction */ - public void setEncryption(int direction, IpSecAlgorithm encryption) { - mFlow[direction].mEncryption = encryption; + /** Set the encryption algorithm */ + public void setEncryption(IpSecAlgorithm encryption) { + mEncryption = encryption; } - /** Set the authentication algorithm for a given direction */ - public void setAuthentication(int direction, IpSecAlgorithm authentication) { - mFlow[direction].mAuthentication = authentication; + /** Set the authentication algorithm */ + public void setAuthentication(IpSecAlgorithm authentication) { + mAuthentication = authentication; } - /** Set the authenticated encryption algorithm for a given direction */ - public void setAuthenticatedEncryption(int direction, IpSecAlgorithm authenticatedEncryption) { - mFlow[direction].mAuthenticatedEncryption = authenticatedEncryption; + /** Set the authenticated encryption algorithm */ + public void setAuthenticatedEncryption(IpSecAlgorithm authenticatedEncryption) { + mAuthenticatedEncryption = authenticatedEncryption; } + /** Set the underlying network that will carry traffic for this transform */ public void setNetwork(Network network) { mNetwork = network; } @@ -155,28 +126,28 @@ public final class IpSecConfig implements Parcelable { return mMode; } - public String getLocalAddress() { - return mLocalAddress; + public String getSourceAddress() { + return mSourceAddress; } - public int getSpiResourceId(int direction) { - return mFlow[direction].mSpiResourceId; + public int getSpiResourceId() { + return mSpiResourceId; } - public String getRemoteAddress() { - return mRemoteAddress; + public String getDestinationAddress() { + return mDestinationAddress; } - public IpSecAlgorithm getEncryption(int direction) { - return mFlow[direction].mEncryption; + public IpSecAlgorithm getEncryption() { + return mEncryption; } - public IpSecAlgorithm getAuthentication(int direction) { - return mFlow[direction].mAuthentication; + public IpSecAlgorithm getAuthentication() { + return mAuthentication; } - public IpSecAlgorithm getAuthenticatedEncryption(int direction) { - return mFlow[direction].mAuthenticatedEncryption; + public IpSecAlgorithm getAuthenticatedEncryption() { + return mAuthenticatedEncryption; } public Network getNetwork() { @@ -209,17 +180,13 @@ public final class IpSecConfig implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeInt(mMode); - out.writeString(mLocalAddress); - out.writeString(mRemoteAddress); + out.writeString(mSourceAddress); + out.writeString(mDestinationAddress); out.writeParcelable(mNetwork, flags); - out.writeInt(mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mEncryption, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthentication, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption, flags); - out.writeInt(mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mEncryption, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication, flags); - out.writeParcelable(mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption, flags); + out.writeInt(mSpiResourceId); + out.writeParcelable(mEncryption, flags); + out.writeParcelable(mAuthentication, flags); + out.writeParcelable(mAuthenticatedEncryption, flags); out.writeInt(mEncapType); out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); @@ -231,22 +198,15 @@ public final class IpSecConfig implements Parcelable { private IpSecConfig(Parcel in) { mMode = in.readInt(); - mLocalAddress = in.readString(); - mRemoteAddress = in.readString(); + mSourceAddress = in.readString(); + mDestinationAddress = in.readString(); mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mSpiResourceId = in.readInt(); - mFlow[IpSecTransform.DIRECTION_IN].mEncryption = + mSpiResourceId = in.readInt(); + mEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mAuthentication = + mAuthentication = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_IN].mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mSpiResourceId = in.readInt(); - mFlow[IpSecTransform.DIRECTION_OUT].mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); - mFlow[IpSecTransform.DIRECTION_OUT].mAuthenticatedEncryption = + mAuthenticatedEncryption = (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); @@ -260,10 +220,10 @@ public final class IpSecConfig implements Parcelable { strBuilder .append("{mMode=") .append(mMode == IpSecTransform.MODE_TUNNEL ? "TUNNEL" : "TRANSPORT") - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) + .append(", mSourceAddress=") + .append(mSourceAddress) + .append(", mDestinationAddress=") + .append(mDestinationAddress) .append(", mNetwork=") .append(mNetwork) .append(", mEncapType=") @@ -274,10 +234,14 @@ public final class IpSecConfig implements Parcelable { .append(mEncapRemotePort) .append(", mNattKeepaliveInterval=") .append(mNattKeepaliveInterval) - .append(", mFlow[OUT]=") - .append(mFlow[IpSecTransform.DIRECTION_OUT]) - .append(", mFlow[IN]=") - .append(mFlow[IpSecTransform.DIRECTION_IN]) + .append("{mSpiResourceId=") + .append(mSpiResourceId) + .append(", mEncryption=") + .append(mEncryption) + .append(", mAuthentication=") + .append(mAuthentication) + .append(", mAuthenticatedEncryption=") + .append(mAuthenticatedEncryption) .append("}"); return strBuilder.toString(); @@ -299,17 +263,18 @@ public final class IpSecConfig implements Parcelable { public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { if (lhs == null || rhs == null) return (lhs == rhs); return (lhs.mMode == rhs.mMode - && lhs.mLocalAddress.equals(rhs.mLocalAddress) - && lhs.mRemoteAddress.equals(rhs.mRemoteAddress) + && lhs.mSourceAddress.equals(rhs.mSourceAddress) + && lhs.mDestinationAddress.equals(rhs.mDestinationAddress) && ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork)) || (lhs.mNetwork == rhs.mNetwork)) && lhs.mEncapType == rhs.mEncapType && lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId && lhs.mEncapRemotePort == rhs.mEncapRemotePort && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval - && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_OUT], - rhs.mFlow[IpSecTransform.DIRECTION_OUT]) - && IpSecConfig.Flow.equals(lhs.mFlow[IpSecTransform.DIRECTION_IN], - rhs.mFlow[IpSecTransform.DIRECTION_IN])); + && lhs.mSpiResourceId == rhs.mSpiResourceId + && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) + && IpSecAlgorithm.equals( + lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) + && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); } } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 34cfa9b215..67d4fcac97 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -17,6 +17,7 @@ package android.net; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemService; import android.annotation.TestApi; @@ -33,6 +34,8 @@ import dalvik.system.CloseGuard; import java.io.FileDescriptor; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; @@ -52,6 +55,23 @@ import java.net.Socket; public final class IpSecManager { private static final String TAG = "IpSecManager"; + /** + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic towards the host. + */ + public static final int DIRECTION_IN = 0; + + /** + * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute + * applies to traffic from the host. + */ + public static final int DIRECTION_OUT = 1; + + /** @hide */ + @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) + @Retention(RetentionPolicy.SOURCE) + public @interface PolicyDirection {} + /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * @@ -125,7 +145,7 @@ public final class IpSecManager { */ public static final class SecurityParameterIndex implements AutoCloseable { private final IIpSecService mService; - private final InetAddress mRemoteAddress; + private final InetAddress mDestinationAddress; private final CloseGuard mCloseGuard = CloseGuard.get(); private int mSpi = INVALID_SECURITY_PARAMETER_INDEX; private int mResourceId = INVALID_RESOURCE_ID; @@ -164,14 +184,14 @@ public final class IpSecManager { } private SecurityParameterIndex( - @NonNull IIpSecService service, int direction, InetAddress remoteAddress, int spi) + @NonNull IIpSecService service, InetAddress destinationAddress, int spi) throws ResourceUnavailableException, SpiUnavailableException { mService = service; - mRemoteAddress = remoteAddress; + mDestinationAddress = destinationAddress; try { IpSecSpiResponse result = mService.allocateSecurityParameterIndex( - direction, remoteAddress.getHostAddress(), spi, new Binder()); + destinationAddress.getHostAddress(), spi, new Binder()); if (result == null) { throw new NullPointerException("Received null response from IpSecService"); @@ -216,25 +236,23 @@ public final class IpSecManager { } /** - * Reserve a random SPI for traffic bound to or from the specified remote address. + * Reserve a random SPI for traffic bound to or from the specified destination address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress + * @param destinationAddress the destination address for traffic bearing the requested SPI. + * For inbound traffic, the destination should be an address currently assigned on-device. * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated - * for this user - * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved + * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * currently allocated for this user */ - public SecurityParameterIndex allocateSecurityParameterIndex( - int direction, InetAddress remoteAddress) throws ResourceUnavailableException { + public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress) + throws ResourceUnavailableException { try { return new SecurityParameterIndex( mService, - direction, - remoteAddress, + destinationAddress, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); } catch (SpiUnavailableException unlikely) { throw new ResourceUnavailableException("No SPIs available"); @@ -242,26 +260,27 @@ public final class IpSecManager { } /** - * Reserve the requested SPI for traffic bound to or from the specified remote address. + * Reserve the requested SPI for traffic bound to or from the specified destination address. * *

            If successful, this SPI is guaranteed available until released by a call to {@link * SecurityParameterIndex#close()}. * - * @param direction {@link IpSecTransform#DIRECTION_IN} or {@link IpSecTransform#DIRECTION_OUT} - * @param remoteAddress address of the remote. SPIs must be unique for each remoteAddress + * @param destinationAddress the destination address for traffic bearing the requested SPI. + * For inbound traffic, the destination should be an address currently assigned on-device. * @param requestedSpi the requested SPI, or '0' to allocate a random SPI * @return the reserved SecurityParameterIndex - * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated - * for this user - * @throws SpiUnavailableException indicating that the requested SPI could not be reserved + * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * currently allocated for this user + * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be + * reserved */ public SecurityParameterIndex allocateSecurityParameterIndex( - int direction, InetAddress remoteAddress, int requestedSpi) + InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); } - return new SecurityParameterIndex(mService, direction, remoteAddress, requestedSpi); + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); } /** @@ -269,14 +288,14 @@ public final class IpSecManager { * *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * *

            For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * *

            Rekey Procedure

            * @@ -287,14 +306,15 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a stream socket + * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied - * @hide */ - public void applyTransportModeTransform(Socket socket, IpSecTransform transform) + public void applyTransportModeTransform( + Socket socket, int direction, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - applyTransportModeTransform(pfd, transform); + applyTransportModeTransform(pfd, direction, transform); } } @@ -303,14 +323,14 @@ public final class IpSecManager { * *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * *

            For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * *

            Rekey Procedure

            * @@ -321,14 +341,14 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a datagram socket + * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied - * @hide */ - public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform( + DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - applyTransportModeTransform(pfd, transform); + applyTransportModeTransform(pfd, direction, transform); } } @@ -337,14 +357,14 @@ public final class IpSecManager { * *

            This applies transport mode encapsulation to the given socket. Once applied, I/O on the * socket will be encapsulated according to the parameters of the {@code IpSecTransform}. When - * the transform is removed from the socket by calling {@link #removeTransportModeTransform}, + * the transform is removed from the socket by calling {@link #removeTransportModeTransforms}, * unprotected traffic can resume on that socket. * *

            For security reasons, the destination address of any traffic on the socket must match the * remote {@code InetAddress} of the {@code IpSecTransform}. Attempts to send traffic to any * other IP address will result in an IOException. In addition, reads and writes on the socket * will throw IOException if the user deactivates the transform (by calling {@link - * IpSecTransform#close()}) without calling {@link #removeTransportModeTransform}. + * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * *

            Rekey Procedure

            * @@ -355,24 +375,27 @@ public final class IpSecManager { * in-flight packets have been received. * * @param socket a socket file descriptor + * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + public void applyTransportModeTransform( + FileDescriptor socket, int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method // This is behaviorally the same as the other versions, but the PFD constructor does not // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup(). try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - applyTransportModeTransform(pfd, transform); + applyTransportModeTransform(pfd, direction, transform); } } /* Call down to activate a transform */ - private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + private void applyTransportModeTransform( + ParcelFileDescriptor pfd, int direction, IpSecTransform transform) throws IOException { try { - mService.applyTransportModeTransform(pfd, transform.getResourceId()); + mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -407,12 +430,11 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket - * @hide */ - public void removeTransportModeTransform(Socket socket, IpSecTransform transform) + public void removeTransportModeTransforms(Socket socket, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - removeTransportModeTransform(pfd, transform); + removeTransportModeTransforms(pfd, transform); } } @@ -430,12 +452,11 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket - * @hide */ - public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) + public void removeTransportModeTransforms(DatagramSocket socket, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - removeTransportModeTransform(pfd, transform); + removeTransportModeTransforms(pfd, transform); } } @@ -454,17 +475,17 @@ public final class IpSecManager { * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) + public void removeTransportModeTransforms(FileDescriptor socket, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - removeTransportModeTransform(pfd, transform); + removeTransportModeTransforms(pfd, transform); } } /* Call down to remove a transform */ - private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) { + private void removeTransportModeTransforms(ParcelFileDescriptor pfd, IpSecTransform transform) { try { - mService.removeTransportModeTransform(pfd, transform.getResourceId()); + mService.removeTransportModeTransforms(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 102ba6d94f..7b9b483092 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -38,13 +38,11 @@ import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; /** - * This class represents an IPsec transform, which comprises security associations in one or both - * directions. + * This class represents a transform, which roughly corresponds to an IPsec Security Association. * *

            Transforms are created using {@link IpSecTransform.Builder}. Each {@code IpSecTransform} - * object encapsulates the properties and state of an inbound and outbound IPsec security - * association. That includes, but is not limited to, algorithm choice, key material, and allocated - * system resources. + * object encapsulates the properties and state of an IPsec security association. That includes, + * but is not limited to, algorithm choice, key material, and allocated system resources. * * @see RFC 4301, Security Architecture for the * Internet Protocol @@ -52,23 +50,6 @@ import java.net.InetAddress; public final class IpSecTransform implements AutoCloseable { private static final String TAG = "IpSecTransform"; - /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic towards the host. - */ - public static final int DIRECTION_IN = 0; - - /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic from the host. - */ - public static final int DIRECTION_OUT = 1; - - /** @hide */ - @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) - @Retention(RetentionPolicy.SOURCE) - public @interface TransformDirection {} - /** @hide */ public static final int MODE_TRANSPORT = 0; @@ -170,7 +151,7 @@ public final class IpSecTransform implements AutoCloseable { * *

            Deactivating a transform while it is still applied to a socket will result in errors on * that socket. Make sure to remove transforms by calling {@link - * IpSecManager#removeTransportModeTransform}. Note, removing an {@code IpSecTransform} from a + * IpSecManager#removeTransportModeTransforms}. Note, removing an {@code IpSecTransform} from a * socket will not deactivate it (because one transform may be applied to multiple sockets). * *

            It is safe to call this method on a transform that has already been deactivated. @@ -272,85 +253,49 @@ public final class IpSecTransform implements AutoCloseable { private IpSecConfig mConfig; /** - * Set the encryption algorithm for the given direction. - * - *

            If encryption is set for a direction without also providing an SPI for that direction, - * creation of an {@code IpSecTransform} will fail when attempting to build the transform. + * Set the encryption algorithm. * *

            Encryption is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ - public IpSecTransform.Builder setEncryption( - @TransformDirection int direction, IpSecAlgorithm algo) { + public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - mConfig.setEncryption(direction, algo); + Preconditions.checkNotNull(algo); + mConfig.setEncryption(algo); return this; } /** - * Set the authentication (integrity) algorithm for the given direction. - * - *

            If authentication is set for a direction without also providing an SPI for that - * direction, creation of an {@code IpSecTransform} will fail when attempting to build the - * transform. + * Set the authentication (integrity) algorithm. * *

            Authentication is mutually exclusive with authenticated encryption. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ - public IpSecTransform.Builder setAuthentication( - @TransformDirection int direction, IpSecAlgorithm algo) { + public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - mConfig.setAuthentication(direction, algo); + Preconditions.checkNotNull(algo); + mConfig.setAuthentication(algo); return this; } /** - * Set the authenticated encryption algorithm for the given direction. + * Set the authenticated encryption algorithm. * - *

            If an authenticated encryption algorithm is set for a given direction without also - * providing an SPI for that direction, creation of an {@code IpSecTransform} will fail when - * attempting to build the transform. - * - *

            The Authenticated Encryption (AE) class of algorithms are also known as Authenticated - * Encryption with Associated Data (AEAD) algorithms, or Combined mode algorithms (as - * referred to in RFC 4301). + *

            The Authenticated Encryption (AE) class of algorithms are also known as + * Authenticated Encryption with Associated Data (AEAD) algorithms, or Combined mode + * algorithms (as referred to in + * RFC 4301). * *

            Authenticated encryption is mutually exclusive with encryption and authentication. * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * be applied. */ - public IpSecTransform.Builder setAuthenticatedEncryption( - @TransformDirection int direction, IpSecAlgorithm algo) { - mConfig.setAuthenticatedEncryption(direction, algo); - return this; - } - - /** - * Set the SPI for the given direction. - * - *

            Because IPsec operates at the IP layer, this 32-bit identifier uniquely identifies - * packets to a given destination address. To prevent SPI collisions, values should be - * reserved by calling {@link IpSecManager#allocateSecurityParameterIndex}. - * - *

            If the SPI and algorithms are omitted for one direction, traffic in that direction - * will not be encrypted or authenticated. - * - * @param direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} - * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed - * traffic - */ - public IpSecTransform.Builder setSpi( - @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) { - if (spi.getResourceId() == INVALID_RESOURCE_ID) { - throw new IllegalArgumentException("Invalid SecurityParameterIndex"); - } - mConfig.setSpiResourceId(direction, spi.getResourceId()); + public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { + Preconditions.checkNotNull(algo); + mConfig.setAuthenticatedEncryption(algo); return this; } @@ -363,7 +308,8 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi - public IpSecTransform.Builder setUnderlyingNetwork(Network net) { + public IpSecTransform.Builder setUnderlyingNetwork(@NonNull Network net) { + Preconditions.checkNotNull(net); mConfig.setNetwork(net); return this; } @@ -382,7 +328,8 @@ public final class IpSecTransform implements AutoCloseable { * encapsulated traffic. In the case of IKEv2, this should be port 4500. */ public IpSecTransform.Builder setIpv4Encapsulation( - IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { + @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { + Preconditions.checkNotNull(localSocket); mConfig.setEncapType(ENCAP_ESPINUDP); if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); @@ -419,24 +366,33 @@ public final class IpSecTransform implements AutoCloseable { * will not affect any network traffic until it has been applied to one or more sockets. * * @see IpSecManager#applyTransportModeTransform - * @param remoteAddress the remote {@code InetAddress} of traffic on sockets that will use - * this transform + * @param sourceAddress the source {@code InetAddress} of traffic on sockets that will use + * this transform; this address must belong to the Network used by all sockets that + * utilize this transform; if provided, then only traffic originating from the + * specified source address will be processed. + * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed + * traffic * @throws IllegalArgumentException indicating that a particular combination of transform * properties is invalid - * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms are - * active + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms + * are active * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI * collides with an existing transform * @throws IOException indicating other errors */ - public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress) + public IpSecTransform buildTransportModeTransform( + @NonNull InetAddress sourceAddress, + @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - if (remoteAddress == null) { - throw new IllegalArgumentException("Remote address may not be null or empty!"); + Preconditions.checkNotNull(sourceAddress); + Preconditions.checkNotNull(spi); + if (spi.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } mConfig.setMode(MODE_TRANSPORT); - mConfig.setRemoteAddress(remoteAddress.getHostAddress()); + mConfig.setSourceAddress(sourceAddress.getHostAddress()); + mConfig.setSpiResourceId(spi.getResourceId()); // FIXME: modifying a builder after calling build can change the built transform. return new IpSecTransform(mContext, mConfig).activate(); } @@ -445,26 +401,33 @@ public final class IpSecTransform implements AutoCloseable { * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some * parameters have interdependencies that are checked at build time. * - * @param localAddress the {@link InetAddress} that provides the local endpoint for this + * @param sourceAddress the {@link InetAddress} that provides the source address for this * IPsec tunnel. This is almost certainly an address belonging to the {@link Network} * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}. - * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this - * IPsec tunnel. + * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed + * traffic * @throws IllegalArgumentException indicating that a particular combination of transform * properties is invalid. + * @throws IpSecManager.ResourceUnavailableException indicating that too many transforms + * are active + * @throws IpSecManager.SpiUnavailableException indicating the rare case where an SPI + * collides with an existing transform + * @throws IOException indicating other errors * @hide */ public IpSecTransform buildTunnelModeTransform( - InetAddress localAddress, InetAddress remoteAddress) { - if (localAddress == null) { - throw new IllegalArgumentException("Local address may not be null or empty!"); + @NonNull InetAddress sourceAddress, + @NonNull IpSecManager.SecurityParameterIndex spi) + throws IpSecManager.ResourceUnavailableException, + IpSecManager.SpiUnavailableException, IOException { + Preconditions.checkNotNull(sourceAddress); + Preconditions.checkNotNull(spi); + if (spi.getResourceId() == INVALID_RESOURCE_ID) { + throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } - if (remoteAddress == null) { - throw new IllegalArgumentException("Remote address may not be null or empty!"); - } - mConfig.setLocalAddress(localAddress.getHostAddress()); - mConfig.setRemoteAddress(remoteAddress.getHostAddress()); mConfig.setMode(MODE_TUNNEL); + mConfig.setSourceAddress(sourceAddress.getHostAddress()); + mConfig.setSpiResourceId(spi.getResourceId()); return new IpSecTransform(mContext, mConfig); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 02cfe3dc75..9d228c3d0a 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -25,6 +25,7 @@ import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; import android.content.Context; +import android.net.ConnectivityManager; import android.net.IIpSecService; import android.net.INetd; import android.net.IpSecAlgorithm; @@ -62,7 +63,6 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicInteger; import libcore.io.IoUtils; @@ -83,7 +83,7 @@ public class IpSecService extends IIpSecService.Stub { private static final String NETD_SERVICE_NAME = "netd"; private static final int[] DIRECTIONS = - new int[] {IpSecTransform.DIRECTION_OUT, IpSecTransform.DIRECTION_IN}; + new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int MAX_PORT_BIND_ATTEMPTS = 10; @@ -104,10 +104,10 @@ public class IpSecService extends IIpSecService.Stub { private final Context mContext; /** - * The next non-repeating global ID for tracking resources between users, this service, - * and kernel data structures. Accessing this variable is not thread safe, so it is - * only read or modified within blocks synchronized on IpSecService.this. We want to - * avoid -1 (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). + * The next non-repeating global ID for tracking resources between users, this service, and + * kernel data structures. Accessing this variable is not thread safe, so it is only read or + * modified within blocks synchronized on IpSecService.this. We want to avoid -1 + * (INVALID_RESOURCE_ID) and 0 (we probably forgot to initialize it). */ @GuardedBy("IpSecService.this") private int mNextResourceId = 1; @@ -536,14 +536,14 @@ public class IpSecService extends IIpSecService.Stub { private final class TransformRecord extends KernelResourceRecord { private final IpSecConfig mConfig; - private final SpiRecord[] mSpis; + private final SpiRecord mSpi; private final EncapSocketRecord mSocket; TransformRecord( - int resourceId, IpSecConfig config, SpiRecord[] spis, EncapSocketRecord socket) { + int resourceId, IpSecConfig config, SpiRecord spi, EncapSocketRecord socket) { super(resourceId); mConfig = config; - mSpis = spis; + mSpi = spi; mSocket = socket; } @@ -551,29 +551,26 @@ public class IpSecService extends IIpSecService.Stub { return mConfig; } - public SpiRecord getSpiRecord(int direction) { - return mSpis[direction]; + public SpiRecord getSpiRecord() { + return mSpi; } /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { - for (int direction : DIRECTIONS) { - int spi = mSpis[direction].getSpi(); - try { - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityAssociation( - mResourceId, - direction, - mConfig.getLocalAddress(), - mConfig.getRemoteAddress(), - spi); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); - } + int spi = mSpi.getSpi(); + try { + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, + mConfig.getSourceAddress(), + mConfig.getDestinationAddress(), + spi); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); } getResourceTracker().give(); @@ -597,10 +594,8 @@ public class IpSecService extends IIpSecService.Stub { .append(super.toString()) .append(", mSocket=") .append(mSocket) - .append(", mSpis[OUT].mResourceId=") - .append(mSpis[IpSecTransform.DIRECTION_OUT].mResourceId) - .append(", mSpis[IN].mResourceId=") - .append(mSpis[IpSecTransform.DIRECTION_IN].mResourceId) + .append(", mSpi.mResourceId=") + .append(mSpi.mResourceId) .append(", mConfig=") .append(mConfig) .append("}"); @@ -609,23 +604,16 @@ public class IpSecService extends IIpSecService.Stub { } private final class SpiRecord extends KernelResourceRecord { - private final int mDirection; - private final String mLocalAddress; - private final String mRemoteAddress; + private final String mSourceAddress; + private final String mDestinationAddress; private int mSpi; private boolean mOwnedByTransform = false; - SpiRecord( - int resourceId, - int direction, - String localAddress, - String remoteAddress, - int spi) { + SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) { super(resourceId); - mDirection = direction; - mLocalAddress = localAddress; - mRemoteAddress = remoteAddress; + mSourceAddress = sourceAddress; + mDestinationAddress = destinationAddress; mSpi = spi; } @@ -646,7 +634,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, mDirection, mLocalAddress, mRemoteAddress, mSpi); + mResourceId, mSourceAddress, mDestinationAddress, mSpi); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } catch (RemoteException e) { @@ -662,6 +650,10 @@ public class IpSecService extends IIpSecService.Stub { return mSpi; } + public String getDestinationAddress() { + return mDestinationAddress; + } + public void setOwnedByTransform() { if (mOwnedByTransform) { // Programming error @@ -689,12 +681,10 @@ public class IpSecService extends IIpSecService.Stub { .append(super.toString()) .append(", mSpi=") .append(mSpi) - .append(", mDirection=") - .append(mDirection) - .append(", mLocalAddress=") - .append(mLocalAddress) - .append(", mRemoteAddress=") - .append(mRemoteAddress) + .append(", mSourceAddress=") + .append(mSourceAddress) + .append(", mDestinationAddress=") + .append(mDestinationAddress) .append(", mOwnedByTransform=") .append(mOwnedByTransform) .append("}"); @@ -772,14 +762,17 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { - this(context, config, (fd, uid) -> { - try{ - TrafficStats.setThreadStatsUid(uid); - TrafficStats.tagFileDescriptor(fd); - } finally { - TrafficStats.clearThreadStatsUid(); - } - }); + this( + context, + config, + (fd, uid) -> { + try { + TrafficStats.setThreadStatsUid(uid); + TrafficStats.tagFileDescriptor(fd); + } finally { + TrafficStats.clearThreadStatsUid(); + } + }); } /** @hide */ @@ -845,8 +838,8 @@ public class IpSecService extends IIpSecService.Stub { */ private static void checkDirection(int direction) { switch (direction) { - case IpSecTransform.DIRECTION_OUT: - case IpSecTransform.DIRECTION_IN: + case IpSecManager.DIRECTION_OUT: + case IpSecManager.DIRECTION_IN: return; } throw new IllegalArgumentException("Invalid Direction: " + direction); @@ -855,10 +848,8 @@ public class IpSecService extends IIpSecService.Stub { /** Get a new SPI and maintain the reservation in the system server */ @Override public synchronized IpSecSpiResponse allocateSecurityParameterIndex( - int direction, String remoteAddress, int requestedSpi, IBinder binder) - throws RemoteException { - checkDirection(direction); - checkInetAddress(remoteAddress); + String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { + checkInetAddress(destinationAddress); /* requestedSpi can be anything in the int range, so no check is needed. */ checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); @@ -866,28 +857,21 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; - String localAddress = ""; - try { if (!userRecord.mSpiQuotaTracker.isAvailable()) { return new IpSecSpiResponse( IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } + spi = mSrvConfig .getNetdInstance() - .ipSecAllocateSpi( - resourceId, - direction, - localAddress, - remoteAddress, - requestedSpi); + .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, new RefcountedResource( - new SpiRecord(resourceId, direction, localAddress, remoteAddress, spi), - binder)); + new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { // TODO: Add appropriate checks when other ServiceSpecificException types are supported return new IpSecSpiResponse( @@ -1032,27 +1016,27 @@ public class IpSecService extends IIpSecService.Stub { } @VisibleForTesting - void validateAlgorithms(IpSecConfig config, int direction) throws IllegalArgumentException { - IpSecAlgorithm auth = config.getAuthentication(direction); - IpSecAlgorithm crypt = config.getEncryption(direction); - IpSecAlgorithm aead = config.getAuthenticatedEncryption(direction); + void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException { + IpSecAlgorithm auth = config.getAuthentication(); + IpSecAlgorithm crypt = config.getEncryption(); + IpSecAlgorithm aead = config.getAuthenticatedEncryption(); - // Validate the algorithm set - Preconditions.checkArgument( - aead != null || crypt != null || auth != null, - "No Encryption or Authentication algorithms specified"); - Preconditions.checkArgument( - auth == null || auth.isAuthentication(), - "Unsupported algorithm for Authentication"); - Preconditions.checkArgument( + // Validate the algorithm set + Preconditions.checkArgument( + aead != null || crypt != null || auth != null, + "No Encryption or Authentication algorithms specified"); + Preconditions.checkArgument( + auth == null || auth.isAuthentication(), + "Unsupported algorithm for Authentication"); + Preconditions.checkArgument( crypt == null || crypt.isEncryption(), "Unsupported algorithm for Encryption"); - Preconditions.checkArgument( - aead == null || aead.isAead(), - "Unsupported algorithm for Authenticated Encryption"); - Preconditions.checkArgument( - aead == null || (auth == null && crypt == null), - "Authenticated Encryption is mutually exclusive with other Authentication " - + "or Encryption algorithms"); + Preconditions.checkArgument( + aead == null || aead.isAead(), + "Unsupported algorithm for Authenticated Encryption"); + Preconditions.checkArgument( + aead == null || (auth == null && crypt == null), + "Authenticated Encryption is mutually exclusive with other Authentication " + + "or Encryption algorithms"); } /** @@ -1062,29 +1046,6 @@ public class IpSecService extends IIpSecService.Stub { private void checkIpSecConfig(IpSecConfig config) { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - if (config.getLocalAddress() == null) { - throw new IllegalArgumentException("Invalid null Local InetAddress"); - } - - if (config.getRemoteAddress() == null) { - throw new IllegalArgumentException("Invalid null Remote InetAddress"); - } - - switch (config.getMode()) { - case IpSecTransform.MODE_TRANSPORT: - if (!config.getLocalAddress().isEmpty()) { - throw new IllegalArgumentException("Non-empty Local Address"); - } - // Must be valid, and not a wildcard - checkInetAddress(config.getRemoteAddress()); - break; - case IpSecTransform.MODE_TUNNEL: - break; - default: - throw new IllegalArgumentException( - "Invalid IpSecTransform.mode: " + config.getMode()); - } - switch (config.getEncapType()) { case IpSecTransform.ENCAP_NONE: break; @@ -1103,11 +1064,36 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Invalid Encap Type: " + config.getEncapType()); } - for (int direction : DIRECTIONS) { - validateAlgorithms(config, direction); + validateAlgorithms(config); - // Retrieve SPI record; will throw IllegalArgumentException if not found - userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId(direction)); + // Retrieve SPI record; will throw IllegalArgumentException if not found + SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); + + // If no remote address is supplied, then use one from the SPI. + if (TextUtils.isEmpty(config.getDestinationAddress())) { + config.setDestinationAddress(s.getDestinationAddress()); + } + + // All remote addresses must match + if (!config.getDestinationAddress().equals(s.getDestinationAddress())) { + throw new IllegalArgumentException("Mismatched remote addresseses."); + } + + // This check is technically redundant due to the chain of custody between the SPI and + // the IpSecConfig, but in the future if the dest is allowed to be set explicitly in + // the transform, this will prevent us from messing up. + checkInetAddress(config.getDestinationAddress()); + + // Require a valid source address for all transforms. + checkInetAddress(config.getSourceAddress()); + + switch (config.getMode()) { + case IpSecTransform.MODE_TRANSPORT: + case IpSecTransform.MODE_TUNNEL: + break; + default: + throw new IllegalArgumentException( + "Invalid IpSecTransform.mode: " + config.getMode()); } } @@ -1127,13 +1113,12 @@ public class IpSecService extends IIpSecService.Stub { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - // Avoid resizing by creating a dependency array of min-size 3 (1 UDP encap + 2 SPIs) - List dependencies = new ArrayList<>(3); + // Avoid resizing by creating a dependency array of min-size 2 (1 UDP encap + 1 SPI) + List dependencies = new ArrayList<>(2); if (!userRecord.mTransformQuotaTracker.isAvailable()) { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } - SpiRecord[] spis = new SpiRecord[DIRECTIONS.length]; int encapType, encapLocalPort = 0, encapRemotePort = 0; EncapSocketRecord socketRecord = null; @@ -1149,51 +1134,46 @@ public class IpSecService extends IIpSecService.Stub { encapRemotePort = c.getEncapRemotePort(); } - for (int direction : DIRECTIONS) { - IpSecAlgorithm auth = c.getAuthentication(direction); - IpSecAlgorithm crypt = c.getEncryption(direction); - IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(direction); + IpSecAlgorithm auth = c.getAuthentication(); + IpSecAlgorithm crypt = c.getEncryption(); + IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); - RefcountedResource refcountedSpiRecord = - userRecord.mSpiRecords.getRefcountedResourceOrThrow( - c.getSpiResourceId(direction)); - dependencies.add(refcountedSpiRecord); + RefcountedResource refcountedSpiRecord = + userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId()); + dependencies.add(refcountedSpiRecord); + SpiRecord spiRecord = refcountedSpiRecord.getResource(); - spis[direction] = refcountedSpiRecord.getResource(); - int spi = spis[direction].getSpi(); - try { - mSrvConfig - .getNetdInstance() - .ipSecAddSecurityAssociation( - resourceId, - c.getMode(), - direction, - c.getLocalAddress(), - c.getRemoteAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetworkHandle() : 0, - spi, - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } + try { + mSrvConfig + .getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + c.getSourceAddress(), + c.getDestinationAddress(), + (c.getNetwork() != null) ? c.getNetwork().netId : 0, + spiRecord.getSpi(), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : new byte[] {}, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : new byte[] {}, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } // Both SAs were created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( resourceId, new RefcountedResource( - new TransformRecord(resourceId, c, spis, socketRecord), + new TransformRecord(resourceId, c, spiRecord, socketRecord), binder, dependencies.toArray(new RefcountedResource[dependencies.size()]))); return new IpSecTransformResponse(IpSecManager.Status.OK, resourceId); @@ -1217,9 +1197,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void applyTransportModeTransform( - ParcelFileDescriptor socket, int resourceId) throws RemoteException { + ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - + checkDirection(direction); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); @@ -1230,17 +1210,15 @@ public class IpSecService extends IIpSecService.Stub { IpSecConfig c = info.getConfig(); try { - for (int direction : DIRECTIONS) { - mSrvConfig - .getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - c.getLocalAddress(), - c.getRemoteAddress(), - info.getSpiRecord(direction).getSpi()); - } + mSrvConfig + .getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } catch (ServiceSpecificException e) { if (e.errorCode == EINVAL) { throw new IllegalArgumentException(e.toString()); @@ -1251,14 +1229,14 @@ public class IpSecService extends IIpSecService.Stub { } /** - * Remove a transport mode transform from a socket, applying the default (empty) policy. This - * will ensure that NO IPsec policy is applied to the socket (would be the equivalent of - * applying a policy that performs no IPsec). Today the resourceId parameter is passed but not - * used: reserved for future improved input validation. + * Remove transport mode transforms from a socket, applying the default (empty) policy. This + * ensures that NO IPsec policy is applied to the socket (would be the equivalent of applying a + * policy that performs no IPsec). Today the resourceId parameter is passed but not used: + * reserved for future improved input validation. */ @Override - public synchronized void removeTransportModeTransform(ParcelFileDescriptor socket, int resourceId) - throws RemoteException { + public synchronized void removeTransportModeTransforms( + ParcelFileDescriptor socket, int resourceId) throws RemoteException { try { mSrvConfig .getNetdInstance() From 16e0b07615454e9203feffb8cc89851471fad5a6 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 16 Jan 2018 12:08:43 -0800 Subject: [PATCH 0449/1150] Prevent Closure of Underlying Socket FDs The version of applyTransportModeTransform() and removeTransportModeTransform() that accepted Socket and DatagramSocket were closing the underlying FDs upon return. It's unclear whether this is due to a behavior change elsewhere in ParcelFileDescriptor, but either way, converting to using getFileDescriptor$ and then calling dup() explicitly rather than relying on ParcelFileDescriptor seems like a better idea anyway. Bug: 72047396 Test: CTS - IpSecManagerTest.testCreateTransform() Change-Id: Ia2f02564e1289f25bf113dbb861fcfd2240537a7 --- core/java/android/net/IpSecManager.java | 35 ++++--------------------- 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 67d4fcac97..2202df3baf 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -313,9 +313,7 @@ public final class IpSecManager { public void applyTransportModeTransform( Socket socket, int direction, IpSecTransform transform) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - applyTransportModeTransform(pfd, direction, transform); - } + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } /** @@ -347,9 +345,7 @@ public final class IpSecManager { */ public void applyTransportModeTransform( DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - applyTransportModeTransform(pfd, direction, transform); - } + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } /** @@ -383,18 +379,8 @@ public final class IpSecManager { FileDescriptor socket, int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() - // constructor takes control and closes the user's FD when we exit the method - // This is behaviorally the same as the other versions, but the PFD constructor does not - // dup() automatically, whereas PFD.fromSocket() and PDF.fromDatagramSocket() do dup(). + // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - applyTransportModeTransform(pfd, direction, transform); - } - } - - /* Call down to activate a transform */ - private void applyTransportModeTransform( - ParcelFileDescriptor pfd, int direction, IpSecTransform transform) throws IOException { - try { mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -433,9 +419,7 @@ public final class IpSecManager { */ public void removeTransportModeTransforms(Socket socket, IpSecTransform transform) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromSocket(socket)) { - removeTransportModeTransforms(pfd, transform); - } + removeTransportModeTransforms(socket.getFileDescriptor$(), transform); } /** @@ -455,9 +439,7 @@ public final class IpSecManager { */ public void removeTransportModeTransforms(DatagramSocket socket, IpSecTransform transform) throws IOException { - try (ParcelFileDescriptor pfd = ParcelFileDescriptor.fromDatagramSocket(socket)) { - removeTransportModeTransforms(pfd, transform); - } + removeTransportModeTransforms(socket.getFileDescriptor$(), transform); } /** @@ -478,13 +460,6 @@ public final class IpSecManager { public void removeTransportModeTransforms(FileDescriptor socket, IpSecTransform transform) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - removeTransportModeTransforms(pfd, transform); - } - } - - /* Call down to remove a transform */ - private void removeTransportModeTransforms(ParcelFileDescriptor pfd, IpSecTransform transform) { - try { mService.removeTransportModeTransforms(pfd, transform.getResourceId()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); From 24f3bb8c6d120444b49cf50bb9790ffb5ddb961f Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 17 Jan 2018 01:00:20 -0800 Subject: [PATCH 0450/1150] IpSec - API Tweak for removeTransportModeTransform Because IpSecTransforms are now unidirectional, and because the only mechanism for removing Transforms removes it from both directions, the API can no longer use the Transform parameter to meaningfully validate that the caller had applied a transform. Since that functionality was as-yet unimplemented and is now infeasible, the transform parameter is removed. Bug: 72079356 Test: cts - IpSecManagerTest; runtest frameworks-net Change-Id: If19b0d34bdc6daf31a40d6d62bff326dcbca08c0 --- core/java/android/net/IIpSecService.aidl | 2 +- core/java/android/net/IpSecManager.java | 30 ++++++++----------- .../java/com/android/server/IpSecService.java | 4 +-- 3 files changed, 15 insertions(+), 21 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3fe531fd79..790c80b1d9 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -45,5 +45,5 @@ interface IIpSecService void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); - void removeTransportModeTransforms(in ParcelFileDescriptor socket, int transformId); + void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 2202df3baf..2cda58c99a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -405,62 +405,56 @@ public final class IpSecManager { /** * Remove an IPsec transform from a stream socket. * - *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + *

            Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(Socket socket, IpSecTransform transform) + public void removeTransportModeTransforms(Socket socket) throws IOException { - removeTransportModeTransforms(socket.getFileDescriptor$(), transform); + removeTransportModeTransforms(socket.getFileDescriptor$()); } /** * Remove an IPsec transform from a datagram socket. * - *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + *

            Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(DatagramSocket socket, IpSecTransform transform) + public void removeTransportModeTransforms(DatagramSocket socket) throws IOException { - removeTransportModeTransforms(socket.getFileDescriptor$(), transform); + removeTransportModeTransforms(socket.getFileDescriptor$()); } /** * Remove an IPsec transform from a socket. * - *

            Once removed, traffic on the socket will not be encrypted. This operation will succeed - * regardless of the state of the transform. Removing a transform from a socket allows the - * socket to be reused for communication in the clear. + *

            Once removed, traffic on the socket will not be encrypted. Removing transforms from a + * socket allows the socket to be reused for communication in the clear. * *

            If an {@code IpSecTransform} object applied to this socket was deallocated by calling * {@link IpSecTransform#close()}, then communication on the socket will fail until this method * is called. * * @param socket a socket that previously had a transform applied to it - * @param transform the IPsec Transform that was previously applied to the given socket * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(FileDescriptor socket, IpSecTransform transform) + public void removeTransportModeTransforms(FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { - mService.removeTransportModeTransforms(pfd, transform.getResourceId()); + mService.removeTransportModeTransforms(pfd); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 9d228c3d0a..46a35ec800 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1235,8 +1235,8 @@ public class IpSecService extends IIpSecService.Stub { * reserved for future improved input validation. */ @Override - public synchronized void removeTransportModeTransforms( - ParcelFileDescriptor socket, int resourceId) throws RemoteException { + public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) + throws RemoteException { try { mSrvConfig .getNetdInstance() From fab3fa31106dfe2acdf10e058468fb58cef4a95d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 13 Dec 2017 17:16:53 -0800 Subject: [PATCH 0451/1150] Address comments and final cleanup from refcounting integration Added some extra comments on reference counting and moved a few methods around. No significant logical changes made in this CL Bug: 63409385 Test: CTS, Unit tests (both frameworks-base and netd) and binder tests all pass Change-Id: I89f1f4a021db48ae406fefefa6aca7406045736c --- .../java/com/android/server/IpSecService.java | 90 +++++++++++++------ 1 file changed, 63 insertions(+), 27 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 46a35ec800..64eb870352 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -148,7 +148,7 @@ public class IpSecService extends IIpSecService.Stub { * resources. * *

            References to the IResource object may be held by other RefcountedResource objects, - * and as such, the kernel resources and quota may not be cleaned up. + * and as such, the underlying resources and quota may not be cleaned up. */ void invalidate() throws RemoteException; @@ -298,7 +298,12 @@ public class IpSecService extends IIpSecService.Stub { } } - /* Very simple counting class that looks much like a counting semaphore */ + /** + * Very simple counting class that looks much like a counting semaphore + * + *

            This class is not thread-safe, and expects that that users of this class will ensure + * synchronization and thread safety by holding the IpSecService.this instance lock. + */ @VisibleForTesting static class ResourceTracker { private final int mMax; @@ -341,26 +346,38 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final class UserRecord { - /* Type names */ - public static final String TYPENAME_SPI = "SecurityParameterIndex"; - public static final String TYPENAME_TRANSFORM = "IpSecTransform"; - public static final String TYPENAME_ENCAP_SOCKET = "UdpEncapSocket"; - /* Maximum number of each type of resource that a single UID may possess */ public static final int MAX_NUM_ENCAP_SOCKETS = 2; public static final int MAX_NUM_TRANSFORMS = 4; public static final int MAX_NUM_SPIS = 8; + /** + * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing + * and explicit (user) reference management. + * + *

            These are stored in separate arrays to improve debuggability and dump output clarity. + * + *

            Resources are removed from this array when the user releases their explicit reference + * by calling one of the releaseResource() methods. + */ final RefcountedResourceArray mSpiRecords = - new RefcountedResourceArray<>(TYPENAME_SPI); - final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); - + new RefcountedResourceArray<>(SpiRecord.class.getSimpleName()); final RefcountedResourceArray mTransformRecords = - new RefcountedResourceArray<>(TYPENAME_TRANSFORM); - final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); - + new RefcountedResourceArray<>(TransformRecord.class.getSimpleName()); final RefcountedResourceArray mEncapSocketRecords = - new RefcountedResourceArray<>(TYPENAME_ENCAP_SOCKET); + new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); + + /** + * Trackers for quotas for each of the OwnedResource types. + * + *

            These trackers are separate from the resource arrays, since they are incremented and + * decremented at different points in time. Specifically, quota is only returned upon final + * resource deallocation (after all explicit and implicit references are released). Note + * that it is possible that calls to releaseResource() will not return the used quota if + * there are other resources that depend on (are parents of) the resource being released. + */ + final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); + final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); void removeSpiRecord(int resourceId) { @@ -395,11 +412,15 @@ public class IpSecService extends IIpSecService.Stub { } } + /** + * This class is not thread-safe, and expects that that users of this class will ensure + * synchronization and thread safety by holding the IpSecService.this instance lock. + */ @VisibleForTesting static final class UserResourceTracker { private final SparseArray mUserRecords = new SparseArray<>(); - /** Never-fail getter that populates the list of UIDs as-needed */ + /** Lazy-initialization/getter that populates or retrieves the UserRecord as needed */ public UserRecord getUserRecord(int uid) { checkCallerUid(uid); @@ -428,18 +449,20 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting final UserResourceTracker mUserResourceTracker = new UserResourceTracker(); /** - * The KernelResourceRecord class provides a facility to cleanly and reliably track system + * The OwnedResourceRecord class provides a facility to cleanly and reliably track system * resources. It relies on a provided resourceId that should uniquely identify the kernel * resource. To use this class, the user should implement the invalidate() and * freeUnderlyingResources() methods that are responsible for cleaning up IpSecService resource - * tracking arrays and kernel resources, respectively + * tracking arrays and kernel resources, respectively. + * + *

            This class associates kernel resources with the UID that owns and controls them. */ - private abstract class KernelResourceRecord implements IResource { + private abstract class OwnedResourceRecord implements IResource { final int pid; final int uid; protected final int mResourceId; - KernelResourceRecord(int resourceId) { + OwnedResourceRecord(int resourceId) { super(); if (resourceId == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); @@ -479,8 +502,6 @@ public class IpSecService extends IIpSecService.Stub { } }; - // TODO: Move this to right after RefcountedResource. With this here, Gerrit was showing many - // more things as changed. /** * Thin wrapper over SparseArray to ensure resources exist, and simplify generic typing. * @@ -534,7 +555,12 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class TransformRecord extends KernelResourceRecord { + /** + * Tracks an SA in the kernel, and manages cleanup paths. Once a TransformRecord is + * created, the SpiRecord that originally tracked the SAs will reliquish the + * responsibility of freeing the underlying SA to this class via the mOwnedByTransform flag. + */ + private final class TransformRecord extends OwnedResourceRecord { private final IpSecConfig mConfig; private final SpiRecord mSpi; private final EncapSocketRecord mSocket; @@ -603,7 +629,12 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class SpiRecord extends KernelResourceRecord { + /** + * Tracks a single SA in the kernel, and manages cleanup paths. Once used in a Transform, the + * responsibility for cleaning up underlying resources will be passed to the TransformRecord + * object + */ + private final class SpiRecord extends OwnedResourceRecord { private final String mSourceAddress; private final String mDestinationAddress; private int mSpi; @@ -692,7 +723,14 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class EncapSocketRecord extends KernelResourceRecord { + /** + * Tracks a UDP encap socket, and manages cleanup paths + * + *

            While this class does not manage non-kernel resources, race conditions around socket + * binding require that the service creates the encap socket, binds it and applies the socket + * policy before handing it to a user. + */ + private final class EncapSocketRecord extends OwnedResourceRecord { private FileDescriptor mSocket; private final int mPort; @@ -1112,9 +1150,7 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); - - // Avoid resizing by creating a dependency array of min-size 2 (1 UDP encap + 1 SPI) - List dependencies = new ArrayList<>(2); + List dependencies = new ArrayList<>(); if (!userRecord.mTransformQuotaTracker.isAvailable()) { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); From 3f6d5df0b5a8565e7aa7f328628d26eb84df8cdb Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 17 Jan 2018 16:09:24 -0800 Subject: [PATCH 0452/1150] Add Tunnel Interface APIs to IpSecManager Add a new interface and a new management object, IpSecTunnelInterface to the IpSecManager surface. This object will be used to control IPsec tunnels. -Add IpSecTunnelInterface object -Add methods to create and use an IpSecTunnelInterface -Update the IpSecTransform builder to create Tunnel mode IpSecTransform objects (usable with an IpSecTunnel) Bug: 36033193 Test: compilation Change-Id: Ib6948b12c15c93674234dc36288058ae44435b90 --- core/java/android/net/IpSecManager.java | 128 ++++++++++++++++++++++ core/java/android/net/IpSecTransform.java | 16 +-- 2 files changed, 129 insertions(+), 15 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 2cda58c99a..f04f03f6b6 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; @@ -624,6 +625,133 @@ public final class IpSecManager { return new UdpEncapsulationSocket(mService, 0); } + /** + * This class represents an IpSecTunnelInterface + * + *

            IpSecTunnelInterface objects track tunnel interfaces that serve as + * local endpoints for IPsec tunnels. + * + *

            Creating an IpSecTunnelInterface creates a device to which IpSecTransforms may be + * applied to provide IPsec security to packets sent through the tunnel. While a tunnel + * cannot be used in standalone mode within Android, the higher layers may use the tunnel + * to create Network objects which are accessible to the Android system. + * @hide + */ + @SystemApi + public static final class IpSecTunnelInterface implements AutoCloseable { + private final IIpSecService mService; + private final InetAddress mRemoteAddress; + private final InetAddress mLocalAddress; + private final Network mUnderlyingNetwork; + private final CloseGuard mCloseGuard = CloseGuard.get(); + private String mInterfaceName; + private int mResourceId = INVALID_RESOURCE_ID; + + /** Get the underlying SPI held by this object. */ + public String getInterfaceName() { + return mInterfaceName; + } + + /** + * Add an address to the IpSecTunnelInterface + * + *

            Add an address which may be used as the local inner address for + * tunneled traffic. + * + * @param address the local address for traffic inside the tunnel + * @throws IOException if the address could not be added + * @hide + */ + public void addAddress(LinkAddress address) throws IOException { + } + + /** + * Remove an address from the IpSecTunnelInterface + * + *

            Remove an address which was previously added to the IpSecTunnelInterface + * + * @param address to be removed + * @throws IOException if the address could not be removed + * @hide + */ + public void removeAddress(LinkAddress address) throws IOException { + } + + private IpSecTunnelInterface(@NonNull IIpSecService service, + @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, + @NonNull Network underlyingNetwork) + throws ResourceUnavailableException, IOException { + mService = service; + mLocalAddress = localAddress; + mRemoteAddress = remoteAddress; + mUnderlyingNetwork = underlyingNetwork; + // TODO: Call IpSecService + } + + /** + * Delete an IpSecTunnelInterface + * + *

            Calling close will deallocate the IpSecTunnelInterface and all of its system + * resources. Any packets bound for this interface either inbound or outbound will + * all be lost. + */ + @Override + public void close() { + // try { + // TODO: Call IpSecService + mResourceId = INVALID_RESOURCE_ID; + // } catch (RemoteException e) { + // throw e.rethrowFromSystemServer(); + // } + mCloseGuard.close(); + } + + /** Check that the Interface was closed properly. */ + @Override + protected void finalize() throws Throwable { + if (mCloseGuard != null) { + mCloseGuard.warnIfOpen(); + } + close(); + } + } + + /** + * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. + * + * @param localAddress The local addres of the tunnel + * @param remoteAddress The local addres of the tunnel + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. + * This network should almost certainly be a network such as WiFi with an L2 address. + * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the socket could not be opened or bound + * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open + * @hide + */ + @SystemApi + public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, + @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) + throws ResourceUnavailableException, IOException { + return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); + } + + /** + * Apply a transform to the IpSecTunnelInterface + * + * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied + * transform. + * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which + * the transform will be used. + * @param transform an {@link IpSecTransform} created in tunnel mode + * @throws IOException indicating that the transform could not be applied due to a lower + * layer failure. + * @hide + */ + @SystemApi + void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, + IpSecTransform transform) throws IOException { + // TODO: call IpSecService + } /** * Construct an instance of IpSecManager within an application context. * diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 7b9b483092..be6026ff37 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -299,21 +299,6 @@ public final class IpSecTransform implements AutoCloseable { return this; } - /** - * Set the {@link Network} which will carry tunneled traffic. - * - *

            Restricts the transformed traffic to a particular {@link Network}. This is required - * for tunnel mode, otherwise tunneled traffic would be sent on the default network. - * - * @hide - */ - @SystemApi - public IpSecTransform.Builder setUnderlyingNetwork(@NonNull Network net) { - Preconditions.checkNotNull(net); - mConfig.setNetwork(net); - return this; - } - /** * Add UDP encapsulation to an IPv4 transform. * @@ -415,6 +400,7 @@ public final class IpSecTransform implements AutoCloseable { * @throws IOException indicating other errors * @hide */ + @SystemApi public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) From 47d108c1913797206356b3fdc377a54fb0efb5ef Mon Sep 17 00:00:00 2001 From: Di Lu Date: Thu, 11 Jan 2018 11:35:25 -0800 Subject: [PATCH 0453/1150] Add xfrm mark in IpSecConfig Bug: 63589600 Test: runtest frameworks-net Change-Id: I2d38d781b8b31d8bf39fd4e9a7e31509f15a9e16 --- core/java/android/net/IpSecConfig.java | 32 ++++++++++++++++++- .../java/com/android/server/IpSecService.java | 8 +++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 80b0af3373..6a262e2c87 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -65,6 +65,10 @@ public final class IpSecConfig implements Parcelable { // An interval, in seconds between the NattKeepalive packets private int mNattKeepaliveInterval; + // XFRM mark and mask + private int mMarkValue; + private int mMarkMask; + /** Set the mode for this IPsec transform */ public void setMode(int mode) { mMode = mode; @@ -121,6 +125,14 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = interval; } + public void setMarkValue(int mark) { + mMarkValue = mark; + } + + public void setMarkMask(int mask) { + mMarkMask = mask; + } + // Transport or Tunnel public int getMode() { return mMode; @@ -170,6 +182,14 @@ public final class IpSecConfig implements Parcelable { return mNattKeepaliveInterval; } + public int getMarkValue() { + return mMarkValue; + } + + public int getMarkMask() { + return mMarkMask; + } + // Parcelable Methods @Override @@ -191,6 +211,8 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mEncapSocketResourceId); out.writeInt(mEncapRemotePort); out.writeInt(mNattKeepaliveInterval); + out.writeInt(mMarkValue); + out.writeInt(mMarkMask); } @VisibleForTesting @@ -212,6 +234,8 @@ public final class IpSecConfig implements Parcelable { mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); mNattKeepaliveInterval = in.readInt(); + mMarkValue = in.readInt(); + mMarkMask = in.readInt(); } @Override @@ -242,6 +266,10 @@ public final class IpSecConfig implements Parcelable { .append(mAuthentication) .append(", mAuthenticatedEncryption=") .append(mAuthenticatedEncryption) + .append(", mMarkValue=") + .append(mMarkValue) + .append(", mMarkMask=") + .append(mMarkMask) .append("}"); return strBuilder.toString(); @@ -275,6 +303,8 @@ public final class IpSecConfig implements Parcelable { && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) && IpSecAlgorithm.equals( lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) - && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication)); + && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication) + && lhs.mMarkValue == rhs.mMarkValue + && lhs.mMarkMask == rhs.mMarkMask); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 46a35ec800..09d7d9bc62 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -566,7 +566,9 @@ public class IpSecService extends IIpSecService.Stub { mResourceId, mConfig.getSourceAddress(), mConfig.getDestinationAddress(), - spi); + spi, + mConfig.getMarkValue(), + mConfig.getMarkMask()); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } catch (RemoteException e) { @@ -634,7 +636,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, mSourceAddress, mDestinationAddress, mSpi); + mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception } catch (RemoteException e) { @@ -1153,6 +1155,8 @@ public class IpSecService extends IIpSecService.Stub { c.getDestinationAddress(), (c.getNetwork() != null) ? c.getNetwork().netId : 0, spiRecord.getSpi(), + c.getMarkValue(), + c.getMarkMask(), (auth != null) ? auth.getName() : "", (auth != null) ? auth.getKey() : new byte[] {}, (auth != null) ? auth.getTruncationLengthBits() : 0, From bc015bd353f7fa97e1aad2ec721de3cddc7f18f1 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 00:50:48 +0900 Subject: [PATCH 0454/1150] Pass all default networks to NetworkStatsService This will allow NetworkStatsService to treat traffic on these networks differently from traffic where the app selects a network that is not the default. Bug: 35142602 Test: runtest frameworks-net Change-Id: I5ea9d200d9fb153490c6108bb9390bf152f297da --- .../android/net/INetworkStatsService.aidl | 3 ++- .../server/net/NetworkStatsService.java | 27 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 95e7f6031c..90e3ffd550 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; +import android.net.Network; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; @@ -53,7 +54,7 @@ interface INetworkStatsService { void setUidForeground(int uid, boolean uidForeground); /** Force update of ifaces. */ - void forceUpdateIfaces(); + void forceUpdateIfaces(in Network[] defaultNetworks); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index db61ef5cd9..0b25573c30 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -83,6 +83,7 @@ import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkInfo; @@ -231,14 +232,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Object mStatsLock = new Object(); /** Set of currently active ifaces. */ + @GuardedBy("mStatsLock") private final ArrayMap mActiveIfaces = new ArrayMap<>(); + /** Set of currently active ifaces for UID stats. */ + @GuardedBy("mStatsLock") private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); + /** Current default active iface. */ private String mActiveIface; + /** Set of any ifaces associated with mobile networks since boot. */ + @GuardedBy("mStatsLock") private String[] mMobileIfaces = new String[0]; + /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ + @GuardedBy("mStatsLock") + private Network[] mDefaultNetworks = new Network[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -779,13 +790,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces() { + public void forceUpdateIfaces(Network[] defaultNetworks) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(); + updateIfaces(defaultNetworks); } finally { Binder.restoreCallingIdentity(token); } @@ -996,11 +1007,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces() { + private void updateIfaces(Network[] defaultNetworks) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(); + updateIfacesLocked(defaultNetworks); } finally { mWakeLock.release(); } @@ -1013,7 +1024,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * are active on a single {@code iface}, they are combined under a single * {@link NetworkIdentitySet}. */ - private void updateIfacesLocked() { + private void updateIfacesLocked(Network[] defaultNetworks) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1040,6 +1051,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); + if (defaultNetworks != null) { + // Caller is ConnectivityService. Update the list of default networks. + mDefaultNetworks = defaultNetworks; + } final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { @@ -1511,7 +1526,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return true; } case MSG_UPDATE_IFACES: { - mService.updateIfaces(); + mService.updateIfaces(null); return true; } case MSG_REGISTER_GLOBAL_ALERT: { From 6fe513c753074172d255a01aa2be53d0d2f2d416 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 01:05:20 +0900 Subject: [PATCH 0455/1150] Add the default network to NetworkStats and NetworkStatsCollection. This allows us to maintain NetworkStats entries that track whether the traffic was on the default network. At the moment, the stats collection code always passes in DEFAULT_NETWORK_NO. However, this value is a no-op, since it is not persisted to disk. Only the ident, the uid/set/tag, and the packet/byte/operation counters are persisted. A future change will add defaultNetwork to the ident and start persisting it. Bug: 35142602 Test: runtest frameworks-net Change-Id: Ifa291c62c0fa389b88e5561086a29dcd7cee2253 --- core/java/android/net/NetworkStats.java | 90 +++++++++++++++---- .../internal/net/NetworkStatsFactory.java | 2 +- ...droid_internal_net_NetworkStatsFactory.cpp | 9 +- .../server/net/NetworkStatsCollection.java | 2 + .../server/net/NetworkStatsService.java | 7 +- 5 files changed, 90 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 171adc054b..a85f80e38d 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -82,6 +82,13 @@ public class NetworkStats implements Parcelable { /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; + /** {@link #onDefaultNetwork} value to account for all default network states. */ + public static final int DEFAULT_NETWORK_ALL = -1; + /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ + public static final int DEFAULT_NETWORK_NO = 0; + /** {@link #onDefaultNetwork} value to account for usage while the default network. */ + public static final int DEFAULT_NETWORK_YES = 1; + /** Denotes a request for stats at the interface level. */ public static final int STATS_PER_IFACE = 0; /** Denotes a request for stats at the interface and UID level. */ @@ -102,6 +109,7 @@ public class NetworkStats implements Parcelable { private int[] tag; private int[] metered; private int[] roaming; + private int[] defaultNetwork; private long[] rxBytes; private long[] rxPackets; private long[] txBytes; @@ -125,6 +133,12 @@ public class NetworkStats implements Parcelable { * getSummary(). */ public int roaming; + /** + * Note that this is only populated w/ the default value when read from /proc or written + * to disk. We merge in the correct value when reporting this value to clients of + * getSummary(). + */ + public int defaultNetwork; public long rxBytes; public long rxPackets; public long txBytes; @@ -142,18 +156,27 @@ public class NetworkStats implements Parcelable { public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, METERED_NO, ROAMING_NO, rxBytes, rxPackets, txBytes, - txPackets, operations); + this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, + rxBytes, rxPackets, txBytes, txPackets, operations); + } + + // TODO: fix the the telephony code to pass DEFAULT_NETWORK_YES and remove this constructor. + public Entry(String iface, int uid, int set, int tag, int metered, int roaming, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + this(iface, uid, set, tag, metered, roaming, DEFAULT_NETWORK_YES, rxBytes, rxPackets, + txBytes, txPackets, operations); } public Entry(String iface, int uid, int set, int tag, int metered, int roaming, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, + long operations) { this.iface = iface; this.uid = uid; this.set = set; this.tag = tag; this.metered = metered; this.roaming = roaming; + this.defaultNetwork = defaultNetwork; this.rxBytes = rxBytes; this.rxPackets = rxPackets; this.txBytes = txBytes; @@ -187,6 +210,7 @@ public class NetworkStats implements Parcelable { builder.append(" tag=").append(tagToString(tag)); builder.append(" metered=").append(meteredToString(metered)); builder.append(" roaming=").append(roamingToString(roaming)); + builder.append(" defaultNetwork=").append(defaultNetworkToString(defaultNetwork)); builder.append(" rxBytes=").append(rxBytes); builder.append(" rxPackets=").append(rxPackets); builder.append(" txBytes=").append(txBytes); @@ -200,7 +224,8 @@ public class NetworkStats implements Parcelable { if (o instanceof Entry) { final Entry e = (Entry) o; return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered - && roaming == e.roaming && rxBytes == e.rxBytes && rxPackets == e.rxPackets + && roaming == e.roaming && defaultNetwork == e.defaultNetwork + && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes && txPackets == e.txPackets && operations == e.operations && iface.equals(e.iface); } @@ -209,7 +234,7 @@ public class NetworkStats implements Parcelable { @Override public int hashCode() { - return Objects.hash(uid, set, tag, metered, roaming, iface); + return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface); } } @@ -224,6 +249,7 @@ public class NetworkStats implements Parcelable { this.tag = new int[initialSize]; this.metered = new int[initialSize]; this.roaming = new int[initialSize]; + this.defaultNetwork = new int[initialSize]; this.rxBytes = new long[initialSize]; this.rxPackets = new long[initialSize]; this.txBytes = new long[initialSize]; @@ -238,6 +264,7 @@ public class NetworkStats implements Parcelable { this.tag = EmptyArray.INT; this.metered = EmptyArray.INT; this.roaming = EmptyArray.INT; + this.defaultNetwork = EmptyArray.INT; this.rxBytes = EmptyArray.LONG; this.rxPackets = EmptyArray.LONG; this.txBytes = EmptyArray.LONG; @@ -256,6 +283,7 @@ public class NetworkStats implements Parcelable { tag = parcel.createIntArray(); metered = parcel.createIntArray(); roaming = parcel.createIntArray(); + defaultNetwork = parcel.createIntArray(); rxBytes = parcel.createLongArray(); rxPackets = parcel.createLongArray(); txBytes = parcel.createLongArray(); @@ -274,6 +302,7 @@ public class NetworkStats implements Parcelable { dest.writeIntArray(tag); dest.writeIntArray(metered); dest.writeIntArray(roaming); + dest.writeIntArray(defaultNetwork); dest.writeLongArray(rxBytes); dest.writeLongArray(rxPackets); dest.writeLongArray(txBytes); @@ -308,10 +337,11 @@ public class NetworkStats implements Parcelable { @VisibleForTesting public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { + int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, + long operations) { return addValues(new Entry( - iface, uid, set, tag, metered, roaming, rxBytes, rxPackets, txBytes, txPackets, - operations)); + iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, + txBytes, txPackets, operations)); } /** @@ -327,6 +357,7 @@ public class NetworkStats implements Parcelable { tag = Arrays.copyOf(tag, newLength); metered = Arrays.copyOf(metered, newLength); roaming = Arrays.copyOf(roaming, newLength); + defaultNetwork = Arrays.copyOf(defaultNetwork, newLength); rxBytes = Arrays.copyOf(rxBytes, newLength); rxPackets = Arrays.copyOf(rxPackets, newLength); txBytes = Arrays.copyOf(txBytes, newLength); @@ -341,6 +372,7 @@ public class NetworkStats implements Parcelable { tag[size] = entry.tag; metered[size] = entry.metered; roaming[size] = entry.roaming; + defaultNetwork[size] = entry.defaultNetwork; rxBytes[size] = entry.rxBytes; rxPackets[size] = entry.rxPackets; txBytes[size] = entry.txBytes; @@ -362,6 +394,7 @@ public class NetworkStats implements Parcelable { entry.tag = tag[i]; entry.metered = metered[i]; entry.roaming = roaming[i]; + entry.defaultNetwork = defaultNetwork[i]; entry.rxBytes = rxBytes[i]; entry.rxPackets = rxPackets[i]; entry.txBytes = txBytes[i]; @@ -416,7 +449,7 @@ public class NetworkStats implements Parcelable { */ public NetworkStats combineValues(Entry entry) { final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, - entry.roaming); + entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution addValues(entry); @@ -444,10 +477,12 @@ public class NetworkStats implements Parcelable { /** * Find first stats index that matches the requested parameters. */ - public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming) { + public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming, + int defaultNetwork) { for (int i = 0; i < size; i++) { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] && metered == this.metered[i] && roaming == this.roaming[i] + && defaultNetwork == this.defaultNetwork[i] && Objects.equals(iface, this.iface[i])) { return i; } @@ -461,7 +496,7 @@ public class NetworkStats implements Parcelable { */ @VisibleForTesting public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming, - int hintIndex) { + int defaultNetwork, int hintIndex) { for (int offset = 0; offset < size; offset++) { final int halfOffset = offset / 2; @@ -475,6 +510,7 @@ public class NetworkStats implements Parcelable { if (uid == this.uid[i] && set == this.set[i] && tag == this.tag[i] && metered == this.metered[i] && roaming == this.roaming[i] + && defaultNetwork == this.defaultNetwork[i] && Objects.equals(iface, this.iface[i])) { return i; } @@ -489,7 +525,8 @@ public class NetworkStats implements Parcelable { */ public void spliceOperationsFrom(NetworkStats stats) { for (int i = 0; i < size; i++) { - final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i]); + final int j = stats.findIndex(iface[i], uid[i], set[i], tag[i], metered[i], roaming[i], + defaultNetwork[i]); if (j == -1) { operations[i] = 0; } else { @@ -581,6 +618,7 @@ public class NetworkStats implements Parcelable { entry.tag = TAG_NONE; entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; + entry.defaultNetwork = DEFAULT_NETWORK_ALL; entry.rxBytes = 0; entry.rxPackets = 0; entry.txBytes = 0; @@ -677,6 +715,7 @@ public class NetworkStats implements Parcelable { entry.tag = left.tag[i]; entry.metered = left.metered[i]; entry.roaming = left.roaming[i]; + entry.defaultNetwork = left.defaultNetwork[i]; entry.rxBytes = left.rxBytes[i]; entry.rxPackets = left.rxPackets[i]; entry.txBytes = left.txBytes[i]; @@ -685,7 +724,7 @@ public class NetworkStats implements Parcelable { // find remote row that matches, and subtract final int j = right.findIndexHinted(entry.iface, entry.uid, entry.set, entry.tag, - entry.metered, entry.roaming, i); + entry.metered, entry.roaming, entry.defaultNetwork, i); if (j != -1) { // Found matching row, subtract remote value. entry.rxBytes -= right.rxBytes[j]; @@ -725,6 +764,7 @@ public class NetworkStats implements Parcelable { entry.tag = TAG_NONE; entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; + entry.defaultNetwork = DEFAULT_NETWORK_ALL; entry.operations = 0L; for (int i = 0; i < size; i++) { @@ -755,6 +795,7 @@ public class NetworkStats implements Parcelable { entry.tag = TAG_NONE; entry.metered = METERED_ALL; entry.roaming = ROAMING_ALL; + entry.defaultNetwork = DEFAULT_NETWORK_ALL; for (int i = 0; i < size; i++) { // skip specific tags, since already counted in TAG_NONE @@ -802,6 +843,7 @@ public class NetworkStats implements Parcelable { pw.print(" tag="); pw.print(tagToString(tag[i])); pw.print(" metered="); pw.print(meteredToString(metered[i])); pw.print(" roaming="); pw.print(roamingToString(roaming[i])); + pw.print(" defaultNetwork="); pw.print(defaultNetworkToString(defaultNetwork[i])); pw.print(" rxBytes="); pw.print(rxBytes[i]); pw.print(" rxPackets="); pw.print(rxPackets[i]); pw.print(" txBytes="); pw.print(txBytes[i]); @@ -900,6 +942,22 @@ public class NetworkStats implements Parcelable { } } + /** + * Return text description of {@link #defaultNetwork} value. + */ + public static String defaultNetworkToString(int defaultNetwork) { + switch (defaultNetwork) { + case DEFAULT_NETWORK_ALL: + return "ALL"; + case DEFAULT_NETWORK_NO: + return "NO"; + case DEFAULT_NETWORK_YES: + return "YES"; + default: + return "UNKNOWN"; + } + } + @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); @@ -1055,6 +1113,7 @@ public class NetworkStats implements Parcelable { tmpEntry.set = set[i]; tmpEntry.metered = metered[i]; tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { moved.add(tmpEntry); @@ -1075,6 +1134,7 @@ public class NetworkStats implements Parcelable { moved.iface = underlyingIface; moved.metered = METERED_ALL; moved.roaming = ROAMING_ALL; + moved.defaultNetwork = DEFAULT_NETWORK_ALL; combineValues(moved); // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than @@ -1085,13 +1145,13 @@ public class NetworkStats implements Parcelable { // roaming data after applying these adjustments, by checking the NetworkIdentity of the // underlying iface. int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO); + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnBackground != -1) { tunSubtract(idxVpnBackground, this, moved); } int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO); + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved); } diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 3d3e148fb3..b576a20db5 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -217,7 +217,7 @@ public class NetworkStatsFactory { } NetworkStats.Entry adjust = - new NetworkStats.Entry(baseIface, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); + new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); // Subtract any 464lat traffic seen for the root UID on the current base interface. adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 0cb6935990..d254de65f7 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -45,6 +45,7 @@ static struct { jfieldID tag; jfieldID metered; jfieldID roaming; + jfieldID defaultNetwork; jfieldID rxBytes; jfieldID rxPackets; jfieldID txBytes; @@ -246,6 +247,9 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ScopedIntArrayRW roaming(env, get_int_array(env, stats, gNetworkStatsClassInfo.roaming, size, grow)); if (roaming.get() == NULL) return -1; + ScopedIntArrayRW defaultNetwork(env, get_int_array(env, stats, + gNetworkStatsClassInfo.defaultNetwork, size, grow)); + if (defaultNetwork.get() == NULL) return -1; ScopedLongArrayRW rxBytes(env, get_long_array(env, stats, gNetworkStatsClassInfo.rxBytes, size, grow)); if (rxBytes.get() == NULL) return -1; @@ -269,7 +273,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, uid[i] = lines[i].uid; set[i] = lines[i].set; tag[i] = lines[i].tag; - // Metered and Roaming are populated in Java-land by inspecting the iface properties. + // Metered, roaming and defaultNetwork are populated in Java-land. rxBytes[i] = lines[i].rxBytes; rxPackets[i] = lines[i].rxPackets; txBytes[i] = lines[i].txBytes; @@ -285,6 +289,8 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, env->SetObjectField(stats, gNetworkStatsClassInfo.tag, tag.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.metered, metered.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.roaming, roaming.getJavaArray()); + env->SetObjectField(stats, gNetworkStatsClassInfo.defaultNetwork, + defaultNetwork.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxBytes, rxBytes.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.rxPackets, rxPackets.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.txBytes, txBytes.getJavaArray()); @@ -318,6 +324,7 @@ int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); + gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I"); gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 4ceb592af0..5f797691be 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; @@ -364,6 +365,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; + entry.defaultNetwork = DEFAULT_NETWORK_YES; entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0b25573c30..84dd05d326 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; @@ -677,9 +678,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, - ROAMING_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, - entry.operations)); + stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, + entry.txBytes, entry.txPackets, entry.operations)); return stats; } From 502b95fb44f0bc8236cb29137d74267cad2d28ab Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 01:12:04 +0900 Subject: [PATCH 0456/1150] Track and persist in stats whether traffic is on the default network. This change adds the defaultNetwork to the ident based on current system networking state, and persists that value to flash. Bug: 35142602 Test: runtest frameworks-net Test: downloaded files using default/non-default networks while watching dumpsys netstats Change-Id: Id8776d149b2977548a9eb455ad4926af55e25aba --- core/java/android/net/NetworkIdentity.java | 24 ++++++++++++---- .../server/net/NetworkIdentitySet.java | 28 +++++++++++++++++-- .../server/net/NetworkStatsCollection.java | 4 ++- .../server/net/NetworkStatsService.java | 7 +++-- 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index d3b35998be..fd118f3401 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -58,21 +58,24 @@ public class NetworkIdentity implements Comparable { final String mNetworkId; final boolean mRoaming; final boolean mMetered; + final boolean mDefaultNetwork; public NetworkIdentity( int type, int subType, String subscriberId, String networkId, boolean roaming, - boolean metered) { + boolean metered, boolean defaultNetwork) { mType = type; mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; mMetered = metered; + mDefaultNetwork = defaultNetwork; } @Override public int hashCode() { - return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered); + return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, + mDefaultNetwork); } @Override @@ -82,7 +85,8 @@ public class NetworkIdentity implements Comparable { return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming && Objects.equals(mSubscriberId, ident.mSubscriberId) && Objects.equals(mNetworkId, ident.mNetworkId) - && mMetered == ident.mMetered; + && mMetered == ident.mMetered + && mDefaultNetwork == ident.mDefaultNetwork; } return false; } @@ -109,6 +113,7 @@ public class NetworkIdentity implements Comparable { builder.append(", ROAMING"); } builder.append(", metered=").append(mMetered); + builder.append(", defaultNetwork=").append(mDefaultNetwork); return builder.append("}").toString(); } @@ -153,6 +158,10 @@ public class NetworkIdentity implements Comparable { return mMetered; } + public boolean getDefaultNetwork() { + return mDefaultNetwork; + } + /** * Scrub given IMSI on production builds. */ @@ -183,7 +192,8 @@ public class NetworkIdentity implements Comparable { * Build a {@link NetworkIdentity} from the given {@link NetworkState}, * assuming that any mobile networks are using the current IMSI. */ - public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state) { + public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, + boolean defaultNetwork) { final int type = state.networkInfo.getType(); final int subType = state.networkInfo.getSubtype(); @@ -216,7 +226,8 @@ public class NetworkIdentity implements Comparable { } } - return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered); + return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, + defaultNetwork); } @Override @@ -237,6 +248,9 @@ public class NetworkIdentity implements Comparable { if (res == 0) { res = Boolean.compare(mMetered, another.mMetered); } + if (res == 0) { + res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork); + } return res; } } diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index ee00fdc333..68cd5e7aed 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -39,6 +39,7 @@ public class NetworkIdentitySet extends HashSet implements private static final int VERSION_ADD_ROAMING = 2; private static final int VERSION_ADD_NETWORK_ID = 3; private static final int VERSION_ADD_METERED = 4; + private static final int VERSION_ADD_DEFAULT_NETWORK = 5; public NetworkIdentitySet() { } @@ -76,12 +77,20 @@ public class NetworkIdentitySet extends HashSet implements metered = (type == TYPE_MOBILE); } - add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered)); + final boolean defaultNetwork; + if (version >= VERSION_ADD_DEFAULT_NETWORK) { + defaultNetwork = in.readBoolean(); + } else { + defaultNetwork = true; + } + + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, + defaultNetwork)); } } public void writeToStream(DataOutputStream out) throws IOException { - out.writeInt(VERSION_ADD_METERED); + out.writeInt(VERSION_ADD_DEFAULT_NETWORK); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -90,6 +99,7 @@ public class NetworkIdentitySet extends HashSet implements writeOptionalString(out, ident.getNetworkId()); out.writeBoolean(ident.getRoaming()); out.writeBoolean(ident.getMetered()); + out.writeBoolean(ident.getDefaultNetwork()); } } @@ -119,6 +129,20 @@ public class NetworkIdentitySet extends HashSet implements return false; } + /** @return whether any {@link NetworkIdentity} in this set is considered on the default + network. */ + public boolean areAllMembersOnDefaultNetwork() { + if (isEmpty()) { + return true; + } + for (NetworkIdentity ident : this) { + if (!ident.getDefaultNetwork()) { + return false; + } + } + return true; + } + private static void writeOptionalString(DataOutputStream out, String value) throws IOException { if (value != null) { out.writeByte(1); diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 5f797691be..961a451778 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; @@ -365,7 +366,8 @@ public class NetworkStatsCollection implements FileRotator.Reader { entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; - entry.defaultNetwork = DEFAULT_NETWORK_YES; + entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() ? + DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 84dd05d326..78fd4b4923 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1061,7 +1061,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, + isDefault); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1081,7 +1083,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Copy the identify from IMS one but mark it as metered. NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), - ident.getRoaming(), true); + ident.getRoaming(), true /* metered */, + true /* onDefaultNetwork */); findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent); } From f6311456b2b06485d03bca6cd4c7dd1f634402ab Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 01:12:58 +0900 Subject: [PATCH 0457/1150] Add getDefaultNetwork to the NetworkStats public API. This allows an app using the public API to know whether the traffic in a particular bucket was on the default network (i.e., the network was selected by the system), or not (i.e., the network was selected by the app). Bug: 35142602 Test: builds, boots Test: added coverage to NetworkUsageStatsTest CTS test, still passes Change-Id: I9f6669908fa119743b9c0aa0c31a03e5ebafa7db --- core/java/android/app/usage/NetworkStats.java | 52 +++++++++++++++++++ .../app/usage/NetworkStatsManager.java | 35 +++++++------ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 2e44a630b0..da36157d85 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -227,6 +227,30 @@ public final class NetworkStats implements AutoCloseable { */ public static final int ROAMING_YES = 0x2; + /** @hide */ + @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { + DEFAULT_NETWORK_ALL, + DEFAULT_NETWORK_NO, + DEFAULT_NETWORK_YES + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DefaultNetwork {} + + /** + * Combined usage for this network regardless of whether it was the active default network. + */ + public static final int DEFAULT_NETWORK_ALL = -1; + + /** + * Usage that occurs while this network is not the active default network. + */ + public static final int DEFAULT_NETWORK_NO = 0x1; + + /** + * Usage that occurs while this network is the active default network. + */ + public static final int DEFAULT_NETWORK_YES = 0x2; + /** * Special TAG value for total data across all tags */ @@ -235,6 +259,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mDefaultNetwork; private int mMetered; private int mRoaming; private long mBeginTimeStamp; @@ -286,6 +311,15 @@ public final class NetworkStats implements AutoCloseable { return 0; } + private static @DefaultNetwork int convertDefaultNetwork(int defaultNetwork) { + switch (defaultNetwork) { + case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; + case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; + case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; + } + return 0; + } + public Bucket() { } @@ -350,6 +384,21 @@ public final class NetworkStats implements AutoCloseable { return mRoaming; } + /** + * Default network state. One of the following values:

            + *

              + *
            • {@link #DEFAULT_NETWORK_ALL}
            • + *
            • {@link #DEFAULT_NETWORK_NO}
            • + *
            • {@link #DEFAULT_NETWORK_YES}
            • + *
            + *

            Indicates whether the network usage occurred on the system default network for this + * type of traffic, or whether the application chose to send this traffic on a network that + * was not the one selected by the system. + */ + public @DefaultNetwork int getDefaultNetwork() { + return mDefaultNetwork; + } + /** * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. @@ -551,6 +600,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + bucketOut.mDefaultNetwork = Bucket.convertDefaultNetwork( + mRecycledSummaryEntry.defaultNetwork); bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; @@ -600,6 +651,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL; bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 853b00331a..90b514e272 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -60,10 +60,11 @@ import android.util.Log; * {@link #queryDetailsForUid}

            * {@link #queryDetails}

            * These queries do not aggregate over time but do aggregate over state, metered and roaming. - * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to - * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * Therefore there can be multiple buckets for a particular key. However, all Buckets will have + * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, + * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, + * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. *

            * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, @@ -136,7 +137,9 @@ public class NetworkStatsManager { * roaming. This means the bucket's start and end timestamp are going to be the same as the * 'startTime' and 'endTime' parameters. State is going to be * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, + * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -209,10 +212,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state, uid, metered, or roaming. This means buckets' - * start and end timestamps are going to be the same as the 'startTime' and 'endTime' - * parameters. State, uid, metered, and roaming are going to vary, and tag is going to be the - * same. + * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This + * means buckets' start and end timestamps are going to be the same as the 'startTime' and + * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to + * be the same. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -258,9 +261,10 @@ public class NetworkStatsManager { * belonging to calling user. Result is aggregated over state but not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the - * same as the 'uid' parameter and tag the same as 'tag' parameter. metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * same as the 'uid' parameter and tag the same as 'tag' parameter. + * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and + * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. @@ -301,9 +305,10 @@ public class NetworkStatsManager { * metered, nor roaming. This means buckets' start and end timestamps are going to be between * 'startTime' and 'endTime' parameters. State is going to be * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * tag {@link NetworkStats.Bucket#TAG_NONE}, + * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, + * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. From 976205c14881269026735bc46bf075dfb87b272b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 20 Jan 2018 02:02:56 +0900 Subject: [PATCH 0458/1150] Add the defaultNetwork element to the netstats.proto. This is in its own commit because AOSP has diverged from internal master. Bug: 35142602 Test: builds, boots Change-Id: I75fc85b961bc919e3d6c2adce6d6861c6f2c8379 --- core/java/android/net/NetworkIdentity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index fd118f3401..ce2de8554d 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -130,6 +130,7 @@ public class NetworkIdentity implements Comparable { proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); proto.end(start); } From 77df1d37eddb3c368c763b766aec9de170fd179a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 18 Jan 2018 14:38:16 -0800 Subject: [PATCH 0459/1150] Rename create/delete transform methods CreateTransportModeTransform and DeleteTransportModeTransform are both agnostic as far as which mode of transform it creates/deletes. As such, to facilitate the implementation of tunnel mode, this patch renames them to CreateTransform and DeleteTransform, along with all test names. Bug: 63588681 Test: frameworks/base unit tests and CTS tests run, passed Change-Id: I1f015eb7ad0e85fca966658a9402485ca2b44091 --- core/java/android/net/IIpSecService.aidl | 4 ++-- core/java/android/net/IpSecTransform.java | 5 ++--- services/core/java/com/android/server/IpSecService.java | 8 ++++---- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 790c80b1d9..eeb30e23d0 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -39,9 +39,9 @@ interface IIpSecService void closeUdpEncapsulationSocket(int resourceId); - IpSecTransformResponse createTransportModeTransform(in IpSecConfig c, in IBinder binder); + IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder); - void deleteTransportModeTransform(int transformId); + void deleteTransform(int transformId); void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 7b9b483092..794cafcf36 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -124,8 +124,7 @@ public final class IpSecTransform implements AutoCloseable { synchronized (this) { try { IIpSecService svc = getIpSecService(); - IpSecTransformResponse result = - svc.createTransportModeTransform(mConfig, new Binder()); + IpSecTransformResponse result = svc.createTransform(mConfig, new Binder()); int status = result.status; checkResultStatus(status); mResourceId = result.resourceId; @@ -170,7 +169,7 @@ public final class IpSecTransform implements AutoCloseable { * still want to clear out the transform. */ IIpSecService svc = getIpSecService(); - svc.deleteTransportModeTransform(mResourceId); + svc.deleteTransform(mResourceId); stopKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 46a35ec800..af33ab08cb 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1105,10 +1105,10 @@ public class IpSecService extends IIpSecService.Stub { * receive data. */ @Override - public synchronized IpSecTransformResponse createTransportModeTransform( - IpSecConfig c, IBinder binder) throws RemoteException { + public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder) + throws RemoteException { checkIpSecConfig(c); - checkNotNull(binder, "Null Binder passed to createTransportModeTransform"); + checkNotNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); @@ -1186,7 +1186,7 @@ public class IpSecService extends IIpSecService.Stub { * other reasons. */ @Override - public synchronized void deleteTransportModeTransform(int resourceId) throws RemoteException { + public synchronized void deleteTransform(int resourceId) throws RemoteException { UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); releaseResource(userRecord.mTransformRecords, resourceId); } From e7fdf8ac1a3fe64e26f565f9b4a11cb689fa036d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 21 Jan 2018 23:00:55 +0900 Subject: [PATCH 0460/1150] Remove obsolete NetworkStats.Entry constructor. The only caller is telephony code, and it's being fixed in this topic. Bug: 35142602 Test: builds, boots Change-Id: Ia77a1c2c297037f311c2355610c206cd8e3192c4 --- core/java/android/net/NetworkStats.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index a85f80e38d..01b2b39213 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -160,13 +160,6 @@ public class NetworkStats implements Parcelable { rxBytes, rxPackets, txBytes, txPackets, operations); } - // TODO: fix the the telephony code to pass DEFAULT_NETWORK_YES and remove this constructor. - public Entry(String iface, int uid, int set, int tag, int metered, int roaming, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - this(iface, uid, set, tag, metered, roaming, DEFAULT_NETWORK_YES, rxBytes, rxPackets, - txBytes, txPackets, operations); - } - public Entry(String iface, int uid, int set, int tag, int metered, int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { From 1a4a483ed6ba31a9bc57b013db52eda5d1911743 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 22 Jan 2018 11:54:46 +0900 Subject: [PATCH 0461/1150] Add metered, roaming, and defaultNetwork info to NetworkTemplate. This will allow data usage clients to query for and receive callbacks on data usage matching these conditions. Bug: 35142602 Test: atest FrameworksNetTests Change-Id: I4d985a2734eeab7ee454c09cc2098b6b3c671c23 --- core/java/android/net/NetworkTemplate.java | 69 +++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b307c5d6fc..8efd39a7a7 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -24,6 +24,15 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.DEFAULT_NETWORK_YES; +import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; +import static android.net.NetworkStats.ROAMING_ALL; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -191,16 +200,30 @@ public class NetworkTemplate implements Parcelable { private final String mNetworkId; + // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. + private final int mMetered; + private final int mRoaming; + private final int mDefaultNetwork; + public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; + mMetered = metered; + mRoaming = roaming; + mDefaultNetwork = defaultNetwork; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -213,6 +236,9 @@ public class NetworkTemplate implements Parcelable { mSubscriberId = in.readString(); mMatchSubscriberIds = in.createStringArray(); mNetworkId = in.readString(); + mMetered = in.readInt(); + mRoaming = in.readInt(); + mDefaultNetwork = in.readInt(); } @Override @@ -221,6 +247,9 @@ public class NetworkTemplate implements Parcelable { dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); dest.writeString(mNetworkId); + dest.writeInt(mMetered); + dest.writeInt(mRoaming); + dest.writeInt(mDefaultNetwork); } @Override @@ -243,12 +272,23 @@ public class NetworkTemplate implements Parcelable { if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); } + if (mMetered != METERED_ALL) { + builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); + } + if (mRoaming != ROAMING_ALL) { + builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); + } + if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { + builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( + mDefaultNetwork)); + } return builder.toString(); } @Override public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, mNetworkId); + return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, + mDefaultNetwork); } @Override @@ -257,7 +297,10 @@ public class NetworkTemplate implements Parcelable { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule && Objects.equals(mSubscriberId, other.mSubscriberId) - && Objects.equals(mNetworkId, other.mNetworkId); + && Objects.equals(mNetworkId, other.mNetworkId) + && mMetered == other.mMetered + && mRoaming == other.mRoaming + && mDefaultNetwork == other.mDefaultNetwork; } return false; } @@ -300,6 +343,10 @@ public class NetworkTemplate implements Parcelable { * Test if given {@link NetworkIdentity} matches this template. */ public boolean matches(NetworkIdentity ident) { + if (!matchesMetered(ident)) return false; + if (!matchesRoaming(ident)) return false; + if (!matchesDefaultNetwork(ident)) return false; + switch (mMatchRule) { case MATCH_MOBILE_ALL: return matchesMobile(ident); @@ -326,6 +373,24 @@ public class NetworkTemplate implements Parcelable { } } + private boolean matchesMetered(NetworkIdentity ident) { + return (mMetered == METERED_ALL) + || (mMetered == METERED_YES && ident.mMetered) + || (mMetered == METERED_NO && !ident.mMetered); + } + + private boolean matchesRoaming(NetworkIdentity ident) { + return (mRoaming == ROAMING_ALL) + || (mRoaming == ROAMING_YES && ident.mRoaming) + || (mRoaming == ROAMING_NO && !ident.mRoaming); + } + + private boolean matchesDefaultNetwork(NetworkIdentity ident) { + return (mDefaultNetwork == DEFAULT_NETWORK_ALL) + || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) + || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } From 3249e27a21367a2d6f7fcf4131ca9590a47df507 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 22 Jan 2018 21:00:49 +0900 Subject: [PATCH 0462/1150] Support passing a template to NetworkStatsManager queries. Currently, NetworkStatsManager queries and callbacks only allow selecting network traffic based on network identifiers: networkType, subscriptionId and networkId. The code ends up converting these into a template under the hood. Now that templates can express more fine-grained queries (e.g., select only roaming traffic, or select only traffic that's not on the default network) add a hidden method to pass in a template. This should have no security implications, as all the access controls are performed in NetworkStatsService. Bug: 35142602 Test: android.app.usage.cts.NetworkUsageStatsTest passes Change-Id: Iab4afa26b34544299d2a9c501c1b0feb470e90a9 --- .../app/usage/NetworkStatsManager.java | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 90b514e272..5576e86edd 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -131,6 +131,17 @@ public class NetworkStatsManager { } } + /** @hide */ + public Bucket querySummaryForDevice(NetworkTemplate template, + long startTime, long endTime) throws SecurityException, RemoteException { + Bucket bucket = null; + NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + bucket = stats.getDeviceSummaryForNetwork(); + + stats.close(); + return bucket; + } + /** * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and @@ -163,12 +174,7 @@ public class NetworkStatsManager { return null; } - Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); - bucket = stats.getDeviceSummaryForNetwork(); - - stats.close(); - return bucket; + return querySummaryForDevice(template, startTime, endTime); } /** @@ -340,6 +346,37 @@ public class NetworkStatsManager { return result; } + /** @hide */ + public void registerUsageCallback(NetworkTemplate template, int networkType, + long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { + checkNotNull(callback, "UsageCallback cannot be null"); + + final Looper looper; + if (handler == null) { + looper = Looper.myLooper(); + } else { + looper = handler.getLooper(); + } + + DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, + template, thresholdBytes); + try { + CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, + template.getSubscriberId(), callback); + callback.request = mService.registerUsageCallback( + mContext.getOpPackageName(), request, new Messenger(callbackHandler), + new Binder()); + if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); + + if (callback.request == null) { + Log.e(TAG, "Request from callback is null; should not happen"); + } + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when registering callback"); + throw e.rethrowFromSystemServer(); + } + } + /** * Registers to receive notifications about data usage on specified networks. * @@ -368,15 +405,7 @@ public class NetworkStatsManager { */ public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { - checkNotNull(callback, "UsageCallback cannot be null"); - - final Looper looper; - if (handler == null) { - looper = Looper.myLooper(); - } else { - looper = handler.getLooper(); - } - + NetworkTemplate template = createTemplate(networkType, subscriberId); if (DBG) { Log.d(TAG, "registerUsageCallback called with: {" + " networkType=" + networkType @@ -384,25 +413,7 @@ public class NetworkStatsManager { + " thresholdBytes=" + thresholdBytes + " }"); } - - NetworkTemplate template = createTemplate(networkType, subscriberId); - DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, - template, thresholdBytes); - try { - CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, - subscriberId, callback); - callback.request = mService.registerUsageCallback( - mContext.getOpPackageName(), request, new Messenger(callbackHandler), - new Binder()); - if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); - - if (callback.request == null) { - Log.e(TAG, "Request from callback is null; should not happen"); - } - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when registering callback"); - throw e.rethrowFromSystemServer(); - } + registerUsageCallback(template, networkType, thresholdBytes, callback, handler); } /** From d220c1630445ce396b1520cc5644db52d611486f Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 13 Dec 2017 18:26:40 -0800 Subject: [PATCH 0463/1150] Add checks to ensure SPIs are not reused This change adds an additional check in CheckIpsecConfig to prevent users from using the same SPI twice. This allows for a more granular error message. Bug: 70642141 Test: Tests added in IpSecServiceParameterizedTest Change-Id: I9621fb05c6b162bd8ae8db4ac1e64feaa9d0ac73 --- .../java/com/android/server/IpSecService.java | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index ef6bc437cb..24d493e301 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -571,6 +571,8 @@ public class IpSecService extends IIpSecService.Stub { mConfig = config; mSpi = spi; mSocket = socket; + + spi.setOwnedByTransform(); } public IpSecConfig getConfig() { @@ -651,16 +653,6 @@ public class IpSecService extends IIpSecService.Stub { /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { - if (mOwnedByTransform) { - Log.d(TAG, "Cannot release Spi " + mSpi + ": Currently locked by a Transform"); - // Because SPIs are "handed off" to transform, objects, they should never be - // freed from the SpiRecord once used in a transform. (They refer to the same SA, - // thus ownership and responsibility for freeing these resources passes to the - // Transform object). Thus, we should let the user free them without penalty once - // they are applied in a Transform object. - return; - } - try { mSrvConfig .getNetdInstance() @@ -694,6 +686,10 @@ public class IpSecService extends IIpSecService.Stub { mOwnedByTransform = true; } + public boolean getOwnedByTransform() { + return mOwnedByTransform; + } + @Override public void invalidate() throws RemoteException { getUserRecord().removeSpiRecord(mResourceId); @@ -1107,6 +1103,11 @@ public class IpSecService extends IIpSecService.Stub { // Retrieve SPI record; will throw IllegalArgumentException if not found SpiRecord s = userRecord.mSpiRecords.getResourceOrThrow(config.getSpiResourceId()); + // Check to ensure that SPI has not already been used. + if (s.getOwnedByTransform()) { + throw new IllegalStateException("SPI already in use; cannot be used in new Transforms"); + } + // If no remote address is supplied, then use one from the SPI. if (TextUtils.isEmpty(config.getDestinationAddress())) { config.setDestinationAddress(s.getDestinationAddress()); From 37a880e339d6ffa4fc5df11a20c0b719e339e3ee Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 20 Nov 2017 18:23:46 -0800 Subject: [PATCH 0464/1150] Add BPF support for NetworkStatsService Add the native implementation for NetworkStatsService to read the uidStatsMap and tagStatsMap to get the network traffic information. Currently the implementation only try to get the data from bpf for a reference but the final value returned is still from old xt_qtaguid module. So the result will not be effected. The bpf implementation is depending on libbpf inside netd. Bug: 30950746 Test: CtsNetTestCases -t android.net.cts.TrafficStatsTest Change-Id: Ia85e4d4d602f6bd536739d89085e6dc37ad82e15 --- .../server/net/NetworkStatsService.java | 16 +++-- ...android_server_net_NetworkStatsService.cpp | 58 ++++++++++++++----- 2 files changed, 53 insertions(+), 21 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 78fd4b4923..bfc150e1a9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -887,17 +887,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getUidStats(int uid, int type) { - return nativeGetUidStat(uid, type); + return nativeGetUidStat(uid, type, checkBpfStatsEnable()); } @Override public long getIfaceStats(String iface, int type) { - return nativeGetIfaceStat(iface, type); + return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); } @Override public long getTotalStats(int type) { - return nativeGetTotalStat(type); + return nativeGetTotalStat(type, checkBpfStatsEnable()); + } + + private boolean checkBpfStatsEnable() { + return new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); } /** @@ -1668,7 +1672,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static int TYPE_TCP_RX_PACKETS; private static int TYPE_TCP_TX_PACKETS; - private static native long nativeGetTotalStat(int type); - private static native long nativeGetIfaceStat(String iface, int type); - private static native long nativeGetUidStat(int uid, int type); + private static native long nativeGetTotalStat(int type, boolean useBpfStats); + private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats); + private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats); } diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 8de24e5565..3302dea535 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -29,6 +29,15 @@ #include #include +#include "android-base/unique_fd.h" +#include "bpf/BpfNetworkStats.h" +#include "bpf/BpfUtils.h" + +using android::bpf::Stats; +using android::bpf::hasBpfSupport; +using android::bpf::bpfGetUidStats; +using android::bpf::bpfGetIfaceStats; + namespace android { static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt"; @@ -46,15 +55,6 @@ enum StatsType { TCP_TX_PACKETS = 5 }; -struct Stats { - uint64_t rxBytes; - uint64_t rxPackets; - uint64_t txBytes; - uint64_t txPackets; - uint64_t tcpRxPackets; - uint64_t tcpTxPackets; -}; - static uint64_t getStatsType(struct Stats* stats, StatsType type) { switch (type) { case RX_BYTES: @@ -150,9 +150,18 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) { return 0; } -static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { +static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) { struct Stats stats; memset(&stats, 0, sizeof(Stats)); + + if (useBpfStats) { + if (bpfGetIfaceStats(NULL, &stats) == 0) { + return getStatsType(&stats, (StatsType) type); + } else { + return UNKNOWN; + } + } + if (parseIfaceStats(NULL, &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { @@ -160,7 +169,8 @@ static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { } } -static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { +static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, + jboolean useBpfStats) { ScopedUtfChars iface8(env, iface); if (iface8.c_str() == NULL) { return UNKNOWN; @@ -168,6 +178,15 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { struct Stats stats; memset(&stats, 0, sizeof(Stats)); + + if (useBpfStats) { + if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { + return getStatsType(&stats, (StatsType) type); + } else { + return UNKNOWN; + } + } + if (parseIfaceStats(iface8.c_str(), &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { @@ -175,9 +194,18 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { } } -static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { +static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) { struct Stats stats; memset(&stats, 0, sizeof(Stats)); + + if (useBpfStats) { + if (bpfGetUidStats(uid, &stats) == 0) { + return getStatsType(&stats, (StatsType) type); + } else { + return UNKNOWN; + } + } + if (parseUidStats(uid, &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { @@ -186,9 +214,9 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } static const JNINativeMethod gMethods[] = { - {"nativeGetTotalStat", "(I)J", (void*) getTotalStat}, - {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat}, - {"nativeGetUidStat", "(II)J", (void*) getUidStat}, + {"nativeGetTotalStat", "(IZ)J", (void*) getTotalStat}, + {"nativeGetIfaceStat", "(Ljava/lang/String;IZ)J", (void*) getIfaceStat}, + {"nativeGetUidStat", "(IIZ)J", (void*) getUidStat}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { From 155b0b0866aaf41b1a9998f4267cd9a7bf983fae Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 20 Nov 2017 17:03:59 -0800 Subject: [PATCH 0465/1150] Add bpf support for NetworkStatsFactory Add the native method used to read the detail information of network stats from bpf maps. The native method of NetworkStatsFactory should choose the correct implementation to get the stats detail depending on the kernel version. Currently the bpf result is printed as a reference and the actual behavior of NetworkStatsFactory should not change. Test: NetworkStatsFactory related cts test should not fail. Bug: 30950746 Change-Id: I4715a23559b5b2306bd556cea0431f0ed172a993 --- .../internal/net/NetworkStatsFactory.java | 13 +-- ...droid_internal_net_NetworkStatsFactory.cpp | 85 +++++++++++-------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index b576a20db5..47666b57e8 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -62,6 +62,8 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; + private boolean mUseBpfStats; + // TODO: to improve testability and avoid global state, do not use a static variable. @GuardedBy("sStackedIfaces") private static final ArrayMap sStackedIfaces = new ArrayMap<>(); @@ -77,14 +79,15 @@ public class NetworkStatsFactory { } public NetworkStatsFactory() { - this(new File("/proc/")); + this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists()); } @VisibleForTesting - public NetworkStatsFactory(File procRoot) { + public NetworkStatsFactory(File procRoot, boolean useBpfStats) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); + mUseBpfStats = useBpfStats; } /** @@ -252,7 +255,7 @@ public class NetworkStatsFactory { stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, - limitIfaces, limitTag) != 0) { + limitIfaces, limitTag, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); } if (SANITY_CHECK_NATIVE) { @@ -346,6 +349,6 @@ public class NetworkStatsFactory { * are expected to monotonically increase since device boot. */ @VisibleForTesting - public static native int nativeReadNetworkStatsDetail( - NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag); + public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, + int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index d254de65f7..99d9839570 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -30,7 +30,14 @@ #include #include -#include + +#include "android-base/unique_fd.h" +#include "bpf/BpfNetworkStats.h" +#include "bpf/BpfUtils.h" + +using android::bpf::hasBpfSupport; +using android::bpf::parseBpfNetworkStatsDetail; +using android::bpf::stats_line; namespace android { @@ -53,17 +60,6 @@ static struct { jfieldID operations; } gNetworkStatsClassInfo; -struct stats_line { - char iface[32]; - int32_t uid; - int32_t set; - int32_t tag; - int64_t rxBytes; - int64_t rxPackets; - int64_t txBytes; - int64_t txPackets; -}; - static jobjectArray get_string_array(JNIEnv* env, jobject obj, jfieldID field, int size, bool grow) { if (!grow) { @@ -97,33 +93,14 @@ static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int s return env->NewLongArray(size); } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, - jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } - - FILE *fp = fopen(path8.c_str(), "r"); +static int legacyReadNetworkStatsDetail(std::vector* lines, + const std::vector& limitIfaces, + int limitTag, int limitUid, const char* path) { + FILE* fp = fopen(path, "r"); if (fp == NULL) { return -1; } - Vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - limitIfaces.setCapacity(num); - for (int i=0; iGetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.add(String8(string8.c_str())); - } - } - } - - Vector lines; - int lastIdx = 1; int idx; char buffer[384]; @@ -215,7 +192,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, //ALOGI("skipping due to uid: %s", buffer); continue; } - lines.push_back(s); + lines->push_back(s); } else { //ALOGI("skipping due to bad remaining fields: %s", pos); } @@ -225,8 +202,42 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, ALOGE("Failed to close netstats file"); return -1; } + return 0; +} + +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, + jint limitUid, jobjectArray limitIfacesObj, jint limitTag, + jboolean useBpfStats) { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + return -1; + } + + std::vector limitIfaces; + if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { + int num = env->GetArrayLength(limitIfacesObj); + for (int i = 0; i < num; i++) { + jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); + ScopedUtfChars string8(env, string); + if (string8.c_str() != NULL) { + limitIfaces.push_back(std::string(string8.c_str())); + } + } + } + std::vector lines; + + + if (useBpfStats) { + if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) + return -1; + } else { + if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, + limitUid, path8.c_str()) < 0) + return -1; + } int size = lines.size(); + bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); ScopedLocalRef iface(env, get_string_array(env, stats, @@ -303,7 +314,7 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", - "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I", + "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", (void*) readNetworkStatsDetail } }; From e2cafb6d71c50b130d5615ebef2f0f211d4a4ddf Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 18 Jan 2018 19:48:52 -0800 Subject: [PATCH 0466/1150] Use /proc/net/dev to get stats summary If the qtaguid proc file is no longer exist, the device is running new eBPF module to do traffic accounting. So the NetworkStatsFactory need to use the proc/net/dev interface to get the per interface traffic stats summary. Also, adding a test to verify the helper function work properly Bug: 30950746 Test: run NetworkStatsFactoryTest Change-Id: Ia36808bf02f1637dd41a3e7c50917b91b1a77524 --- .../internal/net/NetworkStatsFactory.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 47666b57e8..902bd120e8 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -31,13 +31,17 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; +import com.google.android.collect.Lists; import libcore.io.IoUtils; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; +import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; +import java.util.ArrayList; import java.util.Objects; /** @@ -55,6 +59,8 @@ public class NetworkStatsFactory { // Used for correct stats accounting on clatd interfaces. private static final int IPV4V6_HEADER_DELTA = 20; + /** Path to {@code /proc/net/dev}. */ + private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ @@ -84,12 +90,51 @@ public class NetworkStatsFactory { @VisibleForTesting public NetworkStatsFactory(File procRoot, boolean useBpfStats) { + mStatsIfaceDev = new File(procRoot, "net/dev"); mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; } + @VisibleForTesting + public NetworkStats readNetworkStatsIfaceDev() throws IOException { + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); + + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + final NetworkStats.Entry entry = new NetworkStats.Entry(); + + BufferedReader reader = null; + try { + reader = new BufferedReader(new FileReader(mStatsIfaceDev)); + + // skip first two header lines + reader.readLine(); + reader.readLine(); + + // parse remaining lines + String line; + while ((line = reader.readLine()) != null) { + String[] values = line.trim().split("\\:?\\s+"); + entry.iface = values[0]; + entry.uid = UID_ALL; + entry.set = SET_ALL; + entry.tag = TAG_NONE; + entry.rxBytes = Long.parseLong(values[1]); + entry.rxPackets = Long.parseLong(values[2]); + entry.txBytes = Long.parseLong(values[9]); + entry.txPackets = Long.parseLong(values[10]); + stats.addValues(entry); + } + } catch (NullPointerException|NumberFormatException e) { + throw new ProtocolException("problem parsing stats", e); + } finally { + IoUtils.closeQuietly(reader); + StrictMode.setThreadPolicy(savedPolicy); + } + return stats; + } + /** * Parse and return interface-level summary {@link NetworkStats} measured * using {@code /proc/net/dev} style hooks, which may include non IP layer @@ -99,6 +144,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { + + // Return the stats get from /proc/net/dev if switched to bpf module. + if (mUseBpfStats) + return readNetworkStatsIfaceDev(); + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); @@ -150,6 +200,11 @@ public class NetworkStatsFactory { * @throws IllegalStateException when problem parsing stats. */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { + + // Return the stats get from /proc/net/dev if qtaguid module is replaced. + if (mUseBpfStats) + return readNetworkStatsIfaceDev(); + final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); // return null when kernel doesn't support From bbe19ecf9aa240bfd2ecf51c8025992d2751c855 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 19 Jan 2018 01:12:58 +0900 Subject: [PATCH 0467/1150] Add getDefaultNetwork to the NetworkStats public API. This allows an app using the public API to know whether the traffic in a particular bucket was on the default network (i.e., the network was selected by the system), or not (i.e., the network was selected by the app). Bug: 35142602 Test: builds, boots Test: added coverage to NetworkUsageStatsTest CTS test, still passes Change-Id: I9f6669908fa119743b9c0aa0c31a03e5ebafa7db Merged-In: I9f6669908fa119743b9c0aa0c31a03e5ebafa7db --- core/java/android/app/usage/NetworkStats.java | 52 +++++++++++++++++++ .../app/usage/NetworkStatsManager.java | 35 +++++++------ 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 222e9a0e5e..d33af4faeb 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -215,6 +215,30 @@ public final class NetworkStats implements AutoCloseable { */ public static final int ROAMING_YES = 0x2; + /** @hide */ + @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { + DEFAULT_NETWORK_ALL, + DEFAULT_NETWORK_NO, + DEFAULT_NETWORK_YES + }) + @Retention(RetentionPolicy.SOURCE) + public @interface DefaultNetwork {} + + /** + * Combined usage for this network regardless of whether it was the active default network. + */ + public static final int DEFAULT_NETWORK_ALL = -1; + + /** + * Usage that occurs while this network is not the active default network. + */ + public static final int DEFAULT_NETWORK_NO = 0x1; + + /** + * Usage that occurs while this network is the active default network. + */ + public static final int DEFAULT_NETWORK_YES = 0x2; + /** * Special TAG value for total data across all tags */ @@ -223,6 +247,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; + private int mDefaultNetwork; private int mMetered; private int mRoaming; private long mBeginTimeStamp; @@ -274,6 +299,15 @@ public final class NetworkStats implements AutoCloseable { return 0; } + private static @DefaultNetwork int convertDefaultNetwork(int defaultNetwork) { + switch (defaultNetwork) { + case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; + case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; + case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; + } + return 0; + } + public Bucket() { } @@ -338,6 +372,21 @@ public final class NetworkStats implements AutoCloseable { return mRoaming; } + /** + * Default network state. One of the following values:

            + *

              + *
            • {@link #DEFAULT_NETWORK_ALL}
            • + *
            • {@link #DEFAULT_NETWORK_NO}
            • + *
            • {@link #DEFAULT_NETWORK_YES}
            • + *
            + *

            Indicates whether the network usage occurred on the system default network for this + * type of traffic, or whether the application chose to send this traffic on a network that + * was not the one selected by the system. + */ + public @DefaultNetwork int getDefaultNetwork() { + return mDefaultNetwork; + } + /** * Start timestamp of the bucket's time interval. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. @@ -539,6 +588,8 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); + bucketOut.mDefaultNetwork = Bucket.convertDefaultNetwork( + mRecycledSummaryEntry.defaultNetwork); bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); bucketOut.mBeginTimeStamp = mStartTimeStamp; @@ -588,6 +639,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL; bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 853b00331a..90b514e272 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -60,10 +60,11 @@ import android.util.Log; * {@link #queryDetailsForUid}

            * {@link #queryDetails}

            * These queries do not aggregate over time but do aggregate over state, metered and roaming. - * Therefore there can be multiple buckets for a particular key but all Bucket's state is going to - * be {@link NetworkStats.Bucket#STATE_ALL}, all Bucket's metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and all Bucket's roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * Therefore there can be multiple buckets for a particular key. However, all Buckets will have + * {@code state} {@link NetworkStats.Bucket#STATE_ALL}, + * {@code defaultNetwork} {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * {@code metered } {@link NetworkStats.Bucket#METERED_ALL}, + * {@code roaming} {@link NetworkStats.Bucket#ROAMING_ALL}. *

            * NOTE: Calling {@link #querySummaryForDevice} or accessing stats for apps other than the * calling app requires the permission {@link android.Manifest.permission#PACKAGE_USAGE_STATS}, @@ -136,7 +137,9 @@ public class NetworkStatsManager { * roaming. This means the bucket's start and end timestamp are going to be the same as the * 'startTime' and 'endTime' parameters. State is going to be * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, - * tag {@link NetworkStats.Bucket#TAG_NONE}, metered {@link NetworkStats.Bucket#METERED_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, + * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. * * @param networkType As defined in {@link ConnectivityManager}, e.g. @@ -209,10 +212,10 @@ public class NetworkStatsManager { /** * Query network usage statistics summaries. Result filtered to include only uids belonging to * calling user. Result is aggregated over time, hence all buckets will have the same start and - * end timestamps. Not aggregated over state, uid, metered, or roaming. This means buckets' - * start and end timestamps are going to be the same as the 'startTime' and 'endTime' - * parameters. State, uid, metered, and roaming are going to vary, and tag is going to be the - * same. + * end timestamps. Not aggregated over state, uid, default network, metered, or roaming. This + * means buckets' start and end timestamps are going to be the same as the 'startTime' and + * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to + * be the same. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -258,9 +261,10 @@ public class NetworkStatsManager { * belonging to calling user. Result is aggregated over state but not aggregated over time. * This means buckets' start and end timestamps are going to be between 'startTime' and * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the - * same as the 'uid' parameter and tag the same as 'tag' parameter. metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * same as the 'uid' parameter and tag the same as 'tag' parameter. + * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and + * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. @@ -301,9 +305,10 @@ public class NetworkStatsManager { * metered, nor roaming. This means buckets' start and end timestamps are going to be between * 'startTime' and 'endTime' parameters. State is going to be * {@link NetworkStats.Bucket#STATE_ALL}, uid will vary, - * tag {@link NetworkStats.Bucket#TAG_NONE}, metered is going to be - * {@link NetworkStats.Bucket#METERED_ALL}, and roaming is going to be - * {@link NetworkStats.Bucket#ROAMING_ALL}. + * tag {@link NetworkStats.Bucket#TAG_NONE}, + * default network is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, + * and roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. From 3729a8dd4c7bd4b5fca20cf633e2916294c9c05d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 22 Jan 2018 21:00:49 +0900 Subject: [PATCH 0468/1150] Support passing a template to NetworkStatsManager queries. Currently, NetworkStatsManager queries and callbacks only allow selecting network traffic based on network identifiers: networkType, subscriptionId and networkId. The code ends up converting these into a template under the hood. Now that templates can express more fine-grained queries (e.g., select only roaming traffic, or select only traffic that's not on the default network) add a hidden method to pass in a template. This should have no security implications, as all the access controls are performed in NetworkStatsService. Bug: 35142602 Test: android.app.usage.cts.NetworkUsageStatsTest passes Change-Id: Iab4afa26b34544299d2a9c501c1b0feb470e90a9 Merged-In: Iab4afa26b34544299d2a9c501c1b0feb470e90a9 --- .../app/usage/NetworkStatsManager.java | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 90b514e272..5576e86edd 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -131,6 +131,17 @@ public class NetworkStatsManager { } } + /** @hide */ + public Bucket querySummaryForDevice(NetworkTemplate template, + long startTime, long endTime) throws SecurityException, RemoteException { + Bucket bucket = null; + NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + bucket = stats.getDeviceSummaryForNetwork(); + + stats.close(); + return bucket; + } + /** * Query network usage statistics summaries. Result is summarised data usage for the whole * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and @@ -163,12 +174,7 @@ public class NetworkStatsManager { return null; } - Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); - bucket = stats.getDeviceSummaryForNetwork(); - - stats.close(); - return bucket; + return querySummaryForDevice(template, startTime, endTime); } /** @@ -340,6 +346,37 @@ public class NetworkStatsManager { return result; } + /** @hide */ + public void registerUsageCallback(NetworkTemplate template, int networkType, + long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { + checkNotNull(callback, "UsageCallback cannot be null"); + + final Looper looper; + if (handler == null) { + looper = Looper.myLooper(); + } else { + looper = handler.getLooper(); + } + + DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, + template, thresholdBytes); + try { + CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, + template.getSubscriberId(), callback); + callback.request = mService.registerUsageCallback( + mContext.getOpPackageName(), request, new Messenger(callbackHandler), + new Binder()); + if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); + + if (callback.request == null) { + Log.e(TAG, "Request from callback is null; should not happen"); + } + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when registering callback"); + throw e.rethrowFromSystemServer(); + } + } + /** * Registers to receive notifications about data usage on specified networks. * @@ -368,15 +405,7 @@ public class NetworkStatsManager { */ public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { - checkNotNull(callback, "UsageCallback cannot be null"); - - final Looper looper; - if (handler == null) { - looper = Looper.myLooper(); - } else { - looper = handler.getLooper(); - } - + NetworkTemplate template = createTemplate(networkType, subscriberId); if (DBG) { Log.d(TAG, "registerUsageCallback called with: {" + " networkType=" + networkType @@ -384,25 +413,7 @@ public class NetworkStatsManager { + " thresholdBytes=" + thresholdBytes + " }"); } - - NetworkTemplate template = createTemplate(networkType, subscriberId); - DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, - template, thresholdBytes); - try { - CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, - subscriberId, callback); - callback.request = mService.registerUsageCallback( - mContext.getOpPackageName(), request, new Messenger(callbackHandler), - new Binder()); - if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); - - if (callback.request == null) { - Log.e(TAG, "Request from callback is null; should not happen"); - } - } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when registering callback"); - throw e.rethrowFromSystemServer(); - } + registerUsageCallback(template, networkType, thresholdBytes, callback, handler); } /** From 1b0d4fd42b67af6bbb286cd8580f8a8546b99804 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 20 Jan 2018 02:02:56 +0900 Subject: [PATCH 0469/1150] Add the defaultNetwork element to the netstats.proto. This is in its own commit because AOSP has diverged from internal master. Bug: 35142602 Test: builds, boots Change-Id: I75fc85b961bc919e3d6c2adce6d6861c6f2c8379 Merged-In: I75fc85b961bc919e3d6c2adce6d6861c6f2c8379 --- core/java/android/net/NetworkIdentity.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index fd118f3401..ce2de8554d 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -130,6 +130,7 @@ public class NetworkIdentity implements Comparable { proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); proto.end(start); } From 8afb8fb55da885a776d9bfcdb1c57823b0dc959b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 22 Jan 2018 11:54:46 +0900 Subject: [PATCH 0470/1150] Add metered, roaming, and defaultNetwork info to NetworkTemplate. This will allow data usage clients to query for and receive callbacks on data usage matching these conditions. Bug: 35142602 Test: atest FrameworksNetTests Change-Id: I4d985a2734eeab7ee454c09cc2098b6b3c671c23 Merged-In: I4d985a2734eeab7ee454c09cc2098b6b3c671c23 --- core/java/android/net/NetworkTemplate.java | 69 +++++++++++++++++++++- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index b307c5d6fc..8efd39a7a7 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -24,6 +24,15 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.DEFAULT_NETWORK_YES; +import static android.net.NetworkStats.METERED_ALL; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.METERED_YES; +import static android.net.NetworkStats.ROAMING_ALL; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; @@ -191,16 +200,30 @@ public class NetworkTemplate implements Parcelable { private final String mNetworkId; + // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. + private final int mMetered; + private final int mRoaming; + private final int mDefaultNetwork; + public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL); + } + + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; + mMetered = metered; + mRoaming = roaming; + mDefaultNetwork = defaultNetwork; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -213,6 +236,9 @@ public class NetworkTemplate implements Parcelable { mSubscriberId = in.readString(); mMatchSubscriberIds = in.createStringArray(); mNetworkId = in.readString(); + mMetered = in.readInt(); + mRoaming = in.readInt(); + mDefaultNetwork = in.readInt(); } @Override @@ -221,6 +247,9 @@ public class NetworkTemplate implements Parcelable { dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); dest.writeString(mNetworkId); + dest.writeInt(mMetered); + dest.writeInt(mRoaming); + dest.writeInt(mDefaultNetwork); } @Override @@ -243,12 +272,23 @@ public class NetworkTemplate implements Parcelable { if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); } + if (mMetered != METERED_ALL) { + builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); + } + if (mRoaming != ROAMING_ALL) { + builder.append(", roaming=").append(NetworkStats.roamingToString(mRoaming)); + } + if (mDefaultNetwork != DEFAULT_NETWORK_ALL) { + builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( + mDefaultNetwork)); + } return builder.toString(); } @Override public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, mNetworkId); + return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, + mDefaultNetwork); } @Override @@ -257,7 +297,10 @@ public class NetworkTemplate implements Parcelable { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule && Objects.equals(mSubscriberId, other.mSubscriberId) - && Objects.equals(mNetworkId, other.mNetworkId); + && Objects.equals(mNetworkId, other.mNetworkId) + && mMetered == other.mMetered + && mRoaming == other.mRoaming + && mDefaultNetwork == other.mDefaultNetwork; } return false; } @@ -300,6 +343,10 @@ public class NetworkTemplate implements Parcelable { * Test if given {@link NetworkIdentity} matches this template. */ public boolean matches(NetworkIdentity ident) { + if (!matchesMetered(ident)) return false; + if (!matchesRoaming(ident)) return false; + if (!matchesDefaultNetwork(ident)) return false; + switch (mMatchRule) { case MATCH_MOBILE_ALL: return matchesMobile(ident); @@ -326,6 +373,24 @@ public class NetworkTemplate implements Parcelable { } } + private boolean matchesMetered(NetworkIdentity ident) { + return (mMetered == METERED_ALL) + || (mMetered == METERED_YES && ident.mMetered) + || (mMetered == METERED_NO && !ident.mMetered); + } + + private boolean matchesRoaming(NetworkIdentity ident) { + return (mRoaming == ROAMING_ALL) + || (mRoaming == ROAMING_YES && ident.mRoaming) + || (mRoaming == ROAMING_NO && !ident.mRoaming); + } + + private boolean matchesDefaultNetwork(NetworkIdentity ident) { + return (mDefaultNetwork == DEFAULT_NETWORK_ALL) + || (mDefaultNetwork == DEFAULT_NETWORK_YES && ident.mDefaultNetwork) + || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } From 7377b3cac71d0da75c5ee965f4c9b7d7d2df3b1a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 23 Jan 2018 11:01:28 -0800 Subject: [PATCH 0471/1150] Expose applyTunnelModeTransform as a system API Simple change to expose systemAPI for applyTunnelModeTransform Bug: 36033193 Test: All CTS, unit tests passing Change-Id: I2d857c048bc0dc80c3949387f946b1f5adf0527e --- core/java/android/net/IpSecManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index f04f03f6b6..6125394ab5 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -748,7 +748,7 @@ public final class IpSecManager { * @hide */ @SystemApi - void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, + public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, IpSecTransform transform) throws IOException { // TODO: call IpSecService } From 79d011823be02a063f3181deb819e24ce53ff458 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 18 Jan 2018 18:31:45 -0800 Subject: [PATCH 0472/1150] Add TunnelInterface API and KernelResourceRecords This change adds one KernelResourceRecord type (TunnelInterfaceRecord), and adds methods for the creation of TunnelInterfaces, as well as the application of Transforms to the given TunnelInterfaces As part of the generation of ikeys/okeys, a ReserveKeyTracker manages a java bitset to avoid collisions and reserve/release keys. Bug: 63588681 Test: Compiles, CTS, unit tests all pass on AOSP_marlin Change-Id: I9e9b6455e27073acd4491eae666aa966b3b10e0f --- core/java/android/net/IIpSecService.aidl | 19 ++ core/java/android/net/IpSecManager.java | 53 +++- .../net/IpSecTunnelInterfaceResponse.aidl | 20 ++ .../net/IpSecTunnelInterfaceResponse.java | 78 +++++ .../java/com/android/server/IpSecService.java | 284 ++++++++++++++++++ 5 files changed, 446 insertions(+), 8 deletions(-) create mode 100644 core/java/android/net/IpSecTunnelInterfaceResponse.aidl create mode 100644 core/java/android/net/IpSecTunnelInterfaceResponse.java diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index eeb30e23d0..3ce0283d7f 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -21,6 +21,7 @@ import android.net.IpSecConfig; import android.net.IpSecUdpEncapResponse; import android.net.IpSecSpiResponse; import android.net.IpSecTransformResponse; +import android.net.IpSecTunnelInterfaceResponse; import android.os.Bundle; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -39,11 +40,29 @@ interface IIpSecService void closeUdpEncapsulationSocket(int resourceId); + IpSecTunnelInterfaceResponse createTunnelInterface( + in String localAddr, + in String remoteAddr, + in Network underlyingNetwork, + in IBinder binder); + + void addAddressToTunnelInterface( + int tunnelResourceId, + String localAddr); + + void removeAddressFromTunnelInterface( + int tunnelResourceId, + String localAddr); + + void deleteTunnelInterface(int resourceId); + IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder); void deleteTransform(int transformId); void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); + void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId); + void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 6125394ab5..24a078fccc 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -685,7 +685,30 @@ public final class IpSecManager { mLocalAddress = localAddress; mRemoteAddress = remoteAddress; mUnderlyingNetwork = underlyingNetwork; - // TODO: Call IpSecService + + try { + IpSecTunnelInterfaceResponse result = + mService.createTunnelInterface( + localAddress.getHostAddress(), + remoteAddress.getHostAddress(), + underlyingNetwork, + new Binder()); + switch (result.status) { + case Status.OK: + break; + case Status.RESOURCE_UNAVAILABLE: + throw new ResourceUnavailableException( + "No more tunnel interfaces may be allocated by this requester."); + default: + throw new RuntimeException( + "Unknown status returned by IpSecService: " + result.status); + } + mResourceId = result.resourceId; + mInterfaceName = result.interfaceName; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + mCloseGuard.open("constructor"); } /** @@ -697,12 +720,12 @@ public final class IpSecManager { */ @Override public void close() { - // try { - // TODO: Call IpSecService - mResourceId = INVALID_RESOURCE_ID; - // } catch (RemoteException e) { - // throw e.rethrowFromSystemServer(); - // } + try { + mService.deleteTunnelInterface(mResourceId); + mResourceId = INVALID_RESOURCE_ID; + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } mCloseGuard.close(); } @@ -714,11 +737,20 @@ public final class IpSecManager { } close(); } + + /** @hide */ + @VisibleForTesting + public int getResourceId() { + return mResourceId; + } } /** * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. * + *

            An application that creates tunnels is responsible for cleaning up the tunnel when the + * underlying network goes away, and the onLost() callback is received. + * * @param localAddress The local addres of the tunnel * @param remoteAddress The local addres of the tunnel * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. @@ -750,7 +782,12 @@ public final class IpSecManager { @SystemApi public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, IpSecTransform transform) throws IOException { - // TODO: call IpSecService + try { + mService.applyTunnelModeTransform( + tunnel.getResourceId(), direction, transform.getResourceId()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** * Construct an instance of IpSecManager within an application context. diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.aidl b/core/java/android/net/IpSecTunnelInterfaceResponse.aidl new file mode 100644 index 0000000000..7239221415 --- /dev/null +++ b/core/java/android/net/IpSecTunnelInterfaceResponse.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +parcelable IpSecTunnelInterfaceResponse; diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.java b/core/java/android/net/IpSecTunnelInterfaceResponse.java new file mode 100644 index 0000000000..c23d831a44 --- /dev/null +++ b/core/java/android/net/IpSecTunnelInterfaceResponse.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.net; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * This class is used to return an IpSecTunnelInterface resource Id and and corresponding status + * from the IpSecService to an IpSecTunnelInterface object. + * + * @hide + */ +public final class IpSecTunnelInterfaceResponse implements Parcelable { + private static final String TAG = "IpSecTunnelInterfaceResponse"; + + public final int resourceId; + public final String interfaceName; + public final int status; + // Parcelable Methods + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(status); + out.writeInt(resourceId); + out.writeString(interfaceName); + } + + public IpSecTunnelInterfaceResponse(int inStatus) { + if (inStatus == IpSecManager.Status.OK) { + throw new IllegalArgumentException("Valid status implies other args must be provided"); + } + status = inStatus; + resourceId = IpSecManager.INVALID_RESOURCE_ID; + interfaceName = ""; + } + + public IpSecTunnelInterfaceResponse(int inStatus, int inResourceId, String inInterfaceName) { + status = inStatus; + resourceId = inResourceId; + interfaceName = inInterfaceName; + } + + private IpSecTunnelInterfaceResponse(Parcel in) { + status = in.readInt(); + resourceId = in.readInt(); + interfaceName = in.readString(); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) { + return new IpSecTunnelInterfaceResponse(in); + } + + public IpSecTunnelInterfaceResponse[] newArray(int size) { + return new IpSecTunnelInterfaceResponse[size]; + } + }; +} diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a9a81089fc..c2adbfaeb7 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -34,7 +34,9 @@ import android.net.IpSecManager; import android.net.IpSecSpiResponse; import android.net.IpSecTransform; import android.net.IpSecTransformResponse; +import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; +import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; @@ -50,6 +52,7 @@ import android.text.TextUtils; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -62,6 +65,7 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.BitSet; import java.util.List; import libcore.io.IoUtils; @@ -99,6 +103,7 @@ public class IpSecService extends IIpSecService.Stub { static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer + static final String TUNNEL_INTERFACE_PREFIX = "ipsec"; /* Binder context for this service */ private final Context mContext; @@ -347,6 +352,7 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final class UserRecord { /* Maximum number of each type of resource that a single UID may possess */ + public static final int MAX_NUM_TUNNEL_INTERFACES = 2; public static final int MAX_NUM_ENCAP_SOCKETS = 2; public static final int MAX_NUM_TRANSFORMS = 4; public static final int MAX_NUM_SPIS = 8; @@ -366,6 +372,8 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResourceArray<>(TransformRecord.class.getSimpleName()); final RefcountedResourceArray mEncapSocketRecords = new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); + final RefcountedResourceArray mTunnelInterfaceRecords = + new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName()); /** * Trackers for quotas for each of the OwnedResource types. @@ -379,6 +387,7 @@ public class IpSecService extends IIpSecService.Stub { final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); + final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES); void removeSpiRecord(int resourceId) { mSpiRecords.remove(resourceId); @@ -388,6 +397,10 @@ public class IpSecService extends IIpSecService.Stub { mTransformRecords.remove(resourceId); } + void removeTunnelInterfaceRecord(int resourceId) { + mTunnelInterfaceRecords.remove(resourceId); + } + void removeEncapSocketRecord(int resourceId) { mEncapSocketRecords.remove(resourceId); } @@ -721,6 +734,145 @@ public class IpSecService extends IIpSecService.Stub { } } + // These values have been reserved in ConnectivityService + @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00; + + @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400; + + private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); + private int mNextTunnelNetIdIndex = 0; + + /** + * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces + * + *

            This method should only be called from Binder threads. Do not call this from within the + * system server as it will crash the system on failure. + * + * @return an integer key within the netId range, if successful + * @throws IllegalStateException if unsuccessful (all netId are currently reserved) + */ + @VisibleForTesting + int reserveNetId() { + synchronized (mTunnelNetIds) { + for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) { + int index = mNextTunnelNetIdIndex; + int netId = index + TUN_INTF_NETID_START; + if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0; + if (!mTunnelNetIds.get(netId)) { + mTunnelNetIds.put(netId, true); + return netId; + } + } + } + throw new IllegalStateException("No free netIds to allocate"); + } + + @VisibleForTesting + void releaseNetId(int netId) { + synchronized (mTunnelNetIds) { + mTunnelNetIds.delete(netId); + } + } + + private final class TunnelInterfaceRecord extends OwnedResourceRecord { + private final String mInterfaceName; + private final Network mUnderlyingNetwork; + + // outer addresses + private final String mLocalAddress; + private final String mRemoteAddress; + + private final int mIkey; + private final int mOkey; + + TunnelInterfaceRecord( + int resourceId, + String interfaceName, + Network underlyingNetwork, + String localAddr, + String remoteAddr, + int ikey, + int okey) { + super(resourceId); + + mInterfaceName = interfaceName; + mUnderlyingNetwork = underlyingNetwork; + mLocalAddress = localAddr; + mRemoteAddress = remoteAddr; + mIkey = ikey; + mOkey = okey; + } + + /** always guarded by IpSecService#this */ + @Override + public void freeUnderlyingResources() { + // TODO: Add calls to netd + // Teardown VTI + // Delete global policies + + getResourceTracker().give(); + releaseNetId(mIkey); + releaseNetId(mOkey); + } + + public String getInterfaceName() { + return mInterfaceName; + } + + public Network getUnderlyingNetwork() { + return mUnderlyingNetwork; + } + + /** Returns the local, outer address for the tunnelInterface */ + public String getLocalAddress() { + return mLocalAddress; + } + + /** Returns the remote, outer address for the tunnelInterface */ + public String getRemoteAddress() { + return mRemoteAddress; + } + + public int getIkey() { + return mIkey; + } + + public int getOkey() { + return mOkey; + } + + @Override + protected ResourceTracker getResourceTracker() { + return getUserRecord().mTunnelQuotaTracker; + } + + @Override + public void invalidate() { + getUserRecord().removeTunnelInterfaceRecord(mResourceId); + } + + @Override + public String toString() { + return new StringBuilder() + .append("{super=") + .append(super.toString()) + .append(", mInterfaceName=") + .append(mInterfaceName) + .append(", mUnderlyingNetwork=") + .append(mUnderlyingNetwork) + .append(", mLocalAddress=") + .append(mLocalAddress) + .append(", mRemoteAddress=") + .append(mRemoteAddress) + .append(", mIkey=") + .append(mIkey) + .append(", mOkey=") + .append(mOkey) + .append("}") + .toString(); + } + } + /** * Tracks a UDP encap socket, and manages cleanup paths * @@ -1051,6 +1203,97 @@ public class IpSecService extends IIpSecService.Stub { releaseResource(userRecord.mEncapSocketRecords, resourceId); } + /** + * Create a tunnel interface for use in IPSec tunnel mode. The system server will cache the + * tunnel interface and a record of its owner so that it can and must be freed when no longer + * needed. + */ + @Override + public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( + String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) { + checkNotNull(binder, "Null Binder passed to createTunnelInterface"); + checkNotNull(underlyingNetwork, "No underlying network was specified"); + checkInetAddress(localAddr); + checkInetAddress(remoteAddr); + + // TODO: Check that underlying network exists, and IP addresses not assigned to a different + // network (b/72316676). + + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + if (!userRecord.mTunnelQuotaTracker.isAvailable()) { + return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); + } + + final int resourceId = mNextResourceId++; + final int ikey = reserveNetId(); + final int okey = reserveNetId(); + String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId); + + // TODO: Add calls to netd: + // Create VTI + // Add inbound/outbound global policies + // (use reqid = 0) + + userRecord.mTunnelInterfaceRecords.put( + resourceId, + new RefcountedResource( + new TunnelInterfaceRecord( + resourceId, + intfName, + underlyingNetwork, + localAddr, + remoteAddr, + ikey, + okey), + binder)); + return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); + } + + /** + * Adds a new local address to the tunnel interface. This allows packets to be sent and received + * from multiple local IP addresses over the same tunnel. + */ + @Override + public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + + // Get tunnelInterface record; if no such interface is found, will throw + // IllegalArgumentException + TunnelInterfaceRecord tunnelInterfaceInfo = + userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); + + // TODO: Add calls to netd: + // Add address to TunnelInterface + } + + /** + * Remove a new local address from the tunnel interface. After removal, the address will no + * longer be available to send from, or receive on. + */ + @Override + public synchronized void removeAddressFromTunnelInterface( + int tunnelResourceId, String localAddr) { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + + // Get tunnelInterface record; if no such interface is found, will throw + // IllegalArgumentException + TunnelInterfaceRecord tunnelInterfaceInfo = + userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); + + // TODO: Add calls to netd: + // Remove address from TunnelInterface + } + + /** + * Delete a TunnelInterface that has been been allocated by and registered with the system + * server + */ + @Override + public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException { + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); + } + @VisibleForTesting void validateAlgorithms(IpSecConfig config) throws IllegalArgumentException { IpSecAlgorithm auth = config.getAuthentication(); @@ -1249,7 +1492,12 @@ public class IpSecService extends IIpSecService.Stub { throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); } + // Get config and check that to-be-applied transform has the correct mode IpSecConfig c = info.getConfig(); + Preconditions.checkArgument( + c.getMode() == IpSecTransform.MODE_TRANSPORT, + "Transform mode was not Transport mode; cannot be applied to a socket"); + try { mSrvConfig .getNetdInstance() @@ -1287,6 +1535,42 @@ public class IpSecService extends IIpSecService.Stub { } } + /** + * Apply an active tunnel mode transform to a TunnelInterface, which will apply the IPsec + * security association as a correspondent policy to the provided interface + */ + @Override + public synchronized void applyTunnelModeTransform( + int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { + checkDirection(direction); + + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + + // Get transform record; if no transform is found, will throw IllegalArgumentException + TransformRecord transformInfo = + userRecord.mTransformRecords.getResourceOrThrow(transformResourceId); + + // Get tunnelInterface record; if no such interface is found, will throw + // IllegalArgumentException + TunnelInterfaceRecord tunnelInterfaceInfo = + userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); + + // Get config and check that to-be-applied transform has the correct mode + IpSecConfig c = transformInfo.getConfig(); + Preconditions.checkArgument( + c.getMode() == IpSecTransform.MODE_TUNNEL, + "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface"); + + int mark = + (direction == IpSecManager.DIRECTION_IN) + ? tunnelInterfaceInfo.getIkey() + : tunnelInterfaceInfo.getOkey(); + + // TODO: Add calls to netd: + // Update SA with tunnel mark (ikey or okey based on direction) + // If outbound, add SPI to policy + } + @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); From 779eedf6e0bb0ba18c50adc8a9b6edf37da03f1b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 19 Jan 2018 17:36:02 -0800 Subject: [PATCH 0473/1150] Add tunnel-mode calls to netd in IpSecService Adds calls to relevant netd methods in IpSecService, enabling Tunnel mode functionality. Bug: 63588681 Test: Compiles, passing CTS + unit tests Change-Id: I6deb68584cddb03f21bd76370d4ef69cadc1bf16 --- .../java/com/android/server/IpSecService.java | 220 +++++++++++++----- 1 file changed, 159 insertions(+), 61 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index c2adbfaeb7..fe4ac6d771 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -65,7 +65,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.BitSet; import java.util.List; import libcore.io.IoUtils; @@ -596,6 +595,10 @@ public class IpSecService extends IIpSecService.Stub { return mSpi; } + public EncapSocketRecord getSocketRecord() { + return mSocket; + } + /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { @@ -806,9 +809,29 @@ public class IpSecService extends IIpSecService.Stub { /** always guarded by IpSecService#this */ @Override public void freeUnderlyingResources() { - // TODO: Add calls to netd + // Calls to netd // Teardown VTI // Delete global policies + try { + mSrvConfig.getNetdInstance().removeVirtualTunnelInterface(mInterfaceName); + + for (int direction : DIRECTIONS) { + int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey; + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityPolicy( + 0, direction, mLocalAddress, mRemoteAddress, mark, 0xffffffff); + } + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (RemoteException e) { + Log.e( + TAG, + "Failed to delete VTI with interface name: " + + mInterfaceName + + " and id: " + + mResourceId); + } getResourceTracker().give(); releaseNetId(mIkey); @@ -1229,24 +1252,57 @@ public class IpSecService extends IIpSecService.Stub { final int okey = reserveNetId(); String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId); - // TODO: Add calls to netd: - // Create VTI - // Add inbound/outbound global policies - // (use reqid = 0) + try { + // Calls to netd: + // Create VTI + // Add inbound/outbound global policies + // (use reqid = 0) + mSrvConfig + .getNetdInstance() + .addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); - userRecord.mTunnelInterfaceRecords.put( - resourceId, - new RefcountedResource( - new TunnelInterfaceRecord( - resourceId, - intfName, - underlyingNetwork, - localAddr, - remoteAddr, - ikey, - okey), - binder)); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); + for (int direction : DIRECTIONS) { + int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey; + + mSrvConfig + .getNetdInstance() + .ipSecAddSecurityPolicy( + 0, // Use 0 for reqId + direction, + "", + "", + 0, + mark, + 0xffffffff); + } + + userRecord.mTunnelInterfaceRecords.put( + resourceId, + new RefcountedResource( + new TunnelInterfaceRecord( + resourceId, + intfName, + underlyingNetwork, + localAddr, + remoteAddr, + ikey, + okey), + binder)); + return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); + } catch (RemoteException e) { + // Release keys if we got an error. + releaseNetId(ikey); + releaseNetId(okey); + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + // FIXME: get the error code and throw is at an IOException from Errno Exception + } + + // If we make it to here, then something has gone wrong and we couldn't create a VTI. + // Release the keys that we reserved, and return an error status. + releaseNetId(ikey); + releaseNetId(okey); + return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } /** @@ -1381,12 +1437,50 @@ public class IpSecService extends IIpSecService.Stub { } } + private void createOrUpdateTransform( + IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) + throws RemoteException { + + int encapType = c.getEncapType(), encapLocalPort = 0, encapRemotePort = 0; + if (encapType != IpSecTransform.ENCAP_NONE) { + encapLocalPort = socketRecord.getPort(); + encapRemotePort = c.getEncapRemotePort(); + } + + IpSecAlgorithm auth = c.getAuthentication(); + IpSecAlgorithm crypt = c.getEncryption(); + IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); + + mSrvConfig + .getNetdInstance() + .ipSecAddSecurityAssociation( + resourceId, + c.getMode(), + c.getSourceAddress(), + c.getDestinationAddress(), + (c.getNetwork() != null) ? c.getNetwork().netId : 0, + spiRecord.getSpi(), + c.getMarkValue(), + c.getMarkMask(), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : new byte[] {}, + (auth != null) ? auth.getTruncationLengthBits() : 0, + (crypt != null) ? crypt.getName() : "", + (crypt != null) ? crypt.getKey() : new byte[] {}, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort); + } + /** - * Create a transport mode transform, which represent two security associations (one in each - * direction) in the kernel. The transform will be cached by the system server and must be freed - * when no longer needed. It is possible to free one, deleting the SA from underneath sockets - * that are using it, which will result in all of those sockets becoming unable to send or - * receive data. + * Create a IPsec transform, which represents a single security association in the kernel. The + * transform will be cached by the system server and must be freed when no longer needed. It is + * possible to free one, deleting the SA from underneath sockets that are using it, which will + * result in all of those sockets becoming unable to send or receive data. */ @Override public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder) @@ -1402,58 +1496,28 @@ public class IpSecService extends IIpSecService.Stub { return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } - int encapType, encapLocalPort = 0, encapRemotePort = 0; EncapSocketRecord socketRecord = null; - encapType = c.getEncapType(); - if (encapType != IpSecTransform.ENCAP_NONE) { + if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { RefcountedResource refcountedSocketRecord = userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow( c.getEncapSocketResourceId()); dependencies.add(refcountedSocketRecord); - socketRecord = refcountedSocketRecord.getResource(); - encapLocalPort = socketRecord.getPort(); - encapRemotePort = c.getEncapRemotePort(); } - IpSecAlgorithm auth = c.getAuthentication(); - IpSecAlgorithm crypt = c.getEncryption(); - IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); - RefcountedResource refcountedSpiRecord = userRecord.mSpiRecords.getRefcountedResourceOrThrow(c.getSpiResourceId()); dependencies.add(refcountedSpiRecord); SpiRecord spiRecord = refcountedSpiRecord.getResource(); try { - mSrvConfig - .getNetdInstance() - .ipSecAddSecurityAssociation( - resourceId, - c.getMode(), - c.getSourceAddress(), - c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().netId : 0, - spiRecord.getSpi(), - c.getMarkValue(), - c.getMarkMask(), - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort); + createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } - // Both SAs were created successfully, time to construct a record and lock it away + + // SA was created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( resourceId, new RefcountedResource( @@ -1561,14 +1625,48 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TUNNEL, "Transform mode was not Tunnel mode; cannot be applied to a tunnel interface"); + EncapSocketRecord socketRecord = null; + if (c.getEncapType() != IpSecTransform.ENCAP_NONE) { + socketRecord = + userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); + } + SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId()); + int mark = (direction == IpSecManager.DIRECTION_IN) ? tunnelInterfaceInfo.getIkey() : tunnelInterfaceInfo.getOkey(); - // TODO: Add calls to netd: - // Update SA with tunnel mark (ikey or okey based on direction) - // If outbound, add SPI to policy + try { + c.setMarkValue(mark); + c.setMarkMask(0xffffffff); + + if (direction == IpSecManager.DIRECTION_OUT) { + // Set output mark via underlying network (output only) + c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); + + // If outbound, also add SPI to the policy. + mSrvConfig + .getNetdInstance() + .ipSecUpdateSecurityPolicy( + 0, // Use 0 for reqId + direction, + "", + "", + transformInfo.getSpiRecord().getSpi(), + mark, + 0xffffffff); + } + + // Update SA with tunnel mark (ikey or okey based on direction) + createOrUpdateTransform(c, transformResourceId, spiRecord, socketRecord); + } catch (ServiceSpecificException e) { + if (e.errorCode == EINVAL) { + throw new IllegalArgumentException(e.toString()); + } else { + throw e; + } + } } @Override From dbfdb4a16086f6d21080519ef5a1c6008d60b92d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 6 Dec 2017 19:12:28 -0800 Subject: [PATCH 0474/1150] Move Keepalive out of IpSecTransform.Builder The lifecycle of Keepalive offloading is, unfortunately different from that of an IpSecTransform. Because starting a keepalive is fundamentally asynchronous, and isn't valid until after a transform exists, it will now be a separate optional procedure that may succeed or fail. It remains linked with a Transform by the need for a Transform to exist in order to initiate a Keepalive. Bug: 38350389 Test: compilation Change-Id: Ia76fccee41f86d694dff436043293d0c0762c041 --- core/java/android/net/IpSecTransform.java | 155 ++++++++++++++-------- 1 file changed, 102 insertions(+), 53 deletions(-) diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 37e2c4fbf0..9ccdbe2b1b 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -17,11 +17,14 @@ package android.net; import static android.net.IpSecManager.INVALID_RESOURCE_ID; +import static com.android.internal.util.Preconditions.checkNotNull; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; +import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -128,13 +131,6 @@ public final class IpSecTransform implements AutoCloseable { int status = result.status; checkResultStatus(status); mResourceId = result.resourceId; - - /* Keepalive will silently fail if not needed by the config; but, if needed and - * it fails to start, we need to bail because a transform will not be reliable - * to use if keepalive is expected to offload and fails. - */ - // FIXME: if keepalive fails, we need to fail spectacularly - startKeepalive(mContext); Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); } catch (RemoteException e) { @@ -164,13 +160,9 @@ public final class IpSecTransform implements AutoCloseable { return; } try { - /* Order matters here because the keepalive is best-effort but could fail in some - * horrible way to be removed if the wifi (or cell) subsystem has crashed, and we - * still want to clear out the transform. - */ IIpSecService svc = getIpSecService(); svc.deleteTransform(mResourceId); - stopKeepalive(); + stopNattKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } finally { @@ -198,42 +190,35 @@ public final class IpSecTransform implements AutoCloseable { private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); private ConnectivityManager.PacketKeepalive mKeepalive; - private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE; - private Object mKeepaliveSyncLock = new Object(); - private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback = + private Handler mCallbackHandler; + private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback = new ConnectivityManager.PacketKeepaliveCallback() { @Override public void onStarted() { - synchronized (mKeepaliveSyncLock) { - mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS; - mKeepaliveSyncLock.notifyAll(); + synchronized (this) { + mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted()); } } @Override public void onStopped() { - synchronized (mKeepaliveSyncLock) { - mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE; - mKeepaliveSyncLock.notifyAll(); + synchronized (this) { + mKeepalive = null; + mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped()); } } @Override public void onError(int error) { - synchronized (mKeepaliveSyncLock) { - mKeepaliveStatus = error; - mKeepaliveSyncLock.notifyAll(); + synchronized (this) { + mKeepalive = null; + mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error)); } } }; - /* Package */ - void startKeepalive(Context c) { - if (mConfig.getNattKeepaliveInterval() != 0) { - Log.wtf(TAG, "Keepalive not yet supported."); - } - } + private NattKeepaliveCallback mUserKeepaliveCallback; /** @hide */ @VisibleForTesting @@ -241,9 +226,93 @@ public final class IpSecTransform implements AutoCloseable { return mResourceId; } - /* Package */ - void stopKeepalive() { - return; + /** + * A callback class to provide status information regarding a NAT-T keepalive session + * + *

            Use this callback to receive status information regarding a NAT-T keepalive session + * by registering it when calling {@link #startNattKeepalive}. + * + * @hide + */ + @SystemApi + public static class NattKeepaliveCallback { + /** The specified {@code Network} is not connected. */ + public static final int ERROR_INVALID_NETWORK = 1; + /** The hardware does not support this request. */ + public static final int ERROR_HARDWARE_UNSUPPORTED = 2; + /** The hardware returned an error. */ + public static final int ERROR_HARDWARE_ERROR = 3; + + /** The requested keepalive was successfully started. */ + public void onStarted() {} + /** The keepalive was successfully stopped. */ + public void onStopped() {} + /** An error occurred. */ + public void onError(int error) {} + } + + /** + * Start a NAT-T keepalive session for the current transform. + * + * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides + * a power efficient mechanism of sending NAT-T packets at a specified interval. + * + * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status + * information about the requested NAT-T keepalive session. + * @param intervalSeconds the interval between NAT-T keepalives being sent. The + * the allowed range is between 20 and 3600 seconds. + * @param handler a handler on which to post callbacks when received. + * + * @hide + */ + @SystemApi + public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, + int intervalSeconds, @NonNull Handler handler) throws IOException { + checkNotNull(userCallback); + if (intervalSeconds < 20 || intervalSeconds > 3600) { + throw new IllegalArgumentException("Invalid NAT-T keepalive interval"); + } + checkNotNull(handler); + if (mResourceId == INVALID_RESOURCE_ID) { + throw new IllegalStateException( + "Packet keepalive cannot be started for an inactive transform"); + } + + synchronized (mKeepaliveCallback) { + if (mKeepaliveCallback != null) { + throw new IllegalStateException("Keepalive already active"); + } + + mUserKeepaliveCallback = userCallback; + ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + mKeepalive = cm.startNattKeepalive( + mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback, + NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()), + 4500, // FIXME urgently, we need to get the port number from the Encap socket + NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress())); + mCallbackHandler = handler; + } + } + + /** + * Stop an ongoing NAT-T keepalive session. + * + * Calling this API will request that an ongoing NAT-T keepalive session be terminated. + * If this API is not called when a Transform is closed, the underlying NAT-T session will + * be terminated automatically. + * + * @hide + */ + @SystemApi + public void stopNattKeepalive() { + synchronized (mKeepaliveCallback) { + if (mKeepalive == null) { + Log.e(TAG, "No active keepalive to stop"); + return; + } + mKeepalive.stop(); + } } /** This class is used to build {@link IpSecTransform} objects. */ @@ -323,26 +392,6 @@ public final class IpSecTransform implements AutoCloseable { return this; } - // TODO: Decrease the minimum keepalive to maybe 10? - // TODO: Probably a better exception to throw for NATTKeepalive failure - // TODO: Specify the needed NATT keepalive permission. - /** - * Set NAT-T keepalives to be sent with a given interval. - * - *

            This will set power-efficient keepalive packets to be sent by the system. If NAT-T - * keepalive is requested but cannot be activated, then creation of an {@link - * IpSecTransform} will fail when calling the build method. - * - * @param intervalSeconds the maximum number of seconds between keepalive packets. Must be - * between 20s and 3600s. - * @hide - */ - @SystemApi - public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) { - mConfig.setNattKeepaliveInterval(intervalSeconds); - return this; - } - /** * Build a transport mode {@link IpSecTransform}. * From 51b4917dd30455cb4fe3d9bd5a302b29fb5ab0a4 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Tue, 31 Oct 2017 15:34:16 -0700 Subject: [PATCH 0475/1150] Enable multiple active Ethernet interfaces - add Ethernet interface configurations to config.xml; no vendors can specify network capabilities (in particular they can mark network as restricted which make sense for embedded applications + static IP configuration) - extend EthernetManager to support multiple interfaces, use interface name as an identificator - extend IpConfigStore to store IP configuration based on string identifier (e.g. ethernet name) Test: runtest -x frameworks/base/services/tests/servicestests/ -c com.android.server.net.IpConfigStoreTest Change-Id: Ic1e70003f2380ca8edb4469d6b34e27c5e8cf059 --- core/java/android/net/EthernetManager.java | 49 ++++-- core/java/android/net/IEthernetManager.aidl | 7 +- .../android/net/IEthernetServiceListener.aidl | 2 +- .../com/android/server/net/IpConfigStore.java | 100 ++++++++++--- .../android/server/net/IpConfigStoreTest.java | 140 ++++++++++++++++++ 5 files changed, 259 insertions(+), 39 deletions(-) create mode 100644 services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 31a30968cb..ecccda588a 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -18,9 +18,6 @@ package android.net; import android.annotation.SystemService; import android.content.Context; -import android.net.IEthernetManager; -import android.net.IEthernetServiceListener; -import android.net.IpConfiguration; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -45,18 +42,18 @@ public class EthernetManager { if (msg.what == MSG_AVAILABILITY_CHANGED) { boolean isAvailable = (msg.arg1 == 1); for (Listener listener : mListeners) { - listener.onAvailabilityChanged(isAvailable); + listener.onAvailabilityChanged((String) msg.obj, isAvailable); } } } }; - private final ArrayList mListeners = new ArrayList(); + private final ArrayList mListeners = new ArrayList<>(); private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override - public void onAvailabilityChanged(boolean isAvailable) { + public void onAvailabilityChanged(String iface, boolean isAvailable) { mHandler.obtainMessage( - MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, null).sendToTarget(); + MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, iface).sendToTarget(); } }; @@ -66,9 +63,10 @@ public class EthernetManager { public interface Listener { /** * Called when Ethernet port's availability is changed. - * @param isAvailable {@code true} if one or more Ethernet port exists. + * @param iface Ethernet interface name + * @param isAvailable {@code true} if Ethernet port exists. */ - public void onAvailabilityChanged(boolean isAvailable); + void onAvailabilityChanged(String iface, boolean isAvailable); } /** @@ -86,9 +84,9 @@ public class EthernetManager { * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ - public IpConfiguration getConfiguration() { + public IpConfiguration getConfiguration(String iface) { try { - return mService.getConfiguration(); + return mService.getConfiguration(iface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -97,21 +95,29 @@ public class EthernetManager { /** * Set Ethernet configuration. */ - public void setConfiguration(IpConfiguration config) { + public void setConfiguration(String iface, IpConfiguration config) { try { - mService.setConfiguration(config); + mService.setConfiguration(iface, config); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Indicates whether the system currently has one or more - * Ethernet interfaces. + * Indicates whether the system currently has one or more Ethernet interfaces. */ public boolean isAvailable() { + return getAvailableInterfaces().length > 0; + } + + /** + * Indicates whether the system has given interface. + * + * @param iface Ethernet interface name + */ + public boolean isAvailable(String iface) { try { - return mService.isAvailable(); + return mService.isAvailable(iface); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -136,6 +142,17 @@ public class EthernetManager { } } + /** + * Returns an array of available Ethernet interface names. + */ + public String[] getAvailableInterfaces() { + try { + return mService.getAvailableInterfaces(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } + /** * Removes a listener. * @param listener A {@link Listener} to remove. diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 7a92eb955a..94960b51d3 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -26,9 +26,10 @@ import android.net.IEthernetServiceListener; /** {@hide} */ interface IEthernetManager { - IpConfiguration getConfiguration(); - void setConfiguration(in IpConfiguration config); - boolean isAvailable(); + String[] getAvailableInterfaces(); + IpConfiguration getConfiguration(String iface); + void setConfiguration(String iface, in IpConfiguration config); + boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); } diff --git a/core/java/android/net/IEthernetServiceListener.aidl b/core/java/android/net/IEthernetServiceListener.aidl index 356690e8f7..782fa19d9d 100644 --- a/core/java/android/net/IEthernetServiceListener.aidl +++ b/core/java/android/net/IEthernetServiceListener.aidl @@ -19,5 +19,5 @@ package android.net; /** @hide */ oneway interface IEthernetServiceListener { - void onAvailabilityChanged(boolean isAvailable); + void onAvailabilityChanged(String iface, boolean isAvailable); } diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 4d56468f2f..e3e02e32ad 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -24,11 +24,11 @@ import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; +import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.net.DelayedDiskWrite; import java.io.BufferedInputStream; import java.io.DataInputStream; @@ -38,8 +38,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.net.InetAddress; import java.net.Inet4Address; +import java.net.InetAddress; public class IpConfigStore { private static final String TAG = "IpConfigStore"; @@ -60,7 +60,7 @@ public class IpConfigStore { protected static final String EXCLUSION_LIST_KEY = "exclusionList"; protected static final String EOS = "eos"; - protected static final int IPCONFIG_FILE_VERSION = 2; + protected static final int IPCONFIG_FILE_VERSION = 3; public IpConfigStore(DelayedDiskWrite writer) { mWriter = writer; @@ -70,9 +70,14 @@ public class IpConfigStore { this(new DelayedDiskWrite()); } + private static boolean writeConfig(DataOutputStream out, String configKey, + IpConfiguration config) throws IOException { + return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); + } + @VisibleForTesting - public static boolean writeConfig(DataOutputStream out, int configKey, - IpConfiguration config) throws IOException { + public static boolean writeConfig(DataOutputStream out, String configKey, + IpConfiguration config, int version) throws IOException { boolean written = false; try { @@ -153,7 +158,11 @@ public class IpConfigStore { if (written) { out.writeUTF(ID_KEY); - out.writeInt(configKey); + if (version < 3) { + out.writeInt(Integer.valueOf(configKey)); + } else { + out.writeUTF(configKey); + } } } catch (NullPointerException e) { loge("Failure in writing " + config + e); @@ -163,18 +172,47 @@ public class IpConfigStore { return written; } - public void writeIpAndProxyConfigurations(String filePath, + /** + * @Deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. + * New method uses string as network identifier which could be interface name or MAC address or + * other token. + */ + @Deprecated + public void writeIpAndProxyConfigurationsToFile(String filePath, final SparseArray networks) { - mWriter.write(filePath, new DelayedDiskWrite.Writer() { - public void onWriteCalled(DataOutputStream out) throws IOException{ - out.writeInt(IPCONFIG_FILE_VERSION); - for(int i = 0; i < networks.size(); i++) { - writeConfig(out, networks.keyAt(i), networks.valueAt(i)); - } + mWriter.write(filePath, out -> { + out.writeInt(IPCONFIG_FILE_VERSION); + for(int i = 0; i < networks.size(); i++) { + writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); } }); } + public void writeIpConfigurations(String filePath, + ArrayMap networks) { + mWriter.write(filePath, out -> { + out.writeInt(IPCONFIG_FILE_VERSION); + for(int i = 0; i < networks.size(); i++) { + writeConfig(out, networks.keyAt(i), networks.valueAt(i)); + } + }); + } + + public static ArrayMap readIpConfigurations(String filePath) { + BufferedInputStream bufferedInputStream; + try { + bufferedInputStream = new BufferedInputStream(new FileInputStream(filePath)); + } catch (FileNotFoundException e) { + // Return an empty array here because callers expect an empty array when the file is + // not present. + loge("Error opening configuration file: " + e); + return new ArrayMap<>(0); + } + return readIpConfigurations(bufferedInputStream); + } + + /** @Deprecated use {@link #readIpConfigurations(String)} */ + @Deprecated public static SparseArray readIpAndProxyConfigurations(String filePath) { BufferedInputStream bufferedInputStream; try { @@ -188,21 +226,40 @@ public class IpConfigStore { return readIpAndProxyConfigurations(bufferedInputStream); } + /** @Deprecated use {@link #readIpConfigurations(InputStream)} */ + @Deprecated public static SparseArray readIpAndProxyConfigurations( InputStream inputStream) { - SparseArray networks = new SparseArray(); + ArrayMap networks = readIpConfigurations(inputStream); + if (networks == null) { + return null; + } + + SparseArray networksById = new SparseArray<>(); + for (int i = 0; i < networks.size(); i++) { + int id = Integer.valueOf(networks.keyAt(i)); + networksById.put(id, networks.valueAt(i)); + } + + return networksById; + } + + /** Returns a map of network identity token and {@link IpConfiguration}. */ + public static ArrayMap readIpConfigurations( + InputStream inputStream) { + ArrayMap networks = new ArrayMap<>(); DataInputStream in = null; try { in = new DataInputStream(inputStream); int version = in.readInt(); - if (version != 2 && version != 1) { + if (version != 3 && version != 2 && version != 1) { loge("Bad version on IP configuration file, ignore read"); return null; } while (true) { - int id = -1; + String uniqueToken = null; // Default is DHCP with no proxy IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; @@ -217,7 +274,12 @@ public class IpConfigStore { key = in.readUTF(); try { if (key.equals(ID_KEY)) { - id = in.readInt(); + if (version < 3) { + int id = in.readInt(); + uniqueToken = String.valueOf(id); + } else { + uniqueToken = in.readUTF(); + } } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { @@ -280,9 +342,9 @@ public class IpConfigStore { } } while (true); - if (id != -1) { + if (uniqueToken != null) { IpConfiguration config = new IpConfiguration(); - networks.put(id, config); + networks.put(uniqueToken, config); switch (ipAssignment) { case STATIC: diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java new file mode 100644 index 0000000000..9f4b754621 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; + +import android.net.IpConfiguration; +import android.net.IpConfiguration.IpAssignment; +import android.net.IpConfiguration.ProxySettings; +import android.net.LinkAddress; +import android.net.NetworkUtils; +import android.net.ProxyInfo; +import android.net.StaticIpConfiguration; +import android.support.test.runner.AndroidJUnit4; +import android.util.ArrayMap; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Unit tests for {@link IpConfigStore} + */ +@RunWith(AndroidJUnit4.class) +public class IpConfigStoreTest { + + @Test + public void backwardCompatibility2to3() throws IOException { + final int KEY_CONFIG = 17; + ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + DataOutputStream outputStream = new DataOutputStream(byteStream); + + IpConfiguration expectedConfig = new IpConfiguration(IpAssignment.DHCP, + ProxySettings.NONE, null, null); + + // Emulate writing to old format. + writeDhcpConfigV2(outputStream, KEY_CONFIG, expectedConfig); + + InputStream in = new ByteArrayInputStream(byteStream.toByteArray()); + ArrayMap configurations = IpConfigStore.readIpConfigurations(in); + + assertNotNull(configurations); + assertEquals(1, configurations.size()); + IpConfiguration actualConfig = configurations.get(String.valueOf(KEY_CONFIG)); + assertNotNull(actualConfig); + assertEquals(expectedConfig, actualConfig); + } + + @Test + public void staticIpMultiNetworks() throws Exception { + final String IFACE_1 = "eth0"; + final String IFACE_2 = "eth1"; + final String IP_ADDR_1 = "192.168.1.10/24"; + final String IP_ADDR_2 = "192.168.1.20/24"; + final String DNS_IP_ADDR_1 = "1.2.3.4"; + final String DNS_IP_ADDR_2 = "5.6.7.8"; + + StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + staticIpConfiguration.ipAddress = new LinkAddress(IP_ADDR_1); + staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_1)); + staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_2)); + + ProxyInfo proxyInfo = new ProxyInfo("10.10.10.10", 88, "host1,host2"); + + IpConfiguration expectedConfig1 = new IpConfiguration(IpAssignment.STATIC, + ProxySettings.STATIC, staticIpConfiguration, proxyInfo); + IpConfiguration expectedConfig2 = new IpConfiguration(expectedConfig1); + expectedConfig2.getStaticIpConfiguration().ipAddress = new LinkAddress(IP_ADDR_2); + + ArrayMap expectedNetworks = new ArrayMap<>(); + expectedNetworks.put(IFACE_1, expectedConfig1); + expectedNetworks.put(IFACE_2, expectedConfig2); + + MockedDelayedDiskWrite writer = new MockedDelayedDiskWrite(); + IpConfigStore store = new IpConfigStore(writer); + store.writeIpConfigurations("file/path/not/used/", expectedNetworks); + + InputStream in = new ByteArrayInputStream(writer.byteStream.toByteArray()); + ArrayMap actualNetworks = IpConfigStore.readIpConfigurations(in); + assertNotNull(actualNetworks); + assertEquals(2, actualNetworks.size()); + assertEquals(expectedNetworks.get(IFACE_1), actualNetworks.get(IFACE_1)); + assertEquals(expectedNetworks.get(IFACE_2), actualNetworks.get(IFACE_2)); + } + + // This is simplified snapshot of code that was used to store values in V2 format (key as int). + private static void writeDhcpConfigV2(DataOutputStream out, int configKey, + IpConfiguration config) throws IOException { + out.writeInt(2); // VERSION 2 + switch (config.ipAssignment) { + case DHCP: + out.writeUTF("ipAssignment"); + out.writeUTF(config.ipAssignment.toString()); + break; + default: + fail("Not supported in test environment"); + } + + out.writeUTF("id"); + out.writeInt(configKey); + out.writeUTF("eos"); + } + + /** Synchronously writes into given byte steam */ + private static class MockedDelayedDiskWrite extends DelayedDiskWrite { + final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + + @Override + public void write(String filePath, Writer w) { + DataOutputStream outputStream = new DataOutputStream(byteStream); + + try { + w.onWriteCalled(outputStream); + } catch (IOException e) { + fail(); + } + } + } +} From 7f880c99407d4233e4e32328d89e40e676832164 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 25 Jan 2018 11:43:52 -0800 Subject: [PATCH 0476/1150] Return non-negetive value in getMobileStats method The current implementation of getMobileRxBytes and all the similiar method adds up the return values for multiple calls to getRxBytes so if all of them return UNSUPPORTED for any reason, getMobileRxBytes() would return a value such as -3. This behavior is not compliance with the cts TrafficStatsTest which always assume getMobileRxBytes to return a non-negetive value. The method now will check tha stats get from getRxBytes method and add them up only if the stats is valid. Bug: 72473294 Test: run cts -m CtsNetTestCases -t android.net.cts.TrafficStatsTest Change-Id: I656970ebc8f6506cf17c4353ad46c0178bb65cfd --- core/java/android/net/TrafficStats.java | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 196a3bc9c8..fa4624ef56 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -433,6 +433,10 @@ public class TrafficStats { } } + private static long addIfSupported(long stat) { + return (stat == UNSUPPORTED) ? 0 : stat; + } + /** * Return number of packets transmitted across mobile networks since device * boot. Counts packets across all mobile network interfaces, and always @@ -445,7 +449,7 @@ public class TrafficStats { public static long getMobileTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { - total += getTxPackets(iface); + total += addIfSupported(getTxPackets(iface)); } return total; } @@ -462,7 +466,7 @@ public class TrafficStats { public static long getMobileRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { - total += getRxPackets(iface); + total += addIfSupported(getRxPackets(iface)); } return total; } @@ -479,7 +483,7 @@ public class TrafficStats { public static long getMobileTxBytes() { long total = 0; for (String iface : getMobileIfaces()) { - total += getTxBytes(iface); + total += addIfSupported(getTxBytes(iface)); } return total; } @@ -496,7 +500,7 @@ public class TrafficStats { public static long getMobileRxBytes() { long total = 0; for (String iface : getMobileIfaces()) { - total += getRxBytes(iface); + total += addIfSupported(getRxBytes(iface)); } return total; } @@ -511,9 +515,7 @@ public class TrafficStats { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - if (stat != UNSUPPORTED) { - total += stat; - } + total += addIfSupported(stat); } return total; } @@ -528,9 +530,7 @@ public class TrafficStats { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } - if (stat != UNSUPPORTED) { - total += stat; - } + total += addIfSupported(stat); } return total; } From 72a82a752a4b5f25bfc75057409e1ee01ae44b02 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 24 Jan 2018 15:31:39 -0800 Subject: [PATCH 0477/1150] Fix minor bugs with tunnel mode implementation This change makes sure tunnel mode transforms are properly activated upon construction, and corrects bugs with how policy selectors were being generated for tunnel mode policies. Specifically, the source/destination could not be empty strings, even for cases where an empty selector was desired. Bug: 72457770 Test: GTS tests run Change-Id: I9a9f64c34b07883a02a5c996614f958486d214fc --- core/java/android/net/IpSecTransform.java | 2 +- .../java/com/android/server/IpSecService.java | 57 +++++++++++-------- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 9ccdbe2b1b..0829b4a3e9 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -462,7 +462,7 @@ public final class IpSecTransform implements AutoCloseable { mConfig.setMode(MODE_TUNNEL); mConfig.setSourceAddress(sourceAddress.getHostAddress()); mConfig.setSpiResourceId(spi.getResourceId()); - return new IpSecTransform(mContext, mConfig); + return new IpSecTransform(mContext, mConfig).activate(); } /** diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index fe4ac6d771..a07a982abc 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -87,6 +87,7 @@ public class IpSecService extends IIpSecService.Stub { private static final String NETD_SERVICE_NAME = "netd"; private static final int[] DIRECTIONS = new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN}; + private static final String[] WILDCARD_ADDRESSES = new String[]{"0.0.0.0", "::"}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int MAX_PORT_BIND_ATTEMPTS = 10; @@ -413,12 +414,16 @@ public class IpSecService extends IIpSecService.Stub { .append(mTransformQuotaTracker) .append(", mSocketQuotaTracker=") .append(mSocketQuotaTracker) + .append(", mTunnelQuotaTracker=") + .append(mTunnelQuotaTracker) .append(", mSpiRecords=") .append(mSpiRecords) .append(", mTransformRecords=") .append(mTransformRecords) .append(", mEncapSocketRecords=") .append(mEncapSocketRecords) + .append(", mTunnelInterfaceRecords=") + .append(mTunnelInterfaceRecords) .append("}") .toString(); } @@ -815,12 +820,14 @@ public class IpSecService extends IIpSecService.Stub { try { mSrvConfig.getNetdInstance().removeVirtualTunnelInterface(mInterfaceName); - for (int direction : DIRECTIONS) { - int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey; - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityPolicy( - 0, direction, mLocalAddress, mRemoteAddress, mark, 0xffffffff); + for(String wildcardAddr : WILDCARD_ADDRESSES) { + for (int direction : DIRECTIONS) { + int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey; + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityPolicy( + 0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff); + } } } catch (ServiceSpecificException e) { // FIXME: get the error code and throw is at an IOException from Errno Exception @@ -1261,19 +1268,21 @@ public class IpSecService extends IIpSecService.Stub { .getNetdInstance() .addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); - for (int direction : DIRECTIONS) { - int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey; + for(String wildcardAddr : WILDCARD_ADDRESSES) { + for (int direction : DIRECTIONS) { + int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey; - mSrvConfig - .getNetdInstance() - .ipSecAddSecurityPolicy( + mSrvConfig + .getNetdInstance() + .ipSecAddSecurityPolicy( 0, // Use 0 for reqId direction, - "", - "", + wildcardAddr, + wildcardAddr, 0, mark, 0xffffffff); + } } userRecord.mTunnelInterfaceRecords.put( @@ -1646,16 +1655,18 @@ public class IpSecService extends IIpSecService.Stub { c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); // If outbound, also add SPI to the policy. - mSrvConfig - .getNetdInstance() - .ipSecUpdateSecurityPolicy( - 0, // Use 0 for reqId - direction, - "", - "", - transformInfo.getSpiRecord().getSpi(), - mark, - 0xffffffff); + for(String wildcardAddr : WILDCARD_ADDRESSES) { + mSrvConfig + .getNetdInstance() + .ipSecUpdateSecurityPolicy( + 0, // Use 0 for reqId + direction, + wildcardAddr, + wildcardAddr, + transformInfo.getSpiRecord().getSpi(), + mark, + 0xffffffff); + } } // Update SA with tunnel mark (ikey or okey based on direction) From 14b84ea14ac4639a1b51111b8fcaedbd7b1e3146 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 5 Feb 2018 17:19:22 -0800 Subject: [PATCH 0478/1150] Frameworks: Annotate trivial @GuardedBy in services/core Add @GuardedBy for simple functions that require a single lock and are named XYZLocked. Derived by errorprone. Bug: 73000847 Test: m Test: m javac-check-framework RUN_ERROR_PRONE=true Change-Id: I6993325b11c71a4ec27c21935fb54a954d95455f --- .../com/android/server/net/NetworkStatsService.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index bfc150e1a9..76c4db1340 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -405,6 +405,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mNonMonotonicObserver, dropBox, prefix, config.bucketDuration, includeTags); } + @GuardedBy("mStatsLock") private void shutdownLocked() { mContext.unregisterReceiver(mTetherReceiver); mContext.unregisterReceiver(mPollReceiver); @@ -431,6 +432,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemReady = false; } + @GuardedBy("mStatsLock") private void maybeUpgradeLegacyStatsLocked() { File file; try { @@ -909,6 +911,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * reflect current {@link #mPersistThreshold} value. Always defers to * {@link Global} values when defined. */ + @GuardedBy("mStatsLock") private void updatePersistThresholdsLocked() { mDevRecorder.setPersistThreshold(mSettings.getDevPersistBytes(mPersistThreshold)); mXtRecorder.setPersistThreshold(mSettings.getXtPersistBytes(mPersistThreshold)); @@ -1029,6 +1032,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * are active on a single {@code iface}, they are combined under a single * {@link NetworkIdentitySet}. */ + @GuardedBy("mStatsLock") private void updateIfacesLocked(Network[] defaultNetworks) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1128,6 +1132,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return ident; } + @GuardedBy("mStatsLock") private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. @@ -1163,6 +1168,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Bootstrap initial stats snapshot, usually during {@link #systemReady()} * so we have baseline values without double-counting. */ + @GuardedBy("mStatsLock") private void bootstrapStatsLocked() { final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() : System.currentTimeMillis(); @@ -1197,6 +1203,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Periodic poll operation, reading current statistics and recording into * {@link NetworkStatsHistory}. */ + @GuardedBy("mStatsLock") private void performPollLocked(int flags) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); @@ -1258,6 +1265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Sample recent statistics summary into {@link EventLog}. */ + @GuardedBy("mStatsLock") private void performSampleLocked() { // TODO: migrate trustedtime fixes to separate binary log events final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; @@ -1295,6 +1303,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Clean up {@link #mUidRecorder} after UID is removed. */ + @GuardedBy("mStatsLock") private void removeUidsLocked(int... uids) { if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); @@ -1313,6 +1322,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Clean up {@link #mUidRecorder} after user is removed. */ + @GuardedBy("mStatsLock") private void removeUserLocked(int userId) { if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId); @@ -1434,6 +1444,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + @GuardedBy("mStatsLock") private void dumpProtoLocked(FileDescriptor fd) { final ProtoOutputStream proto = new ProtoOutputStream(fd); From 1b33ea09492c0606a2ee56d41fecd2acb7ee6ff0 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Fri, 2 Feb 2018 18:34:25 -0800 Subject: [PATCH 0479/1150] Require NETWORK_STACK Permission for IpSec Tunnel Mode At least until further permissions are agreed upon, the NETWORK_STACK permission is sufficient to ensure that access to the tunnel mode APIs is secure, and this permission will always be a sufficient condition. Thus, adding NETWORK_STACK. Bug: 66955045 Test: compilation Change-Id: I2dc36896a52d2e71fad55041507d68ca91191ffc --- core/java/android/net/IpSecManager.java | 3 +++ core/java/android/net/IpSecTransform.java | 10 ++++++++++ .../core/java/com/android/server/IpSecService.java | 8 ++++++++ 3 files changed, 21 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 24a078fccc..b60984771a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,6 +19,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -761,6 +762,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { @@ -780,6 +782,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, IpSecTransform transform) throws IOException { try { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 0829b4a3e9..38759a9183 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; @@ -266,6 +267,10 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD + }) public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, int intervalSeconds, @NonNull Handler handler) throws IOException { checkNotNull(userCallback); @@ -305,6 +310,10 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD + }) public void stopNattKeepalive() { synchronized (mKeepaliveCallback) { if (mKeepalive == null) { @@ -449,6 +458,7 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a07a982abc..45a4dfb91b 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1438,7 +1438,9 @@ public class IpSecService extends IIpSecService.Stub { switch (config.getMode()) { case IpSecTransform.MODE_TRANSPORT: + break; case IpSecTransform.MODE_TUNNEL: + enforceNetworkStackPermission(); break; default: throw new IllegalArgumentException( @@ -1446,6 +1448,11 @@ public class IpSecService extends IIpSecService.Stub { } } + private void enforceNetworkStackPermission() { + mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, + "IpSecService"); + } + private void createOrUpdateTransform( IpSecConfig c, int resourceId, SpiRecord spiRecord, EncapSocketRecord socketRecord) throws RemoteException { @@ -1615,6 +1622,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTunnelModeTransform( int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { + enforceNetworkStackPermission(); checkDirection(direction); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From 3a637c7a5572febe683de4d90578d684202b9905 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 9 Feb 2018 10:06:59 -0700 Subject: [PATCH 0480/1150] Shore up dividing by zero protections. We're already trying to protect against zero elsewhere in this file, but we've seen evidence of it still happening, so add last-ditch protections. Test: builds, boots Bug: 73060623 Change-Id: I0549ed08f906521a8dbd9ff6162f80fa9b388434 --- .../core/java/com/android/server/net/NetworkStatsCollection.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 961a451778..3cc4d83267 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -187,6 +187,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ @VisibleForTesting public static long multiplySafe(long value, long num, long den) { + if (den == 0) den = 1; long x = value; long y = num; From 1df43871a02aa5c7ff7361435909548da17e9c10 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 9 Feb 2018 10:06:59 -0700 Subject: [PATCH 0481/1150] Shore up dividing by zero protections. We're already trying to protect against zero elsewhere in this file, but we've seen evidence of it still happening, so add last-ditch protections. Test: builds, boots Bug: 73060623 Change-Id: I0549ed08f906521a8dbd9ff6162f80fa9b388434 (cherry picked from commit a7be8da9adefaf6d55f7c90b95d0c6f9e66fca63) --- .../core/java/com/android/server/net/NetworkStatsCollection.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 961a451778..3cc4d83267 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -187,6 +187,7 @@ public class NetworkStatsCollection implements FileRotator.Reader { */ @VisibleForTesting public static long multiplySafe(long value, long num, long den) { + if (den == 0) den = 1; long x = value; long y = num; From 3899300c2978fc8c609fe30e7f0666dc010c455c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 6 Feb 2018 20:43:21 -0800 Subject: [PATCH 0482/1150] Copy IpSecConfig when IpSecTransforms are created This change prevents IpSecTransforms from being inadvertently modified by changes to the IpSecConfig. Specifically, once the transform is created, it takes a copy of the config, rather than a reference. Bug: 69385347 Test: New tests added, and all test passing Change-Id: I89b8660c175ca20aa70352dcda893434ff7fd42b --- core/java/android/net/IpSecConfig.java | 19 +++++++++++++++++++ core/java/android/net/IpSecTransform.java | 18 ++++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 6a262e2c87..8599f47c62 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -218,6 +218,25 @@ public final class IpSecConfig implements Parcelable { @VisibleForTesting public IpSecConfig() {} + /** Copy constructor */ + @VisibleForTesting + public IpSecConfig(IpSecConfig c) { + mMode = c.mMode; + mSourceAddress = c.mSourceAddress; + mDestinationAddress = c.mDestinationAddress; + mNetwork = c.mNetwork; + mSpiResourceId = c.mSpiResourceId; + mEncryption = c.mEncryption; + mAuthentication = c.mAuthentication; + mAuthenticatedEncryption = c.mAuthenticatedEncryption; + mEncapType = c.mEncapType; + mEncapSocketResourceId = c.mEncapSocketResourceId; + mEncapRemotePort = c.mEncapRemotePort; + mNattKeepaliveInterval = c.mNattKeepaliveInterval; + mMarkValue = c.mMarkValue; + mMarkMask = c.mMarkMask; + } + private IpSecConfig(Parcel in) { mMode = in.readInt(); mSourceAddress = in.readString(); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 38759a9183..60e96f9434 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -84,9 +84,11 @@ public final class IpSecTransform implements AutoCloseable { @Retention(RetentionPolicy.SOURCE) public @interface EncapType {} - private IpSecTransform(Context context, IpSecConfig config) { + /** @hide */ + @VisibleForTesting + public IpSecTransform(Context context, IpSecConfig config) { mContext = context; - mConfig = config; + mConfig = new IpSecConfig(config); mResourceId = INVALID_RESOURCE_ID; } @@ -142,6 +144,18 @@ public final class IpSecTransform implements AutoCloseable { return this; } + /** + * Equals method used for testing + * + * @hide + */ + @VisibleForTesting + public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) { + if (lhs == null || rhs == null) return (lhs == rhs); + return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig()) + && lhs.mResourceId == rhs.mResourceId; + } + /** * Deactivate this {@code IpSecTransform} and free allocated resources. * From 8b0e926d8e127c6cdb0f40e5c1985056868aa723 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 14 Feb 2018 22:29:11 -0700 Subject: [PATCH 0483/1150] Better handling of NTP-based clocks. Now that we have a nice Clock abstraction, we can use it to represent a clock backed by an NTP fix. (This makes testing logic much easier to write.) We now rely completely on NetworkTimeUpdateService to keep our NTP fix up to date, instead of trying to refresh in the middle of critical paths which could trigger random ANRs. Add internal FallbackClock to make it easier to handle missing NTP fixes. Add internal SimpleClock to let implementers focus on single millis() method. Test: bit FrameworksNetTests:com.android.server.net.NetworkStatsServiceTest Test: bit FrameworksServicesTests:com.android.server.NetworkPolicyManagerServiceTest Bug: 69714690, 72320957 Change-Id: Ic32cdcbe093d08b73b0e4b23d6910b23ea8e1968 Exempt-From-Owner-Approval: approved in previous PS --- .../server/net/NetworkStatsService.java | 51 ++++++++----------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 76c4db1340..d1aa21276b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -68,6 +68,7 @@ import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; +import android.annotation.NonNull; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -97,6 +98,7 @@ import android.net.TrafficStats; import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; +import android.os.BestClock; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -120,10 +122,8 @@ import android.util.ArraySet; import android.util.EventLog; import android.util.Log; import android.util.MathUtils; -import android.util.NtpTrustedTime; import android.util.Slog; import android.util.SparseIntArray; -import android.util.TrustedTime; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; @@ -140,6 +140,8 @@ import java.io.File; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.time.Clock; +import java.time.ZoneOffset; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -167,7 +169,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Context mContext; private final INetworkManagementService mNetworkManager; private final AlarmManager mAlarmManager; - private final TrustedTime mTime; + private final Clock mClock; private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -202,7 +204,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public interface NetworkStatsSettings { public long getPollInterval(); - public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); public boolean getAugmentEnabled(); @@ -281,16 +282,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long mPersistThreshold = 2 * MB_IN_BYTES; private long mGlobalAlertBytes; - private static File getDefaultSystemDir() { + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } - private static File getDefaultBaseDir() { + private static @NonNull File getDefaultBaseDir() { File baseDir = new File(getDefaultSystemDir(), "netstats"); baseDir.mkdirs(); return baseDir; } + private static @NonNull Clock getDefaultClock() { + return new BestClock(ZoneOffset.UTC, SystemClock.currentNetworkTimeClock(), + Clock.systemUTC()); + } + public static NetworkStatsService create(Context context, INetworkManagementService networkManager) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); @@ -299,7 +305,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, NtpTrustedTime.getInstance(context), TelephonyManager.getDefault(), + wakeLock, getDefaultClock(), TelephonyManager.getDefault(), new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); @@ -313,13 +319,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, - AlarmManager alarmManager, PowerManager.WakeLock wakeLock, TrustedTime time, + AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, NetworkStatsObservers statsObservers, File systemDir, File baseDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager"); - mTime = checkNotNull(time, "missing TrustedTime"); + mClock = checkNotNull(clock, "missing Clock"); mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); mTeleManager = checkNotNull(teleManager, "missing TelephonyManager"); mWakeLock = checkNotNull(wakeLock, "missing WakeLock"); @@ -413,8 +419,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); // persist any pending stats mDevRecorder.forcePersistLocked(currentTime); @@ -831,8 +836,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // update and persist if beyond new thresholds - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); synchronized (mStatsLock) { if (!mSystemReady) return; @@ -1170,8 +1174,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @GuardedBy("mStatsLock") private void bootstrapStatsLocked() { - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); try { recordSnapshotLocked(currentTime); @@ -1183,11 +1186,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void performPoll(int flags) { - // try refreshing time source when stale - if (mTime.getCacheAge() > mSettings.getTimeCacheMaxAge()) { - mTime.forceRefresh(); - } - synchronized (mStatsLock) { mWakeLock.acquire(); @@ -1215,8 +1213,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // TODO: consider marking "untrusted" times in historical stats - final long currentTime = mTime.hasCache() ? mTime.currentTimeMillis() - : System.currentTimeMillis(); + final long currentTime = mClock.millis(); try { recordSnapshotLocked(currentTime); @@ -1268,7 +1265,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private void performSampleLocked() { // TODO: migrate trustedtime fixes to separate binary log events - final long trustedTime = mTime.hasCache() ? mTime.currentTimeMillis() : -1; + final long currentTime = mClock.millis(); NetworkTemplate template; NetworkStats.Entry devTotal; @@ -1285,7 +1282,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + currentTime); // collect wifi sample template = buildTemplateWifiWildcard(); @@ -1297,7 +1294,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, - trustedTime); + currentTime); } /** @@ -1621,10 +1618,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } @Override - public long getTimeCacheMaxAge() { - return getGlobalLong(NETSTATS_TIME_CACHE_MAX_AGE, DAY_IN_MILLIS); - } - @Override public long getGlobalAlertBytes(long def) { return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } From d0cd0bf0b273116ec1fd70acda85f34e5fc9d975 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 16 Feb 2018 16:28:25 -0700 Subject: [PATCH 0484/1150] Leave NetworkStatsService around during shutdown. We've seen system code continue to ask about network statistics during a shutdown, so keep our objects around to avoid crashing with NPEs. Test: builds, boots Bug: 73323432 Change-Id: I2654d37a59eb830ff32a2151ae6ad6a999a41677 --- .../java/com/android/server/net/NetworkStatsService.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 76c4db1340..02c3210b6b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -422,13 +422,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidRecorder.forcePersistLocked(currentTime); mUidTagRecorder.forcePersistLocked(currentTime); - mDevRecorder = null; - mXtRecorder = null; - mUidRecorder = null; - mUidTagRecorder = null; - - mXtStatsCached = null; - mSystemReady = false; } From 4757d55288c9f7e82dfae03b3785b8269fca5fa5 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 20 Feb 2018 13:36:14 -0700 Subject: [PATCH 0485/1150] Only emit debug logging when requested. Test: builds, boots Bug: 72556865 Change-Id: I69d5d760221ef907eeea38490f56243f0a3b9dcb --- .../java/com/android/server/net/NetworkStatsService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4b80e98f85..32e15c9d9c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -152,7 +152,8 @@ import java.util.List; */ public class NetworkStatsService extends INetworkStatsService.Stub { static final String TAG = "NetworkStats"; - static final boolean LOGV = false; + static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); + static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; @@ -641,14 +642,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL) && mSettings.getAugmentEnabled()) { - Slog.d(TAG, "Resolving plan for " + template); + if (LOGD) Slog.d(TAG, "Resolving plan for " + template); final long token = Binder.clearCallingIdentity(); try { final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); for (int subId : sm.getActiveSubscriptionIdList()) { if (template.matchesSubscriberId(tm.getSubscriberId(subId))) { - Slog.d(TAG, "Found active matching subId " + subId); + if (LOGD) Slog.d(TAG, "Found active matching subId " + subId); final List plans = sm.getSubscriptionPlans(subId); if (!plans.isEmpty()) { plan = plans.get(0); @@ -658,7 +659,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } finally { Binder.restoreCallingIdentity(token); } - Slog.d(TAG, "Resolved to plan " + plan); + if (LOGD) Slog.d(TAG, "Resolved to plan " + plan); } return plan; } From 82ffcf567c07d18129812ec6423d40c520cb7864 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 20 Feb 2018 17:24:55 -0700 Subject: [PATCH 0486/1150] Name specific app for rapid data usage. When a single app is responsible for more than half of the data usage that caused us to trigger a "rapid usage" alert, name that app in the notification. Tests to verify. Move NPMS->NSS direct calls to "Internal" pattern, following best-practices to avoid unnecessary AIDL exposure. Remove 3G/4G split mobile plan support, which has been deprecated for years and was never supported in a shipping product. Move MultipathPolicyTracker in tree to reflect its package name. Test: bit FrameworksNetTests:* Test: bit FrameworksServicesTests:com.android.server.NetworkPolicyManagerServiceTest Bug: 69263587, 64221505, 73431080, 72746951 Exempt-From-Owner-Approval: approved in previous PS Change-Id: I3e4ec1ae2222d51b232f76f32faca93d4f8cd272 --- .../android/net/INetworkStatsService.aidl | 9 -- core/java/android/net/NetworkStats.java | 35 +++--- .../java/android/net/NetworkStatsHistory.java | 17 +++ core/java/android/net/NetworkTemplate.java | 104 ++---------------- .../server/net/NetworkStatsCollection.java | 4 + .../server/net/NetworkStatsService.java | 72 +++++++++--- 6 files changed, 107 insertions(+), 134 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 90e3ffd550..381cfb61de 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -39,9 +39,6 @@ interface INetworkStatsService { */ INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); - /** Return network layer usage total for traffic that matches template. */ - long getNetworkTotalBytes(in NetworkTemplate template, long start, long end); - /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); /** Return set of any ifaces associated with mobile networks since boot. */ @@ -50,17 +47,11 @@ interface INetworkStatsService { /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); - /** Mark given UID as being in foreground for stats purposes. */ - void setUidForeground(int uid, boolean uidForeground); - /** Force update of ifaces. */ void forceUpdateIfaces(in Network[] defaultNetworks); /** Force update of statistics. */ void forceUpdate(); - /** Advise persistance threshold; may be overridden internally. */ - void advisePersistThreshold(long thresholdBytes); - /** Registers a callback on data usage. */ DataUsageRequest registerUsageCallback(String callingPackage, in DataUsageRequest request, in Messenger messenger, in IBinder binder); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 01b2b39213..16fb858a58 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -234,7 +234,7 @@ public class NetworkStats implements Parcelable { public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; - if (initialSize >= 0) { + if (initialSize > 0) { this.capacity = initialSize; this.iface = new String[initialSize]; this.uid = new int[initialSize]; @@ -250,19 +250,7 @@ public class NetworkStats implements Parcelable { this.operations = new long[initialSize]; } else { // Special case for use by NetworkStatsFactory to start out *really* empty. - this.capacity = 0; - this.iface = EmptyArray.STRING; - this.uid = EmptyArray.INT; - this.set = EmptyArray.INT; - this.tag = EmptyArray.INT; - this.metered = EmptyArray.INT; - this.roaming = EmptyArray.INT; - this.defaultNetwork = EmptyArray.INT; - this.rxBytes = EmptyArray.LONG; - this.rxPackets = EmptyArray.LONG; - this.txBytes = EmptyArray.LONG; - this.txPackets = EmptyArray.LONG; - this.operations = EmptyArray.LONG; + clear(); } } @@ -314,6 +302,25 @@ public class NetworkStats implements Parcelable { return clone; } + /** + * Clear all data stored in this object. + */ + public void clear() { + this.capacity = 0; + this.iface = EmptyArray.STRING; + this.uid = EmptyArray.INT; + this.set = EmptyArray.INT; + this.tag = EmptyArray.INT; + this.metered = EmptyArray.INT; + this.roaming = EmptyArray.INT; + this.defaultNetwork = EmptyArray.INT; + this.rxBytes = EmptyArray.LONG; + this.rxPackets = EmptyArray.LONG; + this.txBytes = EmptyArray.LONG; + this.txPackets = EmptyArray.LONG; + this.operations = EmptyArray.LONG; + } + @VisibleForTesting public NetworkStats addIfaceValues( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 433f9410cc..a13ad659e7 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -39,6 +39,8 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.util.IndentingPrintWriter; +import libcore.util.EmptyArray; + import java.io.CharArrayWriter; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -458,6 +460,21 @@ public class NetworkStatsHistory implements Parcelable { bucketCount++; } + /** + * Clear all data stored in this object. + */ + public void clear() { + bucketStart = EmptyArray.LONG; + if (activeTime != null) activeTime = EmptyArray.LONG; + if (rxBytes != null) rxBytes = EmptyArray.LONG; + if (rxPackets != null) rxPackets = EmptyArray.LONG; + if (txBytes != null) txBytes = EmptyArray.LONG; + if (txPackets != null) txPackets = EmptyArray.LONG; + if (operations != null) operations = EmptyArray.LONG; + bucketCount = 0; + totalBytes = 0; + } + /** * Remove buckets older than requested cutoff. */ diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 8efd39a7a7..74233fd990 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -23,7 +23,6 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -34,11 +33,6 @@ import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; -import static android.telephony.TelephonyManager.NETWORK_CLASS_2_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_3_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G; -import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN; -import static android.telephony.TelephonyManager.getNetworkClass; import android.os.Parcel; import android.os.Parcelable; @@ -55,8 +49,8 @@ import java.util.Arrays; import java.util.Objects; /** - * Template definition used to generically match {@link NetworkIdentity}, - * usually when collecting statistics. + * Predicate used to match {@link NetworkIdentity}, usually when collecting + * statistics. (It should probably have been named {@code NetworkPredicate}.) * * @hide */ @@ -68,13 +62,7 @@ public class NetworkTemplate implements Parcelable { */ private static final int BACKUP_VERSION = 1; - public static final int MATCH_MOBILE_ALL = 1; - /** @deprecated don't use this any more */ - @Deprecated - public static final int MATCH_MOBILE_3G_LOWER = 2; - /** @deprecated don't use this any more */ - @Deprecated - public static final int MATCH_MOBILE_4G = 3; + public static final int MATCH_MOBILE = 1; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; public static final int MATCH_MOBILE_WILDCARD = 6; @@ -84,9 +72,7 @@ public class NetworkTemplate implements Parcelable { private static boolean isKnownMatchRule(final int rule) { switch (rule) { - case MATCH_MOBILE_ALL: - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: + case MATCH_MOBILE: case MATCH_WIFI: case MATCH_ETHERNET: case MATCH_MOBILE_WILDCARD: @@ -111,25 +97,7 @@ public class NetworkTemplate implements Parcelable { * the given IMSI. */ public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_ALL, subscriberId, null); - } - - /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with - * the given IMSI that roughly meet a "3G" definition, or lower. - */ - @Deprecated - public static NetworkTemplate buildTemplateMobile3gLower(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_3G_LOWER, subscriberId, null); - } - - /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with - * the given IMSI that roughly meet a "4G" definition. - */ - @Deprecated - public static NetworkTemplate buildTemplateMobile4g(String subscriberId) { - return new NetworkTemplate(MATCH_MOBILE_4G, subscriberId, null); + return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); } /** @@ -307,9 +275,7 @@ public class NetworkTemplate implements Parcelable { public boolean isMatchRuleMobile() { switch (mMatchRule) { - case MATCH_MOBILE_3G_LOWER: - case MATCH_MOBILE_4G: - case MATCH_MOBILE_ALL: + case MATCH_MOBILE: case MATCH_MOBILE_WILDCARD: return true; default: @@ -348,12 +314,8 @@ public class NetworkTemplate implements Parcelable { if (!matchesDefaultNetwork(ident)) return false; switch (mMatchRule) { - case MATCH_MOBILE_ALL: + case MATCH_MOBILE: return matchesMobile(ident); - case MATCH_MOBILE_3G_LOWER: - return matchesMobile3gLower(ident); - case MATCH_MOBILE_4G: - return matchesMobile4g(ident); case MATCH_WIFI: return matchesWifi(ident); case MATCH_ETHERNET: @@ -409,43 +371,6 @@ public class NetworkTemplate implements Parcelable { } } - /** - * Check if mobile network classified 3G or lower with matching IMSI. - */ - @Deprecated - private boolean matchesMobile3gLower(NetworkIdentity ident) { - ensureSubtypeAvailable(); - if (ident.mType == TYPE_WIMAX) { - return false; - } else if (matchesMobile(ident)) { - switch (getNetworkClass(ident.mSubType)) { - case NETWORK_CLASS_UNKNOWN: - case NETWORK_CLASS_2_G: - case NETWORK_CLASS_3_G: - return true; - } - } - return false; - } - - /** - * Check if mobile network classified 4G with matching IMSI. - */ - @Deprecated - private boolean matchesMobile4g(NetworkIdentity ident) { - ensureSubtypeAvailable(); - if (ident.mType == TYPE_WIMAX) { - // TODO: consider matching against WiMAX subscriber identity - return true; - } else if (matchesMobile(ident)) { - switch (getNetworkClass(ident.mSubType)) { - case NETWORK_CLASS_4_G: - return true; - } - } - return false; - } - /** * Check if matches Wi-Fi network template. */ @@ -506,12 +431,8 @@ public class NetworkTemplate implements Parcelable { private static String getMatchRuleName(int matchRule) { switch (matchRule) { - case MATCH_MOBILE_3G_LOWER: - return "MOBILE_3G_LOWER"; - case MATCH_MOBILE_4G: - return "MOBILE_4G"; - case MATCH_MOBILE_ALL: - return "MOBILE_ALL"; + case MATCH_MOBILE: + return "MOBILE"; case MATCH_WIFI: return "WIFI"; case MATCH_ETHERNET: @@ -529,13 +450,6 @@ public class NetworkTemplate implements Parcelable { } } - private static void ensureSubtypeAvailable() { - if (COMBINE_SUBTYPE_ENABLED) { - throw new IllegalArgumentException( - "Unable to enforce 3G_LOWER template on combined data."); - } - } - /** * Examine the given template and normalize if it refers to a "merged" * mobile subscriber. We pick the "lowest" merged subscriber as the primary diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 3cc4d83267..a5f8dc72d8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -106,6 +106,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { reset(); } + public void clear() { + reset(); + } + public void reset() { mStats.clear(); mStartMillis = Long.MAX_VALUE; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 32e15c9d9c..93c04fe206 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -49,7 +49,6 @@ import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE; import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES; import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL; import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED; -import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE; import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES; @@ -95,10 +94,10 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; -import android.os.BestClock; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; @@ -134,6 +133,7 @@ import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.connectivity.Tethering; import java.io.File; @@ -333,6 +333,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); + + LocalServices.addService(NetworkStatsManagerInternal.class, + new NetworkStatsManagerInternalImpl()); } @VisibleForTesting @@ -640,7 +643,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { SubscriptionPlan plan = null; if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 - && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE_ALL) + && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE) && mSettings.getAugmentEnabled()) { if (LOGD) Slog.d(TAG, "Resolving plan for " + template); final long token = Binder.clearCallingIdentity(); @@ -701,12 +704,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @Override - public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - // Special case - since this is for internal use only, don't worry about - // a full access level check and just require the signature/privileged - // permission. - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { + assertSystemReady(); assertBandwidthControlEnabled(); // NOTE: if callers want to get non-augmented data, they should go @@ -716,6 +715,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); } + private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { + assertSystemReady(); + assertBandwidthControlEnabled(); + + final NetworkStatsCollection uidComplete; + synchronized (mStatsLock) { + uidComplete = mUidRecorder.getOrLoadCompleteLocked(); + } + return uidComplete.getSummary(template, start, end, NetworkStatsAccess.Level.DEVICE, + android.os.Process.SYSTEM_UID); + } + @Override public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { if (Binder.getCallingUid() != uid) { @@ -777,10 +788,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @Override - public void setUidForeground(int uid, boolean uidForeground) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); - + @VisibleForTesting + void setUidForeground(int uid, boolean uidForeground) { synchronized (mStatsLock) { final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); @@ -817,9 +826,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @Override - public void advisePersistThreshold(long thresholdBytes) { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + private void advisePersistThreshold(long thresholdBytes) { assertBandwidthControlEnabled(); // clamp threshold into safe range @@ -1330,6 +1337,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { removeUidsLocked(uids); } + private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal { + @Override + public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { + return NetworkStatsService.this.getNetworkTotalBytes(template, start, end); + } + + @Override + public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { + return NetworkStatsService.this.getNetworkUidBytes(template, start, end); + } + + @Override + public void setUidForeground(int uid, boolean uidForeground) { + NetworkStatsService.this.setUidForeground(uid, uidForeground); + } + + @Override + public void advisePersistThreshold(long thresholdBytes) { + NetworkStatsService.this.advisePersistThreshold(thresholdBytes); + } + + @Override + public void forceUpdate() { + NetworkStatsService.this.forceUpdate(); + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; @@ -1550,6 +1584,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private void assertSystemReady() { + if (!mSystemReady) { + throw new IllegalStateException("System not ready"); + } + } + private void assertBandwidthControlEnabled() { if (!isBandwidthControlEnabled()) { throw new IllegalStateException("Bandwidth module disabled"); From a32100e85c967a941634955a531365060f5a90a4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 27 Feb 2018 22:47:01 +0900 Subject: [PATCH 0487/1150] Minor cleanups to NetworkStats interface tracking. Currently, when a network goes into CONNECTED state, we call updateLinkProperties and then notifyIfacesChangedForNetworkStats. The latter is unnecessary, as there are exactly two cases: 1. networkAgent.linkProperties != null: updateLinkProperties will call notifyIfacesChangedForNetworkStats, because oldLp is null and networkAgent.linkProperties is not null. 2. networkAgent.linkProperties is null: there is no need to call notifyIfacesChangedForNetworkStats, because no interfaces were added or removed. When they are, updateLinkProperties will be called again. Removing the call to notifyIfacesChangedForNetworkStats avoids a stats poll, which is a minor performance improvement. Also, remove the NetworkStatsService code to do asynchronous interface updates, since it has no callers. Bug: 72107146 Test: builds, boots Test: runtest frameworks-net Change-Id: I9337ea26c0505a1c66ceda01254b68e25cd7972c --- .../java/com/android/server/net/NetworkStatsService.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index bfc150e1a9..82981275fc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -153,8 +153,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { static final boolean LOGV = false; private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_UPDATE_IFACES = 2; - private static final int MSG_REGISTER_GLOBAL_ALERT = 3; + private static final int MSG_REGISTER_GLOBAL_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -1533,10 +1532,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mService.performPoll(flags); return true; } - case MSG_UPDATE_IFACES: { - mService.updateIfaces(null); - return true; - } case MSG_REGISTER_GLOBAL_ALERT: { mService.registerGlobalAlert(); return true; From 34dcea11fdc7e01f3317bebdf77597c8d75da411 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 5 Mar 2018 18:14:56 +0900 Subject: [PATCH 0488/1150] Allow null subscriberId in NetworkStatsManager. Use a MATCH_MOBILE_WILDCARD template to avoid filtering by subscriberId when querying statistics from NetworkStatsService. Bug: 74038898 Change-Id: I4b39e7031416cb33b23d89aa36ff0f774eaa942f Fixes: 74038898 Test: runtest frameworks-net, CTS tests pass --- core/java/android/app/usage/NetworkStats.java | 6 +-- .../app/usage/NetworkStatsManager.java | 40 ++++++++++++------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index d33af4faeb..6ca23496a8 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -24,7 +24,6 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.RemoteException; -import android.os.ServiceManager; import android.util.IntArray; import android.util.Log; @@ -98,9 +97,8 @@ public final class NetworkStats implements AutoCloseable { /** @hide */ NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, - long endTimestamp) throws RemoteException, SecurityException { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + long endTimestamp, INetworkStatsService statsService) + throws RemoteException, SecurityException { // Open network stats session mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); mCloseGuard.open("close"); diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5576e86edd..2357637b72 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -37,6 +37,8 @@ import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + /** * Provides access to network usage history and statistics. Usage data is collected in * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. @@ -107,9 +109,15 @@ public class NetworkStatsManager { * {@hide} */ public NetworkStatsManager(Context context) throws ServiceNotFoundException { + this(context, INetworkStatsService.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); + } + + /** @hide */ + @VisibleForTesting + public NetworkStatsManager(Context context, INetworkStatsService service) { mContext = context; - mService = INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); + mService = service; setPollOnOpen(true); } @@ -135,7 +143,8 @@ public class NetworkStatsManager { public Bucket querySummaryForDevice(NetworkTemplate template, long startTime, long endTime) throws SecurityException, RemoteException { Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, + mService); bucket = stats.getDeviceSummaryForNetwork(); stats.close(); @@ -208,7 +217,7 @@ public class NetworkStatsManager { } NetworkStats stats; - stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); stats.startSummaryEnumeration(); stats.close(); @@ -245,7 +254,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startSummaryEnumeration(); return result; @@ -295,7 +304,7 @@ public class NetworkStatsManager { NetworkStats result; try { - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startHistoryEnumeration(uid, tag); } catch (RemoteException e) { Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e); @@ -341,7 +350,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startUserUidEnumeration(); return result; } @@ -451,19 +460,20 @@ public class NetworkStatsManager { } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { - NetworkTemplate template = null; + final NetworkTemplate template; switch (networkType) { - case ConnectivityManager.TYPE_MOBILE: { - template = NetworkTemplate.buildTemplateMobileAll(subscriberId); - } break; - case ConnectivityManager.TYPE_WIFI: { + case ConnectivityManager.TYPE_MOBILE: + template = subscriberId == null + ? NetworkTemplate.buildTemplateMobileWildcard() + : NetworkTemplate.buildTemplateMobileAll(subscriberId); + break; + case ConnectivityManager.TYPE_WIFI: template = NetworkTemplate.buildTemplateWifiWildcard(); - } break; - default: { + break; + default: throw new IllegalArgumentException("Cannot create template for network type " + networkType + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); - } } return template; } From ad1f51c7f894f613127e7a5767038b76f5a7a5e1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Mar 2018 18:53:07 -0800 Subject: [PATCH 0489/1150] Added implementation for VTI add/remove address This change adds implementation details for add/remove addresses onto a VTI. Bug: 73675031 Test: New tests added, passing on Walleye Change-Id: Idde9d943a5285d2c13c5c6b0f7b8a9faf718e6a5 --- core/java/android/net/IIpSecService.aidl | 5 +- core/java/android/net/IpSecManager.java | 16 +++-- .../java/com/android/server/IpSecService.java | 60 +++++++++++++------ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3ce0283d7f..3a3ddcc483 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.LinkAddress; import android.net.Network; import android.net.IpSecConfig; import android.net.IpSecUdpEncapResponse; @@ -48,11 +49,11 @@ interface IIpSecService void addAddressToTunnelInterface( int tunnelResourceId, - String localAddr); + in LinkAddress localAddr); void removeAddressFromTunnelInterface( int tunnelResourceId, - String localAddr); + in LinkAddress localAddr); void deleteTunnelInterface(int resourceId); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a..f1beef1f21 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -660,10 +660,14 @@ public final class IpSecManager { * tunneled traffic. * * @param address the local address for traffic inside the tunnel - * @throws IOException if the address could not be added * @hide */ - public void addAddress(LinkAddress address) throws IOException { + public void addAddress(LinkAddress address) { + try { + mService.addAddressToTunnelInterface(mResourceId, address); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -672,10 +676,14 @@ public final class IpSecManager { *

            Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed - * @throws IOException if the address could not be removed * @hide */ - public void removeAddress(LinkAddress address) throws IOException { + public void removeAddress(LinkAddress address) { + try { + mService.removeAddressFromTunnelInterface(mResourceId, address); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } private IpSecTunnelInterface(@NonNull IIpSecService service, diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45a4dfb91b..45e9481c22 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -36,6 +36,7 @@ import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; +import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; @@ -618,10 +619,8 @@ public class IpSecService extends IIpSecService.Stub { spi, mConfig.getMarkValue(), mConfig.getMarkMask()); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } getResourceTracker().give(); @@ -681,10 +680,8 @@ public class IpSecService extends IIpSecService.Stub { .getNetdInstance() .ipSecDeleteSecurityAssociation( mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); + } catch (ServiceSpecificException | RemoteException e) { + Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); } mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; @@ -829,15 +826,13 @@ public class IpSecService extends IIpSecService.Stub { 0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff); } } - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { + } catch (ServiceSpecificException | RemoteException e) { Log.e( TAG, "Failed to delete VTI with interface name: " + mInterfaceName + " and id: " - + mResourceId); + + mResourceId, e); } getResourceTracker().give(); @@ -1319,7 +1314,9 @@ public class IpSecService extends IIpSecService.Stub { * from multiple local IP addresses over the same tunnel. */ @Override - public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) { + public synchronized void addAddressToTunnelInterface( + int tunnelResourceId, LinkAddress localAddr) { + enforceNetworkStackPermission(); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1327,8 +1324,21 @@ public class IpSecService extends IIpSecService.Stub { TunnelInterfaceRecord tunnelInterfaceInfo = userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - // TODO: Add calls to netd: - // Add address to TunnelInterface + try { + // We can assume general validity of the IP address, since we get them as a + // LinkAddress, which does some validation. + mSrvConfig + .getNetdInstance() + .interfaceAddAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. + throw new IllegalArgumentException(e); + } } /** @@ -1337,7 +1347,8 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, String localAddr) { + int tunnelResourceId, LinkAddress localAddr) { + enforceNetworkStackPermission(); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1345,8 +1356,21 @@ public class IpSecService extends IIpSecService.Stub { TunnelInterfaceRecord tunnelInterfaceInfo = userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - // TODO: Add calls to netd: - // Remove address from TunnelInterface + try { + // We can assume general validity of the IP address, since we get them as a + // LinkAddress, which does some validation. + mSrvConfig + .getNetdInstance() + .interfaceDelAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. + throw new IllegalArgumentException(e); + } } /** From 11669685cdc91c5bd3b421c922b9f4e94e9d6032 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 6 Mar 2018 13:22:22 -0800 Subject: [PATCH 0490/1150] Docstring Updates for applyTransportModeTransform -Add anotations to usages of PolicyDirection for apply...() methods. -Update the comments on DIRECTION_IN and DIRECTION_OUT to better reflect their current usage. -Add a better explanation to the rekey procedure doc. -Remove disused createTunnelInterface() stub. Bug: 73751066 Test: make docs Change-Id: I9f2ec864466148a18899f1e952c74a525902ccbc --- core/java/android/net/IpSecManager.java | 88 +++++++++++++------------ 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a..fbf305633a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -58,14 +58,18 @@ public final class IpSecManager { private static final String TAG = "IpSecManager"; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic towards the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * towards the host. + * + *

            See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_IN = 0; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic from the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * away from the host. + * + *

            See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_OUT = 1; @@ -301,19 +305,21 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a stream socket - * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - Socket socket, int direction, IpSecTransform transform) + Socket socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -334,19 +340,22 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a datagram socket - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { + DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) + throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -366,19 +375,21 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a socket file descriptor - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - FileDescriptor socket, int direction, IpSecTransform transform) + FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method. @@ -389,21 +400,6 @@ public final class IpSecManager { } } - /** - * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to - * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to - * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic). - * Applications should probably not use this API directly. Instead, they should use {@link - * VpnService} to provide VPN capability in a more generic fashion. - * - *

            TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. - * - * @param net a {@link Network} that will be tunneled via IP Sec. - * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. - * @hide - */ - public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} - /** * Remove an IPsec transform from a stream socket. * @@ -770,7 +766,12 @@ public final class IpSecManager { } /** - * Apply a transform to the IpSecTunnelInterface + * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will + * tunnel all traffic for the given direction through the underlying network's interface with + * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional + * IP header and IPsec Header on all inbound traffic). + *

            Applications should probably not use this API directly. + * * * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied * transform. @@ -783,8 +784,8 @@ public final class IpSecManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, - IpSecTransform transform) throws IOException { + public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, + @PolicyDirection int direction, IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId()); @@ -792,6 +793,7 @@ public final class IpSecManager { throw e.rethrowFromSystemServer(); } } + /** * Construct an instance of IpSecManager within an application context. * From cec463f0a7766a37a29431876bdb3ceb0b01be16 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 15 Mar 2018 19:41:41 -0700 Subject: [PATCH 0491/1150] Add support for auth-only transforms Kernel limitations prevent auth-only SAs from being created. Explicitly request a null encryption algorithm instead of omitting the algorithm to comply with the kernel requirement for ESP. Bug: 75049573 Test: CTS tests for auth-only, crypt-only transforms added for all combinations of (UDP, TCP, IPv4, IPv6, UDP-encap) Also added unit tests to ensure correct triggering of NULL_CRYPT usage. Change-Id: Ia9a5cfee9c7786412846bc039f326420f6211c08 --- core/java/android/net/IpSecAlgorithm.java | 7 +++++++ services/core/java/com/android/server/IpSecService.java | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index c69a4d4c0b..f4b328e412 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -37,6 +37,13 @@ import java.util.Arrays; public final class IpSecAlgorithm implements Parcelable { private static final String TAG = "IpSecAlgorithm"; + /** + * Null cipher. + * + * @hide + */ + public static final String CRYPT_NULL = "ecb(cipher_null)"; + /** * AES-CBC Encryption/Ciphering Algorithm. * diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45a4dfb91b..d3f1a7bbb5 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1467,6 +1467,13 @@ public class IpSecService extends IIpSecService.Stub { IpSecAlgorithm crypt = c.getEncryption(); IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); + String cryptName; + if (crypt == null) { + cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : ""; + } else { + cryptName = crypt.getName(); + } + mSrvConfig .getNetdInstance() .ipSecAddSecurityAssociation( @@ -1481,7 +1488,7 @@ public class IpSecService extends IIpSecService.Stub { (auth != null) ? auth.getName() : "", (auth != null) ? auth.getKey() : new byte[] {}, (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", + cryptName, (crypt != null) ? crypt.getKey() : new byte[] {}, (crypt != null) ? crypt.getTruncationLengthBits() : 0, (authCrypt != null) ? authCrypt.getName() : "", From 95c6602f5046dd527ba5add0923f70f5c6616e91 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 6 Mar 2018 13:22:22 -0800 Subject: [PATCH 0492/1150] Docstring Updates for applyTransportModeTransform -Add anotations to usages of PolicyDirection for apply...() methods. -Update the comments on DIRECTION_IN and DIRECTION_OUT to better reflect their current usage. -Add a better explanation to the rekey procedure doc. -Remove disused createTunnelInterface() stub. Bug: 73751066 Test: make docs Merged-In: I9f2ec864466148a18899f1e952c74a525902ccbc Change-Id: I9f2ec864466148a18899f1e952c74a525902ccbc (cherry picked from commit f4cdf25a906d0f52ffd76508d660b843b13b3ff8) --- core/java/android/net/IpSecManager.java | 88 +++++++++++++------------ 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a..fbf305633a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -58,14 +58,18 @@ public final class IpSecManager { private static final String TAG = "IpSecManager"; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic towards the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * towards the host. + * + *

            See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_IN = 0; /** - * For direction-specific attributes of an {@link IpSecTransform}, indicates that an attribute - * applies to traffic from the host. + * Used when applying a transform to direct traffic through an {@link IpSecTransform} + * away from the host. + * + *

            See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. */ public static final int DIRECTION_OUT = 1; @@ -301,19 +305,21 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a stream socket - * @param direction the policy direction either {@link #DIRECTION_IN} or {@link #DIRECTION_OUT} + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - Socket socket, int direction, IpSecTransform transform) + Socket socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -334,19 +340,22 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a datagram socket - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - DatagramSocket socket, int direction, IpSecTransform transform) throws IOException { + DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) + throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -366,19 +375,21 @@ public final class IpSecManager { * *

            Rekey Procedure

            * - *

            When applying a new tranform to a socket, the previous transform will be removed. However, - * inbound traffic on the old transform will continue to be decrypted until that transform is - * deallocated by calling {@link IpSecTransform#close()}. This overlap allows rekey procedures - * where both transforms are valid until both endpoints are using the new transform and all - * in-flight packets have been received. + *

            When applying a new tranform to a socket in the outbound direction, the previous transform + * will be removed and the new transform will take effect immediately, sending all traffic on + * the new transform; however, when applying a transform in the inbound direction, traffic + * on the old transform will continue to be decrypted and delivered until that transform is + * deallocated by calling {@link IpSecTransform#close()}. This overlap allows lossless rekey + * procedures where both transforms are valid until both endpoints are using the new transform + * and all in-flight packets have been received. * * @param socket a socket file descriptor - * @param direction the policy direction either DIRECTION_IN or DIRECTION_OUT + * @param direction the direction in which the transform should be applied * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ public void applyTransportModeTransform( - FileDescriptor socket, int direction, IpSecTransform transform) + FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method. @@ -389,21 +400,6 @@ public final class IpSecManager { } } - /** - * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to - * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to - * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic). - * Applications should probably not use this API directly. Instead, they should use {@link - * VpnService} to provide VPN capability in a more generic fashion. - * - *

            TODO: Update javadoc for tunnel mode APIs at the same time the APIs are re-worked. - * - * @param net a {@link Network} that will be tunneled via IP Sec. - * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform. - * @hide - */ - public void applyTunnelModeTransform(Network net, IpSecTransform transform) {} - /** * Remove an IPsec transform from a stream socket. * @@ -770,7 +766,12 @@ public final class IpSecManager { } /** - * Apply a transform to the IpSecTunnelInterface + * Apply an active Tunnel Mode IPsec Transform to a {@link IpSecTunnelInterface}, which will + * tunnel all traffic for the given direction through the underlying network's interface with + * IPsec (applies an outer IP header and IPsec Header to all traffic, and expects an additional + * IP header and IPsec Header on all inbound traffic). + *

            Applications should probably not use this API directly. + * * * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied * transform. @@ -783,8 +784,8 @@ public final class IpSecManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, int direction, - IpSecTransform transform) throws IOException { + public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, + @PolicyDirection int direction, IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId()); @@ -792,6 +793,7 @@ public final class IpSecManager { throw e.rethrowFromSystemServer(); } } + /** * Construct an instance of IpSecManager within an application context. * From 96a304ec6aad1820daece525711b27ba4ae1859d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 27 Feb 2018 19:19:40 -0800 Subject: [PATCH 0493/1150] Check mOwnedByTransform to avoid DELSA on SPI The owned by transform flag prevents the removal of an SPI from accidentally deleting an associated SA in the kernel. That flag wasn't actually being checked, so deleting an SPI would result in the transform being removed. The existing code already guarantees that the SA is deleted when the transform is deleted Bug: 73258845 Test: runtest frameworks-net Change-Id: I4c26aea7af817a5d9e54da5db1cdf4f943bcae06 --- .../core/java/com/android/server/IpSecService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45e9481c22..89f599b17f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -676,10 +676,12 @@ public class IpSecService extends IIpSecService.Stub { @Override public void freeUnderlyingResources() { try { - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityAssociation( - mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + if (!mOwnedByTransform) { + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); } From 3a48f26dcaaf97ddfbb722a38484e8f5cbf1efc4 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 20 Mar 2018 12:26:10 -0700 Subject: [PATCH 0494/1150] Expose add/removeAddress for IpSecInterfaces When exposing the APIs, these were missed. The outer structure is exposed, so this exposes the addAddress and removeAddress methods. Bug: 75234273 Test: compilation Change-Id: I79911434f9baa660e4d8564cc59d80da4a710c42 --- core/java/android/net/IpSecManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4e1f83430a..cb4299ef69 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -658,7 +658,8 @@ public final class IpSecManager { * @param address the local address for traffic inside the tunnel * @hide */ - public void addAddress(LinkAddress address) { + @SystemApi + public void addAddress(LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -674,7 +675,8 @@ public final class IpSecManager { * @param address to be removed * @hide */ - public void removeAddress(LinkAddress address) { + @SystemApi + public void removeAddress(LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); } catch (RemoteException e) { From f628b3b3c9f42ee45c50bb7867ab5bb442730743 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 15 Mar 2018 19:41:41 -0700 Subject: [PATCH 0495/1150] Add support for auth-only transforms Kernel limitations prevent auth-only SAs from being created. Explicitly request a null encryption algorithm instead of omitting the algorithm to comply with the kernel requirement for ESP. Bug: 75049573 Test: CTS tests for auth-only, crypt-only transforms added for all combinations of (UDP, TCP, IPv4, IPv6, UDP-encap) Also added unit tests to ensure correct triggering of NULL_CRYPT usage. Merged-In: Ia9a5cfee9c7786412846bc039f326420f6211c08 Change-Id: Ia9a5cfee9c7786412846bc039f326420f6211c08 (cherry picked from commit bf013a3820c69348e034c6340b28e95f3441ebe8) --- core/java/android/net/IpSecAlgorithm.java | 7 +++++++ services/core/java/com/android/server/IpSecService.java | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index c69a4d4c0b..f4b328e412 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -37,6 +37,13 @@ import java.util.Arrays; public final class IpSecAlgorithm implements Parcelable { private static final String TAG = "IpSecAlgorithm"; + /** + * Null cipher. + * + * @hide + */ + public static final String CRYPT_NULL = "ecb(cipher_null)"; + /** * AES-CBC Encryption/Ciphering Algorithm. * diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45a4dfb91b..d3f1a7bbb5 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1467,6 +1467,13 @@ public class IpSecService extends IIpSecService.Stub { IpSecAlgorithm crypt = c.getEncryption(); IpSecAlgorithm authCrypt = c.getAuthenticatedEncryption(); + String cryptName; + if (crypt == null) { + cryptName = (authCrypt == null) ? IpSecAlgorithm.CRYPT_NULL : ""; + } else { + cryptName = crypt.getName(); + } + mSrvConfig .getNetdInstance() .ipSecAddSecurityAssociation( @@ -1481,7 +1488,7 @@ public class IpSecService extends IIpSecService.Stub { (auth != null) ? auth.getName() : "", (auth != null) ? auth.getKey() : new byte[] {}, (auth != null) ? auth.getTruncationLengthBits() : 0, - (crypt != null) ? crypt.getName() : "", + cryptName, (crypt != null) ? crypt.getKey() : new byte[] {}, (crypt != null) ? crypt.getTruncationLengthBits() : 0, (authCrypt != null) ? authCrypt.getName() : "", From c53a274b8fcd54af3ba6239d2d17c402c195b508 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 1 Mar 2018 18:53:07 -0800 Subject: [PATCH 0496/1150] Added implementation for VTI add/remove address This change adds implementation details for add/remove addresses onto a VTI. Bug: 73675031 Test: New tests added, passing on Walleye Merged-In: Idde9d943a5285d2c13c5c6b0f7b8a9faf718e6a5 Change-Id: Idde9d943a5285d2c13c5c6b0f7b8a9faf718e6a5 (cherry picked from commit ecc9f7cc08804e3fa15fea04ae94ea1bc74edbfe) --- core/java/android/net/IIpSecService.aidl | 5 +- core/java/android/net/IpSecManager.java | 16 +++-- .../java/com/android/server/IpSecService.java | 60 +++++++++++++------ 3 files changed, 57 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3ce0283d7f..3a3ddcc483 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.LinkAddress; import android.net.Network; import android.net.IpSecConfig; import android.net.IpSecUdpEncapResponse; @@ -48,11 +49,11 @@ interface IIpSecService void addAddressToTunnelInterface( int tunnelResourceId, - String localAddr); + in LinkAddress localAddr); void removeAddressFromTunnelInterface( int tunnelResourceId, - String localAddr); + in LinkAddress localAddr); void deleteTunnelInterface(int resourceId); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index fbf305633a..4e1f83430a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -656,10 +656,14 @@ public final class IpSecManager { * tunneled traffic. * * @param address the local address for traffic inside the tunnel - * @throws IOException if the address could not be added * @hide */ - public void addAddress(LinkAddress address) throws IOException { + public void addAddress(LinkAddress address) { + try { + mService.addAddressToTunnelInterface(mResourceId, address); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** @@ -668,10 +672,14 @@ public final class IpSecManager { *

            Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed - * @throws IOException if the address could not be removed * @hide */ - public void removeAddress(LinkAddress address) throws IOException { + public void removeAddress(LinkAddress address) { + try { + mService.removeAddressFromTunnelInterface(mResourceId, address); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } private IpSecTunnelInterface(@NonNull IIpSecService service, diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45a4dfb91b..45e9481c22 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -36,6 +36,7 @@ import android.net.IpSecTransform; import android.net.IpSecTransformResponse; import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; +import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; @@ -618,10 +619,8 @@ public class IpSecService extends IIpSecService.Stub { spi, mConfig.getMarkValue(), mConfig.getMarkMask()); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SA with ID: " + mResourceId); + } catch (RemoteException | ServiceSpecificException e) { + Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } getResourceTracker().give(); @@ -681,10 +680,8 @@ public class IpSecService extends IIpSecService.Stub { .getNetdInstance() .ipSecDeleteSecurityAssociation( mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { - Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId); + } catch (ServiceSpecificException | RemoteException e) { + Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); } mSpi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; @@ -829,15 +826,13 @@ public class IpSecService extends IIpSecService.Stub { 0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff); } } - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } catch (RemoteException e) { + } catch (ServiceSpecificException | RemoteException e) { Log.e( TAG, "Failed to delete VTI with interface name: " + mInterfaceName + " and id: " - + mResourceId); + + mResourceId, e); } getResourceTracker().give(); @@ -1319,7 +1314,9 @@ public class IpSecService extends IIpSecService.Stub { * from multiple local IP addresses over the same tunnel. */ @Override - public synchronized void addAddressToTunnelInterface(int tunnelResourceId, String localAddr) { + public synchronized void addAddressToTunnelInterface( + int tunnelResourceId, LinkAddress localAddr) { + enforceNetworkStackPermission(); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1327,8 +1324,21 @@ public class IpSecService extends IIpSecService.Stub { TunnelInterfaceRecord tunnelInterfaceInfo = userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - // TODO: Add calls to netd: - // Add address to TunnelInterface + try { + // We can assume general validity of the IP address, since we get them as a + // LinkAddress, which does some validation. + mSrvConfig + .getNetdInstance() + .interfaceAddAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. + throw new IllegalArgumentException(e); + } } /** @@ -1337,7 +1347,8 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, String localAddr) { + int tunnelResourceId, LinkAddress localAddr) { + enforceNetworkStackPermission(); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1345,8 +1356,21 @@ public class IpSecService extends IIpSecService.Stub { TunnelInterfaceRecord tunnelInterfaceInfo = userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); - // TODO: Add calls to netd: - // Remove address from TunnelInterface + try { + // We can assume general validity of the IP address, since we get them as a + // LinkAddress, which does some validation. + mSrvConfig + .getNetdInstance() + .interfaceDelAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. + throw new IllegalArgumentException(e); + } } /** From 902acb89ddaf27abebece6559b987495371e8951 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 20 Mar 2018 12:26:10 -0700 Subject: [PATCH 0497/1150] Expose add/removeAddress for IpSecInterfaces When exposing the APIs, these were missed. The outer structure is exposed, so this exposes the addAddress and removeAddress methods. Bug: 75234273 Test: compilation Merged-In: I79911434f9baa660e4d8564cc59d80da4a710c42 Change-Id: I79911434f9baa660e4d8564cc59d80da4a710c42 (cherry picked from commit a83601a511c3f11470109d78d1a736acdb9c6bd8) --- core/java/android/net/IpSecManager.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4e1f83430a..cb4299ef69 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -658,7 +658,8 @@ public final class IpSecManager { * @param address the local address for traffic inside the tunnel * @hide */ - public void addAddress(LinkAddress address) { + @SystemApi + public void addAddress(LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -674,7 +675,8 @@ public final class IpSecManager { * @param address to be removed * @hide */ - public void removeAddress(LinkAddress address) { + @SystemApi + public void removeAddress(LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); } catch (RemoteException e) { From 52e219bded0f53dec213147732a26908335dbd4b Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 27 Feb 2018 19:19:40 -0800 Subject: [PATCH 0498/1150] Check mOwnedByTransform to avoid DELSA on SPI The owned by transform flag prevents the removal of an SPI from accidentally deleting an associated SA in the kernel. That flag wasn't actually being checked, so deleting an SPI would result in the transform being removed. The existing code already guarantees that the SA is deleted when the transform is deleted Bug: 73258845 Test: runtest frameworks-net Merged-In: I4c26aea7af817a5d9e54da5db1cdf4f943bcae06 Change-Id: I4c26aea7af817a5d9e54da5db1cdf4f943bcae06 (cherry picked from commit 22795302be4ec35449908cf566aa7c16945df836) --- .../core/java/com/android/server/IpSecService.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45e9481c22..89f599b17f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -676,10 +676,12 @@ public class IpSecService extends IIpSecService.Stub { @Override public void freeUnderlyingResources() { try { - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityAssociation( - mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + if (!mOwnedByTransform) { + mSrvConfig + .getNetdInstance() + .ipSecDeleteSecurityAssociation( + mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); } From 2d07666599af3e1518d31fcaab2d0e2065443cc3 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Fri, 16 Mar 2018 17:27:30 -0700 Subject: [PATCH 0499/1150] Add NonNull Annotations To IpSec API Surface This CL adds NonNull annotations to a large number of method returns and parameters as part of API council feedback. Bug: 72473424 Test: compilation (docstring-only change) Change-Id: I2f865dde56fe12116c461ad98e9460bf1802ce18 --- core/java/android/net/IpSecAlgorithm.java | 8 +++-- core/java/android/net/IpSecManager.java | 44 +++++++++++------------ core/java/android/net/IpSecTransform.java | 6 ++++ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index f4b328e412..57f05884ce 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -129,7 +129,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. */ - public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) { + public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { this(algorithm, key, key.length * 8); } @@ -144,7 +144,8 @@ public final class IpSecAlgorithm implements Parcelable { * @param key key padded to a multiple of 8 bits. * @param truncLenBits number of bits of output hash to use. */ - public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { + public IpSecAlgorithm( + @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { mName = algorithm; mKey = key.clone(); mTruncLenBits = truncLenBits; @@ -152,11 +153,13 @@ public final class IpSecAlgorithm implements Parcelable { } /** Get the algorithm name */ + @NonNull public String getName() { return mName; } /** Get the key for this algorithm */ + @NonNull public byte[] getKey() { return mKey.clone(); } @@ -270,6 +273,7 @@ public final class IpSecAlgorithm implements Parcelable { } @Override + @NonNull public String toString() { return new StringBuilder() .append("{mName=") diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index cb4299ef69..4157845d61 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -253,8 +253,9 @@ public final class IpSecManager { * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user */ - public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress) - throws ResourceUnavailableException { + @NonNull + public SecurityParameterIndex allocateSecurityParameterIndex( + @NonNull InetAddress destinationAddress) throws ResourceUnavailableException { try { return new SecurityParameterIndex( mService, @@ -280,8 +281,9 @@ public final class IpSecManager { * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be * reserved */ + @NonNull public SecurityParameterIndex allocateSecurityParameterIndex( - InetAddress destinationAddress, int requestedSpi) + @NonNull InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); @@ -318,9 +320,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - Socket socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull Socket socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -353,9 +354,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull DatagramSocket socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -388,9 +388,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull FileDescriptor socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { @@ -413,8 +412,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(Socket socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { removeTransportModeTransforms(socket.getFileDescriptor$()); } @@ -431,8 +429,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(DatagramSocket socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException { removeTransportModeTransforms(socket.getFileDescriptor$()); } @@ -449,8 +446,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(FileDescriptor socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.removeTransportModeTransforms(pfd); } catch (RemoteException e) { @@ -588,6 +584,7 @@ public final class IpSecManager { // safely usable for Encapsulation without allowing a user to possibly unbind from/close // the port, which could potentially impact the traffic of the next user who binds to that // socket. + @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) throws IOException, ResourceUnavailableException { /* @@ -617,6 +614,7 @@ public final class IpSecManager { // safely usable for Encapsulation without allowing a user to possibly unbind from/close // the port, which could potentially impact the traffic of the next user who binds to that // socket. + @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { return new UdpEncapsulationSocket(mService, 0); @@ -645,6 +643,7 @@ public final class IpSecManager { private int mResourceId = INVALID_RESOURCE_ID; /** Get the underlying SPI held by this object. */ + @NonNull public String getInterfaceName() { return mInterfaceName; } @@ -659,7 +658,7 @@ public final class IpSecManager { * @hide */ @SystemApi - public void addAddress(LinkAddress address) throws IOException { + public void addAddress(@NonNull LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -676,7 +675,7 @@ public final class IpSecManager { * @hide */ @SystemApi - public void removeAddress(LinkAddress address) throws IOException { + public void removeAddress(@NonNull LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -768,6 +767,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) @@ -794,8 +794,8 @@ public final class IpSecManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, - @PolicyDirection int direction, IpSecTransform transform) throws IOException { + public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId()); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 60e96f9434..cf58647bbb 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -350,6 +350,7 @@ public final class IpSecTransform implements AutoCloseable { * * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ + @NonNull public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. Preconditions.checkNotNull(algo); @@ -364,6 +365,7 @@ public final class IpSecTransform implements AutoCloseable { * * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ + @NonNull public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. Preconditions.checkNotNull(algo); @@ -384,6 +386,7 @@ public final class IpSecTransform implements AutoCloseable { * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * be applied. */ + @NonNull public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { Preconditions.checkNotNull(algo); mConfig.setAuthenticatedEncryption(algo); @@ -403,6 +406,7 @@ public final class IpSecTransform implements AutoCloseable { * @param remotePort the UDP port number of the remote host that will send and receive * encapsulated traffic. In the case of IKEv2, this should be port 4500. */ + @NonNull public IpSecTransform.Builder setIpv4Encapsulation( @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { Preconditions.checkNotNull(localSocket); @@ -436,6 +440,7 @@ public final class IpSecTransform implements AutoCloseable { * collides with an existing transform * @throws IOException indicating other errors */ + @NonNull public IpSecTransform buildTransportModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) @@ -472,6 +477,7 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, From a26fb9005288857602801cb97aa36cf74645b893 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Fri, 16 Mar 2018 17:27:30 -0700 Subject: [PATCH 0500/1150] Add NonNull Annotations To IpSec API Surface This CL adds NonNull annotations to a large number of method returns and parameters as part of API council feedback. Bug: 72473424 Test: compilation (docstring-only change) Merged-In: I2f865dde56fe12116c461ad98e9460bf1802ce18 Change-Id: I2f865dde56fe12116c461ad98e9460bf1802ce18 (cherry picked from commit 8fd26f67fdfdedb535ddb8c7d5ededa5dcba40f8) --- core/java/android/net/IpSecAlgorithm.java | 8 +++-- core/java/android/net/IpSecManager.java | 44 +++++++++++------------ core/java/android/net/IpSecTransform.java | 6 ++++ 3 files changed, 34 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index c69a4d4c0b..d9ac981959 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -122,7 +122,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. */ - public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key) { + public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { this(algorithm, key, key.length * 8); } @@ -137,7 +137,8 @@ public final class IpSecAlgorithm implements Parcelable { * @param key key padded to a multiple of 8 bits. * @param truncLenBits number of bits of output hash to use. */ - public IpSecAlgorithm(@AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { + public IpSecAlgorithm( + @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { mName = algorithm; mKey = key.clone(); mTruncLenBits = truncLenBits; @@ -145,11 +146,13 @@ public final class IpSecAlgorithm implements Parcelable { } /** Get the algorithm name */ + @NonNull public String getName() { return mName; } /** Get the key for this algorithm */ + @NonNull public byte[] getKey() { return mKey.clone(); } @@ -263,6 +266,7 @@ public final class IpSecAlgorithm implements Parcelable { } @Override + @NonNull public String toString() { return new StringBuilder() .append("{mName=") diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index cb4299ef69..4157845d61 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -253,8 +253,9 @@ public final class IpSecManager { * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user */ - public SecurityParameterIndex allocateSecurityParameterIndex(InetAddress destinationAddress) - throws ResourceUnavailableException { + @NonNull + public SecurityParameterIndex allocateSecurityParameterIndex( + @NonNull InetAddress destinationAddress) throws ResourceUnavailableException { try { return new SecurityParameterIndex( mService, @@ -280,8 +281,9 @@ public final class IpSecManager { * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be * reserved */ + @NonNull public SecurityParameterIndex allocateSecurityParameterIndex( - InetAddress destinationAddress, int requestedSpi) + @NonNull InetAddress destinationAddress, int requestedSpi) throws SpiUnavailableException, ResourceUnavailableException { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); @@ -318,9 +320,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - Socket socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull Socket socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -353,9 +354,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - DatagramSocket socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull DatagramSocket socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -388,9 +388,8 @@ public final class IpSecManager { * @param transform a transport mode {@code IpSecTransform} * @throws IOException indicating that the transform could not be applied */ - public void applyTransportModeTransform( - FileDescriptor socket, @PolicyDirection int direction, IpSecTransform transform) - throws IOException { + public void applyTransportModeTransform(@NonNull FileDescriptor socket, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { // We dup() the FileDescriptor here because if we don't, then the ParcelFileDescriptor() // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { @@ -413,8 +412,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(Socket socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { removeTransportModeTransforms(socket.getFileDescriptor$()); } @@ -431,8 +429,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(DatagramSocket socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull DatagramSocket socket) throws IOException { removeTransportModeTransforms(socket.getFileDescriptor$()); } @@ -449,8 +446,7 @@ public final class IpSecManager { * @param socket a socket that previously had a transform applied to it * @throws IOException indicating that the transform could not be removed from the socket */ - public void removeTransportModeTransforms(FileDescriptor socket) - throws IOException { + public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.removeTransportModeTransforms(pfd); } catch (RemoteException e) { @@ -588,6 +584,7 @@ public final class IpSecManager { // safely usable for Encapsulation without allowing a user to possibly unbind from/close // the port, which could potentially impact the traffic of the next user who binds to that // socket. + @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket(int port) throws IOException, ResourceUnavailableException { /* @@ -617,6 +614,7 @@ public final class IpSecManager { // safely usable for Encapsulation without allowing a user to possibly unbind from/close // the port, which could potentially impact the traffic of the next user who binds to that // socket. + @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { return new UdpEncapsulationSocket(mService, 0); @@ -645,6 +643,7 @@ public final class IpSecManager { private int mResourceId = INVALID_RESOURCE_ID; /** Get the underlying SPI held by this object. */ + @NonNull public String getInterfaceName() { return mInterfaceName; } @@ -659,7 +658,7 @@ public final class IpSecManager { * @hide */ @SystemApi - public void addAddress(LinkAddress address) throws IOException { + public void addAddress(@NonNull LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -676,7 +675,7 @@ public final class IpSecManager { * @hide */ @SystemApi - public void removeAddress(LinkAddress address) throws IOException { + public void removeAddress(@NonNull LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); } catch (RemoteException e) { @@ -768,6 +767,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) @@ -794,8 +794,8 @@ public final class IpSecManager { */ @SystemApi @RequiresPermission(android.Manifest.permission.NETWORK_STACK) - public void applyTunnelModeTransform(IpSecTunnelInterface tunnel, - @PolicyDirection int direction, IpSecTransform transform) throws IOException { + public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, + @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId()); diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 60e96f9434..cf58647bbb 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -350,6 +350,7 @@ public final class IpSecTransform implements AutoCloseable { * * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied. */ + @NonNull public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. Preconditions.checkNotNull(algo); @@ -364,6 +365,7 @@ public final class IpSecTransform implements AutoCloseable { * * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied. */ + @NonNull public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. Preconditions.checkNotNull(algo); @@ -384,6 +386,7 @@ public final class IpSecTransform implements AutoCloseable { * @param algo {@link IpSecAlgorithm} specifying the authenticated encryption algorithm to * be applied. */ + @NonNull public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { Preconditions.checkNotNull(algo); mConfig.setAuthenticatedEncryption(algo); @@ -403,6 +406,7 @@ public final class IpSecTransform implements AutoCloseable { * @param remotePort the UDP port number of the remote host that will send and receive * encapsulated traffic. In the case of IKEv2, this should be port 4500. */ + @NonNull public IpSecTransform.Builder setIpv4Encapsulation( @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { Preconditions.checkNotNull(localSocket); @@ -436,6 +440,7 @@ public final class IpSecTransform implements AutoCloseable { * collides with an existing transform * @throws IOException indicating other errors */ + @NonNull public IpSecTransform buildTransportModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) @@ -472,6 +477,7 @@ public final class IpSecTransform implements AutoCloseable { * @hide */ @SystemApi + @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, From 4b3f6f982ef74cc35e914481c94bad4515b0dfbf Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 6 Mar 2018 12:36:54 +0900 Subject: [PATCH 0501/1150] Add method to NetworkStatsService for UID stats. Useful for clients such as BatteryStats which currently rely on NetworkStatsFactory. Data at that stage is incomplete as it does not account for tethering, VT data and corresponding 464xlat corrections. Test: runtest frameworks-net, CTS tests pass. Change-Id: I763b77f601c827fd2963204694fb5b45425cc791 --- .../android/net/INetworkStatsService.aidl | 10 +++ core/java/android/net/NetworkStats.java | 64 +++++++++++++---- .../internal/net/NetworkStatsFactory.java | 72 ++++++++++++++----- .../server/net/NetworkStatsService.java | 38 ++++++++-- 4 files changed, 149 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 90e3ffd550..eab70418a9 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -44,6 +44,16 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); + + /** Get a detailed snapshot of stats since boot for all UIDs. + * + *

            Results will not always be limited to stats on requiredIfaces when specified: stats for + * interfaces stacked on the specified interfaces, or for interfaces on which the specified + * interfaces are stacked on, will also be included. + * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}. + */ + NetworkStats getDetailedUidStats(in String[] requiredIfaces); + /** Return set of any ifaces associated with mobile networks since boot. */ String[] getMobileIfaces(); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 01b2b39213..940f98580c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable { /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ public static final int SET_DBG_VPN_OUT = 1002; + /** Include all interfaces when filtering */ + public static final String[] INTERFACES_ALL = null; + /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; @@ -359,23 +362,27 @@ public class NetworkStats implements Parcelable { capacity = newLength; } - iface[size] = entry.iface; - uid[size] = entry.uid; - set[size] = entry.set; - tag[size] = entry.tag; - metered[size] = entry.metered; - roaming[size] = entry.roaming; - defaultNetwork[size] = entry.defaultNetwork; - rxBytes[size] = entry.rxBytes; - rxPackets[size] = entry.rxPackets; - txBytes[size] = entry.txBytes; - txPackets[size] = entry.txPackets; - operations[size] = entry.operations; + setValues(size, entry); size++; return this; } + private void setValues(int i, Entry entry) { + iface[i] = entry.iface; + uid[i] = entry.uid; + set[i] = entry.set; + tag[i] = entry.tag; + metered[i] = entry.metered; + roaming[i] = entry.roaming; + defaultNetwork[i] = entry.defaultNetwork; + rxBytes[i] = entry.rxBytes; + rxPackets[i] = entry.rxPackets; + txBytes[i] = entry.txBytes; + txPackets[i] = entry.txPackets; + operations[i] = entry.operations; + } + /** * Return specific stats entry. */ @@ -824,6 +831,39 @@ public class NetworkStats implements Parcelable { return stats; } + /** + * Only keep entries that match all specified filters. + * + *

            This mutates the original structure in place. After this method is called, + * size is the number of matching entries, and capacity is the previous capacity. + * @param limitUid UID to filter for, or {@link #UID_ALL}. + * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. + * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + */ + public void filter(int limitUid, String[] limitIfaces, int limitTag) { + if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { + return; + } + + Entry entry = new Entry(); + int nextOutputEntry = 0; + for (int i = 0; i < size; i++) { + entry = getValues(i, entry); + final boolean matches = + (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, entry.iface)); + + if (matches) { + setValues(nextOutputEntry, entry); + nextOutputEntry++; + } + } + + size = nextOutputEntry; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 902bd120e8..8172a20632 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; +import android.annotation.Nullable; import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; -import android.util.ArrayMap; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; -import com.google.android.collect.Lists; import libcore.io.IoUtils; @@ -41,8 +39,10 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Objects; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} @@ -70,18 +70,55 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; - // TODO: to improve testability and avoid global state, do not use a static variable. - @GuardedBy("sStackedIfaces") - private static final ArrayMap sStackedIfaces = new ArrayMap<>(); + // TODO: only do adjustments in NetworkStatsService and remove this. + /** + * (Stacked interface) -> (base interface) association for all connected ifaces since boot. + * + * Because counters must never roll backwards, once a given interface is stacked on top of an + * underlying interface, the stacked interface can never be stacked on top of + * another interface. */ + private static final ConcurrentHashMap sStackedIfaces + = new ConcurrentHashMap<>(); public static void noteStackedIface(String stackedIface, String baseIface) { - synchronized (sStackedIfaces) { - if (baseIface != null) { - sStackedIfaces.put(stackedIface, baseIface); - } else { - sStackedIfaces.remove(stackedIface); + if (stackedIface != null && baseIface != null) { + sStackedIfaces.put(stackedIface, baseIface); + } + } + + /** + * Get a set of interfaces containing specified ifaces and stacked interfaces. + * + *

            The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces + * on which the specified ones are stacked. Stacked interfaces are those noted with + * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method + * is called are guaranteed to be included. + */ + public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) { + if (requiredIfaces == NetworkStats.INTERFACES_ALL) { + return null; + } + + HashSet relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); + // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse + // elements as they existed upon construction exactly once, and may + // (but are not guaranteed to) reflect any modifications subsequent to construction". + // This is enough here. + for (Map.Entry entry : sStackedIfaces.entrySet()) { + if (relatedIfaces.contains(entry.getKey())) { + relatedIfaces.add(entry.getValue()); + } else if (relatedIfaces.contains(entry.getValue())) { + relatedIfaces.add(entry.getKey()); } } + + String[] outArray = new String[relatedIfaces.size()]; + return relatedIfaces.toArray(outArray); + } + + @VisibleForTesting + public static void clearStackedIfaces() { + sStackedIfaces.clear(); } public NetworkStatsFactory() { @@ -250,12 +287,9 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - final ArrayMap stackedIfaces; - synchronized (sStackedIfaces) { - stackedIfaces = new ArrayMap<>(sStackedIfaces); - } // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); + // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. + final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size()); NetworkStats.Entry entry = null; // For recycling @@ -269,7 +303,7 @@ public class NetworkStatsFactory { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; } - final String baseIface = stackedIfaces.get(entry.iface); + final String baseIface = sStackedIfaces.get(entry.iface); if (baseIface == null) { continue; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 82981275fc..e0a86437e0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.SET_ALL; @@ -34,6 +35,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.STATS_PER_IFACE; import static android.net.NetworkStats.STATS_PER_UID; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; @@ -128,6 +130,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -143,6 +146,7 @@ import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; /** * Collect and persist detailed network statistics, and provide this data to @@ -726,7 +730,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long token = Binder.clearCallingIdentity(); final NetworkStats networkLayer; try { - networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid, + NetworkStats.INTERFACES_ALL); } finally { Binder.restoreCallingIdentity(token); } @@ -747,6 +752,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return dataLayer; } + @Override + public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + try { + final String[] ifacesToQuery = + NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces); + return getNetworkStatsUidDetail(ifacesToQuery); + } catch (RemoteException e) { + Log.wtf(TAG, "Error compiling UID stats", e); + return new NetworkStats(0L, 0); + } + } + @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1109,6 +1126,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (isMobile) { mobileIfaces.add(stackedIface); } + + NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } } @@ -1130,7 +1149,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1464,12 +1483,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} * values. + * + * @param ifaces A list of interfaces the stats should be restricted to, or + * {@link NetworkStats#INTERFACES_ALL}. */ - private NetworkStats getNetworkStatsUidDetail() throws RemoteException { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + private NetworkStats getNetworkStatsUidDetail(String[] ifaces) + throws RemoteException { + + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, + ifaces); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); + tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1478,10 +1504,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold video calling data usage stats into uid snapshot final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { + vtStats.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(vtStats); } + uidSnapshot.combineAllValues(mUidOperations); + // TODO: apply tethering & VC 464xlat adjustments here + return uidSnapshot; } From 9a713bd28ec77d361041025496d73a8935621f79 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 21 Mar 2018 15:32:42 -0700 Subject: [PATCH 0502/1150] Add MANAGE_IPSEC_TUNNELS Permission Add a new MANAGE_IPSEC_TUNNELS permission and protect all IPsec Tunnel mode APIs with it. This permission is only granted to the system or through an AppOp. Bug: 66955045 Test: compilation Change-Id: I0f618373b500c493ef2211bece681f74652a1833 --- core/java/android/net/IpSecManager.java | 6 ++++-- core/java/android/net/IpSecTransform.java | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4157845d61..972b9c0746 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -658,6 +658,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); @@ -675,6 +676,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); @@ -768,7 +770,7 @@ public final class IpSecManager { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { @@ -793,7 +795,7 @@ public final class IpSecManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index cf58647bbb..099fe02fdd 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -282,7 +282,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, @@ -325,7 +325,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void stopNattKeepalive() { @@ -478,7 +478,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) From bd313c2e1926f6debff8625028d4a865a69bf3e3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 14 Mar 2018 19:01:14 -0700 Subject: [PATCH 0503/1150] Add documentation for TCP interactions with transforms Updates API documentation to mention that TCP sockets where transforms are deactivated will not send FIN packets. Bug: 74851550 Test: API updates only Change-Id: I8169f221c8c747538a8bddfbf02dcc73c9337189 --- core/java/android/net/IpSecManager.java | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a..246d1e1860 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -299,6 +299,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

            Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

            Rekey Procedure

            * *

            When applying a new tranform to a socket, the previous transform will be removed. However, @@ -364,6 +377,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

            Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

            Rekey Procedure

            * *

            When applying a new tranform to a socket, the previous transform will be removed. However, From 8d66e650a1c2ed67905b6a76694d751cdacf7834 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 26 Mar 2018 13:11:33 -0600 Subject: [PATCH 0504/1150] API council requested tweaks to TrafficStats. Test: atest android.appsecurity.cts.AppSecurityTests#testAppFailAccessPrivateData Bug: 71584606 Change-Id: I4be8a47d54a04f17cbaac735d543ff7d6370376d --- core/java/android/net/TrafficStats.java | 32 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 7922276edb..40d53b741d 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -16,7 +16,6 @@ package android.net; -import android.annotation.RequiresPermission; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -259,22 +258,35 @@ public class TrafficStats { /** * Set specific UID to use when accounting {@link Socket} traffic * originating from the current thread. Designed for use when performing an - * operation on behalf of another application. + * operation on behalf of another application, or when another application + * is performing operations on your behalf. + *

            + * Any app can accept blame for traffic performed on a socket + * originally created by another app by calling this method with the + * {@link android.system.Os#getuid()} value. However, only apps holding the + * {@code android.Manifest.permission#UPDATE_DEVICE_STATS} permission may + * assign blame to another UIDs. *

            * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. - *

            - * To take effect, caller must hold - * {@link android.Manifest.permission#UPDATE_DEVICE_STATS} permission. - * - * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @SuppressLint("Doclava125") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } + /** + * Get the active UID used when accounting {@link Socket} traffic originating + * from the current thread. Only one active tag per thread is supported. + * {@link #tagSocket(Socket)}. + * + * @see #setThreadStatsUid(int) + */ + public static int getThreadStatsUid() { + return NetworkManagementSocketTagger.getThreadSocketStatsUid(); + } + /** * Set specific UID to use when accounting {@link Socket} traffic * originating from the current thread as the calling UID. Designed for use @@ -282,7 +294,11 @@ public class TrafficStats { *

            * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. + * + * @removed + * @deprecated use {@link #setThreadStatsUid(int)} instead. */ + @Deprecated public static void setThreadStatsUidSelf() { setThreadStatsUid(android.os.Process.myUid()); } From 98a09350030930c1add229fa658a4b3902a40be3 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 27 Mar 2018 11:09:16 -0600 Subject: [PATCH 0505/1150] Don't let callers OOM the system process. Constrain our default history size to 180 days; if we end up needing more, we'll dynamically grow the history object. Test: manual Bug: 70916680 Change-Id: Id885f9800ad8f45fb0c1a89dab5a4b10ffd9e2f2 --- .../com/android/server/net/NetworkStatsCollection.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index a5f8dc72d8..2ef754e2ba 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -16,9 +16,9 @@ package com.android.server.net; -import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; +import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.METERED_NO; import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_NO; @@ -42,9 +42,11 @@ import android.service.NetworkStatsCollectionKeyProto; import android.service.NetworkStatsCollectionProto; import android.service.NetworkStatsCollectionStatsProto; import android.telephony.SubscriptionPlan; +import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; +import android.util.MathUtils; import android.util.Pair; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -245,7 +247,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { + " is forbidden for caller " + callerUid); } - final int bucketEstimate = (int) ((end - start) / mBucketDuration); + // 180 days of history should be enough for anyone; if we end up needing + // more, we'll dynamically grow the history object. + final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0, + (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration); final NetworkStatsHistory combined = new NetworkStatsHistory( mBucketDuration, bucketEstimate, fields); From f685da3d66f0202eab363782df993b2991e3cc5c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 14 Mar 2018 19:01:14 -0700 Subject: [PATCH 0506/1150] Add documentation for TCP interactions with transforms Updates API documentation to mention that TCP sockets where transforms are deactivated will not send FIN packets. Bug: 74851550 Test: API updates only Merged-In: I8169f221c8c747538a8bddfbf02dcc73c9337189 Change-Id: I8169f221c8c747538a8bddfbf02dcc73c9337189 (cherry picked from commit bd313c2e1926f6debff8625028d4a865a69bf3e3) --- core/java/android/net/IpSecManager.java | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 972b9c0746..a88fe0428a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -305,6 +305,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

            Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

            Rekey Procedure

            * *

            When applying a new tranform to a socket in the outbound direction, the previous transform @@ -373,6 +386,19 @@ public final class IpSecManager { * will throw IOException if the user deactivates the transform (by calling {@link * IpSecTransform#close()}) without calling {@link #removeTransportModeTransforms}. * + *

            Note that when applied to TCP sockets, calling {@link IpSecTransform#close()} on an + * applied transform before completion of graceful shutdown may result in the shutdown sequence + * failing to complete. As such, applications requiring graceful shutdown MUST close the socket + * prior to deactivating the applied transform. Socket closure may be performed asynchronously + * (in batches), so the returning of a close function does not guarantee shutdown of a socket. + * Setting an SO_LINGER timeout results in socket closure being performed synchronously, and is + * sufficient to ensure shutdown. + * + * Specifically, if the transform is deactivated (by calling {@link IpSecTransform#close()}), + * prior to the socket being closed, the standard [FIN - FIN/ACK - ACK], or the reset [RST] + * packets are dropped due to the lack of a valid Transform. Similarly, if a socket without the + * SO_LINGER option set is closed, the delayed/batched FIN packets may be dropped. + * *

            Rekey Procedure

            * *

            When applying a new tranform to a socket in the outbound direction, the previous transform From b6d036d6b34e019b936e2c6cf7615f7633a4bdc3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Mar 2018 16:55:48 -0700 Subject: [PATCH 0507/1150] Clarify UDP encapsulation socket API This change updates the getSocket() methods for IPsec to improve clarity of the return types, both for public APIs, and internal-only methods. Bug: 72473753 Test: APIs updated, CTS + unit tests ran. Change-Id: I0afebd432c5d04c47c93daa1ce616d712aa323d7 --- core/java/android/net/IpSecManager.java | 6 +++--- services/core/java/com/android/server/IpSecService.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b60984771a..5cdac55799 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -484,7 +484,7 @@ public final class IpSecManager { * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the * caller. The caller should not close the {@code FileDescriptor} returned by {@link - * #getSocket}, but should use {@link #close} instead. + * #getFileDescriptor}, but should use {@link #close} instead. * *

            Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic * of the next user who binds to that port. To prevent this scenario, these sockets are held @@ -523,8 +523,8 @@ public final class IpSecManager { mCloseGuard.open("constructor"); } - /** Get the wrapped socket. */ - public FileDescriptor getSocket() { + /** Get the encapsulation socket's file descriptor. */ + public FileDescriptor getFileDescriptor() { if (mPfd == null) { return null; } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 45a4dfb91b..d9d24c4902 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -934,7 +934,7 @@ public class IpSecService extends IIpSecService.Stub { return mPort; } - public FileDescriptor getSocket() { + public FileDescriptor getFileDescriptor() { return mSocket; } From b477e70aed4774d9f2d8d1a55b8d65624691bb0c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 27 Feb 2018 16:47:22 +0900 Subject: [PATCH 0508/1150] Fix network usage stats on 464xlat tethered. Usage stats corrections for 464xlat in NetworkStatsFactory are not applied to tethered traffic. Add adjustments in NetworkStatsService. After migrating external callers off NetworkStatsFactory, we will be able to only apply adjustments in NetworkStatsService and remove stacked interface tracking from NetworkStatsFactory. Bug: 72107146 Fixes: 72107146 Test: runtest frameworks-net & manual - checked corrected network usage Change-Id: I5ce450e616b4fddf21f2a491fe5d0c9e9f969bda --- core/java/android/net/NetworkStats.java | 75 +++++++++++++++++++ .../internal/net/NetworkStatsFactory.java | 60 ++++----------- .../server/net/NetworkStatsService.java | 8 +- 3 files changed, 92 insertions(+), 51 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 940f98580c..d6cbc88524 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -31,6 +31,7 @@ import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Objects; /** @@ -97,6 +98,11 @@ public class NetworkStats implements Parcelable { /** Denotes a request for stats at the interface and UID level. */ public static final int STATS_PER_UID = 1; + private static final String CLATD_INTERFACE_PREFIX = "v4-"; + // Delta between IPv4 header (20b) and IPv6 header (40b). + // Used for correct stats accounting on clatd interfaces. + private static final int IPV4V6_HEADER_DELTA = 20; + // TODO: move fields to "mVariable" notation /** @@ -751,6 +757,75 @@ public class NetworkStats implements Parcelable { return result; } + /** + * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * + *

            This mutates both base and stacked traffic stats, to account respectively for + * double-counted traffic and IPv4/IPv6 header size difference. + * + *

            For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 + * packet on the stacked interface, and once as translated to an IPv6 packet on the + * base interface. For correct stats accounting on the base interface, every 464xlat + * packet needs to be subtracted from the root UID on the base interface both for tx + * and rx traffic (http://b/12249687, http:/b/33681750). + * + *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only + * {@code ConcurrentHashMap} + * @param baseTraffic Traffic on the base interfaces. Will be mutated. + * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. + * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + */ + public static void apply464xlatAdjustments(NetworkStats baseTraffic, + NetworkStats stackedTraffic, Map stackedIfaces) { + // Total 464xlat traffic to subtract from uid 0 on all base interfaces. + // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. + final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); + + // For recycling + Entry entry = null; + Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); + + for (int i = 0; i < stackedTraffic.size; i++) { + entry = stackedTraffic.getValues(i, entry); + if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; + } + final String baseIface = stackedIfaces.get(entry.iface); + if (baseIface == null) { + continue; + } + // Subtract any 464lat traffic seen for the root UID on the current base interface. + adjust.iface = baseIface; + adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets = -entry.rxPackets; + adjust.txPackets = -entry.txPackets; + adjustments.combineValues(adjust); + + // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent + // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes + // difference for all packets (http://b/12249687, http:/b/33681750). + entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; + entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; + stackedTraffic.setValues(i, entry); + } + + baseTraffic.combineAllValues(adjustments); + } + + /** + * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * + *

            This mutates the object this method is called on. Equivalent to calling + * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as + * base and stacked traffic. + * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + */ + public void apply464xlatAdjustments(Map stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); + } + /** * Return total statistics grouped by {@link #iface}; doesn't mutate the * original structure. diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8172a20632..8561bf0279 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -54,11 +54,6 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; - private static final String CLATD_INTERFACE_PREFIX = "v4-"; - // Delta between IPv4 header (20b) and IPv6 header (40b). - // Used for correct stats accounting on clatd interfaces. - private static final int IPV4V6_HEADER_DELTA = 20; - /** Path to {@code /proc/net/dev}. */ private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ @@ -94,7 +89,7 @@ public class NetworkStatsFactory { * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method * is called are guaranteed to be included. */ - public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) { + public static String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { if (requiredIfaces == NetworkStats.INTERFACES_ALL) { return null; } @@ -116,6 +111,15 @@ public class NetworkStatsFactory { return relatedIfaces.toArray(outArray); } + /** + * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) + */ + public static void apply464xlatAdjustments(NetworkStats baseTraffic, + NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces); + } + @VisibleForTesting public static void clearStackedIfaces() { sStackedIfaces.clear(); @@ -287,48 +291,10 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size()); - NetworkStats.Entry entry = null; // For recycling - - // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - // packet on the stacked interface, and once as translated to an IPv6 packet on the - // base interface. For correct stats accounting on the base interface, every 464xlat - // packet needs to be subtracted from the root UID on the base interface both for tx - // and rx traffic (http://b/12249687, http:/b/33681750). - for (int i = 0; i < stats.size(); i++) { - entry = stats.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = sStackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - - NetworkStats.Entry adjust = - new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - // Subtract any 464lat traffic seen for the root UID on the current base interface. - adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets -= entry.rxPackets; - adjust.txPackets -= entry.txPackets; - adjustments.combineValues(adjust); - - // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent - // on the stacked interface with prefix "v4-" and drops the IPv6 header size after - // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes - // difference for all packets (http://b/12249687, http:/b/33681750). - entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA; - entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA; - entry.rxPackets = 0; - entry.txPackets = 0; - stats.combineValues(entry); - } - - stats.combineAllValues(adjustments); + // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. + // TODO: remove this and only apply adjustments in NetworkStatsService. + stats.apply464xlatAdjustments(sStackedIfaces); return stats; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e0a86437e0..da40692a43 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -146,7 +146,6 @@ import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Map; /** * Collect and persist detailed network statistics, and provide this data to @@ -756,7 +755,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { final String[] ifacesToQuery = - NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces); + NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); @@ -1490,12 +1489,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats getNetworkStatsUidDetail(String[] ifaces) throws RemoteException { + // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here. final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, ifaces); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1505,13 +1506,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats); uidSnapshot.combineAllValues(vtStats); } uidSnapshot.combineAllValues(mUidOperations); - // TODO: apply tethering & VC 464xlat adjustments here - return uidSnapshot; } From 4076b1311de8f59e1163089e167d5ba851c36355 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 28 Mar 2018 08:52:51 -0700 Subject: [PATCH 0509/1150] Disallow Reserved SPI Allocation Disallow the allocation of SPIs in the range reserved for future use by RFC 4303. Bug: 77205120 Test: runtest frameworks-net Change-Id: I05e26ed34b5871f1a07d5bd7b58b79a64cd74b67 --- core/java/android/net/IpSecManager.java | 3 ++- services/core/java/com/android/server/IpSecService.java | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 4157845d61..abf51fa7de 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -274,7 +274,8 @@ public final class IpSecManager { * * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is + * reserved and may not be used. See RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d09a161d1e..70efed2c2b 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1065,7 +1065,10 @@ public class IpSecService extends IIpSecService.Stub { public synchronized IpSecSpiResponse allocateSecurityParameterIndex( String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { checkInetAddress(destinationAddress); - /* requestedSpi can be anything in the int range, so no check is needed. */ + // RFC 4303 Section 2.1 - 0=local, 1-255=reserved. + if (requestedSpi > 0 && requestedSpi < 256) { + throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); + } checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From e6f2de337fea7b77f62585953c51629ab5d56e7a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 28 Mar 2018 13:10:40 -0700 Subject: [PATCH 0510/1150] Require explicitly supplied truncation length Instead of providing default truncation lengths (based on RFC or otherwise), this change imposes a restriction that the truncation length must be supplied for all auth or aead algorithms. Bug: 77204048 Test: Updated tests, ran on walleye Change-Id: I4a0e2e71aa97259e56f44e7c8a2ce53135708d97 --- core/java/android/net/IpSecAlgorithm.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 57f05884ce..8034bb62c9 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -56,7 +56,8 @@ public final class IpSecAlgorithm implements Parcelable { * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Keys for this algorithm must be 128 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 128. */ public static final String AUTH_HMAC_MD5 = "hmac(md5)"; @@ -65,7 +66,8 @@ public final class IpSecAlgorithm implements Parcelable { * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Keys for this algorithm must be 160 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 160. */ public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; @@ -73,7 +75,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA256 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 256 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 256. */ public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -81,7 +84,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA384 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 384 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. + * + *

            Valid truncation lengths are multiples of 8 bits from 192 to 384. */ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; @@ -89,7 +93,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA512 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 512 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. + * + *

            Valid truncation lengths are multiples of 8 bits from 256 to 512. */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; @@ -112,6 +117,7 @@ public final class IpSecAlgorithm implements Parcelable { AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, + AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, AUTH_CRYPT_AES_GCM }) @@ -126,11 +132,14 @@ public final class IpSecAlgorithm implements Parcelable { * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are * defined as constants in this class. * + *

            For algorithms that produce an integrity check value, the truncation length is a required + * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)} + * * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. */ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { - this(algorithm, key, key.length * 8); + this(algorithm, key, 0); } /** @@ -228,6 +237,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; + isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; break; default: throw new IllegalArgumentException("Couldn't find an algorithm: " + name); From 17c972f3c053dff1d5d16e0fa488780f3fcb28dc Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 5 Mar 2018 18:14:56 +0900 Subject: [PATCH 0511/1150] Allow null subscriberId in NetworkStatsManager. Use a MATCH_MOBILE_WILDCARD template to avoid filtering by subscriberId when querying statistics from NetworkStatsService. Bug: 74038898 Change-Id: I8296220472a9ba37044dd1a5ede9bdb45d3ed339 Fixes: 74038898 Test: runtest frameworks-net, CTS tests pass Merged-In: I1e4e283c6eaecf33d12488e41e0c524f6ff83954 Merged-In: Ia84d2c7cc63bf8b8bf30f133e0382fd7103bf490 (cherry-picked from aosp I4b39e7031416cb33b23d89aa36ff0f774eaa942f) --- core/java/android/app/usage/NetworkStats.java | 6 +-- .../app/usage/NetworkStatsManager.java | 40 ++++++++++++------- 2 files changed, 27 insertions(+), 19 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index da36157d85..e315e9115f 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -24,7 +24,6 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.RemoteException; -import android.os.ServiceManager; import android.util.IntArray; import android.util.Log; @@ -98,9 +97,8 @@ public final class NetworkStats implements AutoCloseable { /** @hide */ NetworkStats(Context context, NetworkTemplate template, int flags, long startTimestamp, - long endTimestamp) throws RemoteException, SecurityException { - final INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + long endTimestamp, INetworkStatsService statsService) + throws RemoteException, SecurityException { // Open network stats session mSession = statsService.openSessionForUsageStats(flags, context.getOpPackageName()); mCloseGuard.open("close"); diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5576e86edd..2357637b72 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -37,6 +37,8 @@ import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; + /** * Provides access to network usage history and statistics. Usage data is collected in * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. @@ -107,9 +109,15 @@ public class NetworkStatsManager { * {@hide} */ public NetworkStatsManager(Context context) throws ServiceNotFoundException { + this(context, INetworkStatsService.Stub.asInterface( + ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); + } + + /** @hide */ + @VisibleForTesting + public NetworkStatsManager(Context context, INetworkStatsService service) { mContext = context; - mService = INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE)); + mService = service; setPollOnOpen(true); } @@ -135,7 +143,8 @@ public class NetworkStatsManager { public Bucket querySummaryForDevice(NetworkTemplate template, long startTime, long endTime) throws SecurityException, RemoteException { Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, + mService); bucket = stats.getDeviceSummaryForNetwork(); stats.close(); @@ -208,7 +217,7 @@ public class NetworkStatsManager { } NetworkStats stats; - stats = new NetworkStats(mContext, template, mFlags, startTime, endTime); + stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); stats.startSummaryEnumeration(); stats.close(); @@ -245,7 +254,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startSummaryEnumeration(); return result; @@ -295,7 +304,7 @@ public class NetworkStatsManager { NetworkStats result; try { - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startHistoryEnumeration(uid, tag); } catch (RemoteException e) { Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e); @@ -341,7 +350,7 @@ public class NetworkStatsManager { } NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime); + result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startUserUidEnumeration(); return result; } @@ -451,19 +460,20 @@ public class NetworkStatsManager { } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { - NetworkTemplate template = null; + final NetworkTemplate template; switch (networkType) { - case ConnectivityManager.TYPE_MOBILE: { - template = NetworkTemplate.buildTemplateMobileAll(subscriberId); - } break; - case ConnectivityManager.TYPE_WIFI: { + case ConnectivityManager.TYPE_MOBILE: + template = subscriberId == null + ? NetworkTemplate.buildTemplateMobileWildcard() + : NetworkTemplate.buildTemplateMobileAll(subscriberId); + break; + case ConnectivityManager.TYPE_WIFI: template = NetworkTemplate.buildTemplateWifiWildcard(); - } break; - default: { + break; + default: throw new IllegalArgumentException("Cannot create template for network type " + networkType + ", subscriberId '" + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); - } } return template; } From 8fcf85d6b884b374ee8c11aed454d81f92f85312 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 27 Mar 2018 16:55:48 -0700 Subject: [PATCH 0512/1150] Clarify UDP encapsulation socket API This change updates the getSocket() methods for IPsec to improve clarity of the return types, both for public APIs, and internal-only methods. Bug: 72473753 Test: APIs updated, CTS + unit tests ran. Merged-In: I0afebd432c5d04c47c93daa1ce616d712aa323d7 Change-Id: I0afebd432c5d04c47c93daa1ce616d712aa323d7 (cherry picked from commit b6d036d6b34e019b936e2c6cf7615f7633a4bdc3) --- core/java/android/net/IpSecManager.java | 6 +++--- services/core/java/com/android/server/IpSecService.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index a88fe0428a..c7234e3165 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -502,7 +502,7 @@ public final class IpSecManager { * signalling and UDP encapsulated IPsec traffic. Instances can be obtained by calling {@link * IpSecManager#openUdpEncapsulationSocket}. The provided socket cannot be re-bound by the * caller. The caller should not close the {@code FileDescriptor} returned by {@link - * #getSocket}, but should use {@link #close} instead. + * #getFileDescriptor}, but should use {@link #close} instead. * *

            Allowing the user to close or unbind a UDP encapsulation socket could impact the traffic * of the next user who binds to that port. To prevent this scenario, these sockets are held @@ -541,8 +541,8 @@ public final class IpSecManager { mCloseGuard.open("constructor"); } - /** Get the wrapped socket. */ - public FileDescriptor getSocket() { + /** Get the encapsulation socket's file descriptor. */ + public FileDescriptor getFileDescriptor() { if (mPfd == null) { return null; } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d09a161d1e..06c10564ab 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -931,7 +931,7 @@ public class IpSecService extends IIpSecService.Stub { return mPort; } - public FileDescriptor getSocket() { + public FileDescriptor getFileDescriptor() { return mSocket; } From 73ed7b3c8a3e727bdeb161143e033517a48be88c Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 28 Mar 2018 13:10:40 -0700 Subject: [PATCH 0513/1150] Require explicitly supplied truncation length Instead of providing default truncation lengths (based on RFC or otherwise), this change imposes a restriction that the truncation length must be supplied for all auth or aead algorithms. Bug: 77204048 Test: Updated tests, ran on walleye Merged-In: I4a0e2e71aa97259e56f44e7c8a2ce53135708d97 Change-Id: I4a0e2e71aa97259e56f44e7c8a2ce53135708d97 (cherry picked from commit e6f2de337fea7b77f62585953c51629ab5d56e7a) --- core/java/android/net/IpSecAlgorithm.java | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 57f05884ce..8034bb62c9 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -56,7 +56,8 @@ public final class IpSecAlgorithm implements Parcelable { * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Keys for this algorithm must be 128 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 128. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 128. */ public static final String AUTH_HMAC_MD5 = "hmac(md5)"; @@ -65,7 +66,8 @@ public final class IpSecAlgorithm implements Parcelable { * new applications and is provided for legacy compatibility with 3gpp infrastructure. * *

            Keys for this algorithm must be 160 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 160. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 160. */ public static final String AUTH_HMAC_SHA1 = "hmac(sha1)"; @@ -73,7 +75,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA256 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 256 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 96 to (default) 256. + * + *

            Valid truncation lengths are multiples of 8 bits from 96 to 256. */ public static final String AUTH_HMAC_SHA256 = "hmac(sha256)"; @@ -81,7 +84,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA384 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 384 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 192 to (default) 384. + * + *

            Valid truncation lengths are multiples of 8 bits from 192 to 384. */ public static final String AUTH_HMAC_SHA384 = "hmac(sha384)"; @@ -89,7 +93,8 @@ public final class IpSecAlgorithm implements Parcelable { * SHA512 HMAC Authentication/Integrity Algorithm. * *

            Keys for this algorithm must be 512 bits in length. - *

            Valid truncation lengths are multiples of 8 bits from 256 to (default) 512. + * + *

            Valid truncation lengths are multiples of 8 bits from 256 to 512. */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; @@ -112,6 +117,7 @@ public final class IpSecAlgorithm implements Parcelable { AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, + AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, AUTH_CRYPT_AES_GCM }) @@ -126,11 +132,14 @@ public final class IpSecAlgorithm implements Parcelable { * Creates an IpSecAlgorithm of one of the supported types. Supported algorithm names are * defined as constants in this class. * + *

            For algorithms that produce an integrity check value, the truncation length is a required + * parameter. See {@link #IpSecAlgorithm(String algorithm, byte[] key, int truncLenBits)} + * * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. */ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { - this(algorithm, key, key.length * 8); + this(algorithm, key, 0); } /** @@ -228,6 +237,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; + isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; break; default: throw new IllegalArgumentException("Couldn't find an algorithm: " + name); From b3b460821b8ccdff6459d25e2d49091685a30ae5 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 28 Mar 2018 08:52:51 -0700 Subject: [PATCH 0514/1150] Disallow Reserved SPI Allocation Disallow the allocation of SPIs in the range reserved for future use by RFC 4303. Bug: 77205120 Test: runtest frameworks-net Merged-In: I05e26ed34b5871f1a07d5bd7b58b79a64cd74b67 Change-Id: I05e26ed34b5871f1a07d5bd7b58b79a64cd74b67 (cherry picked from commit 4076b1311de8f59e1163089e167d5ba851c36355) --- core/java/android/net/IpSecManager.java | 3 ++- services/core/java/com/android/server/IpSecService.java | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index c7234e3165..1525508326 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -274,7 +274,8 @@ public final class IpSecManager { * * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI + * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is + * reserved and may not be used. See RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 06c10564ab..bde6bd8db6 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1065,7 +1065,10 @@ public class IpSecService extends IIpSecService.Stub { public synchronized IpSecSpiResponse allocateSecurityParameterIndex( String destinationAddress, int requestedSpi, IBinder binder) throws RemoteException { checkInetAddress(destinationAddress); - /* requestedSpi can be anything in the int range, so no check is needed. */ + // RFC 4303 Section 2.1 - 0=local, 1-255=reserved. + if (requestedSpi > 0 && requestedSpi < 256) { + throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); + } checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From 55fc224c70bf34a0acc8a76b0d729a96b229b57d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 6 Mar 2018 12:36:54 +0900 Subject: [PATCH 0515/1150] Add method to NetworkStatsService for UID stats. Useful for clients such as BatteryStats which currently rely on NetworkStatsFactory. Data at that stage is incomplete as it does not account for tethering, VT data and corresponding 464xlat corrections. Test: runtest frameworks-net, CTS tests pass. Bug: b/72107146 Merged-In: I31c5b9b4a7c6e72910152415894a137f000a5858 Merged-In: I2527d95000c7500c824ede70f87ecb38e21ed323 (cherry picked from aosp 4b3f6f982ef74cc35e914481c94bad4515b0dfbf) Change-Id: Ie80f1bb21124241f3414f9be77aceac9a44ec6d1 --- .../android/net/INetworkStatsService.aidl | 10 +++ core/java/android/net/NetworkStats.java | 64 +++++++++++++---- .../internal/net/NetworkStatsFactory.java | 72 ++++++++++++++----- .../server/net/NetworkStatsService.java | 38 ++++++++-- 4 files changed, 149 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 381cfb61de..8e6f272388 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -41,6 +41,16 @@ interface INetworkStatsService { /** Return data layer snapshot of UID network usage. */ NetworkStats getDataLayerSnapshotForUid(int uid); + + /** Get a detailed snapshot of stats since boot for all UIDs. + * + *

            Results will not always be limited to stats on requiredIfaces when specified: stats for + * interfaces stacked on the specified interfaces, or for interfaces on which the specified + * interfaces are stacked on, will also be included. + * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}. + */ + NetworkStats getDetailedUidStats(in String[] requiredIfaces); + /** Return set of any ifaces associated with mobile networks since boot. */ String[] getMobileIfaces(); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 16fb858a58..292bf8e196 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -64,6 +64,9 @@ public class NetworkStats implements Parcelable { /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */ public static final int SET_DBG_VPN_OUT = 1002; + /** Include all interfaces when filtering */ + public static final String[] INTERFACES_ALL = null; + /** {@link #tag} value for total data across all tags. */ // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; @@ -366,23 +369,27 @@ public class NetworkStats implements Parcelable { capacity = newLength; } - iface[size] = entry.iface; - uid[size] = entry.uid; - set[size] = entry.set; - tag[size] = entry.tag; - metered[size] = entry.metered; - roaming[size] = entry.roaming; - defaultNetwork[size] = entry.defaultNetwork; - rxBytes[size] = entry.rxBytes; - rxPackets[size] = entry.rxPackets; - txBytes[size] = entry.txBytes; - txPackets[size] = entry.txPackets; - operations[size] = entry.operations; + setValues(size, entry); size++; return this; } + private void setValues(int i, Entry entry) { + iface[i] = entry.iface; + uid[i] = entry.uid; + set[i] = entry.set; + tag[i] = entry.tag; + metered[i] = entry.metered; + roaming[i] = entry.roaming; + defaultNetwork[i] = entry.defaultNetwork; + rxBytes[i] = entry.rxBytes; + rxPackets[i] = entry.rxPackets; + txBytes[i] = entry.txBytes; + txPackets[i] = entry.txPackets; + operations[i] = entry.operations; + } + /** * Return specific stats entry. */ @@ -831,6 +838,39 @@ public class NetworkStats implements Parcelable { return stats; } + /** + * Only keep entries that match all specified filters. + * + *

            This mutates the original structure in place. After this method is called, + * size is the number of matching entries, and capacity is the previous capacity. + * @param limitUid UID to filter for, or {@link #UID_ALL}. + * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. + * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + */ + public void filter(int limitUid, String[] limitIfaces, int limitTag) { + if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { + return; + } + + Entry entry = new Entry(); + int nextOutputEntry = 0; + for (int i = 0; i < size; i++) { + entry = getValues(i, entry); + final boolean matches = + (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, entry.iface)); + + if (matches) { + setValues(nextOutputEntry, entry); + nextOutputEntry++; + } + } + + size = nextOutputEntry; + } + public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 43abadec0d..0cf5375076 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -22,16 +22,14 @@ import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; +import android.annotation.Nullable; import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; -import android.util.ArrayMap; -import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; -import com.google.android.collect.Lists; import libcore.io.IoUtils; @@ -41,8 +39,10 @@ import java.io.FileInputStream; import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; -import java.util.ArrayList; -import java.util.Objects; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * Creates {@link NetworkStats} instances by parsing various {@code /proc/} @@ -72,18 +72,55 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; - // TODO: to improve testability and avoid global state, do not use a static variable. - @GuardedBy("sStackedIfaces") - private static final ArrayMap sStackedIfaces = new ArrayMap<>(); + // TODO: only do adjustments in NetworkStatsService and remove this. + /** + * (Stacked interface) -> (base interface) association for all connected ifaces since boot. + * + * Because counters must never roll backwards, once a given interface is stacked on top of an + * underlying interface, the stacked interface can never be stacked on top of + * another interface. */ + private static final ConcurrentHashMap sStackedIfaces + = new ConcurrentHashMap<>(); public static void noteStackedIface(String stackedIface, String baseIface) { - synchronized (sStackedIfaces) { - if (baseIface != null) { - sStackedIfaces.put(stackedIface, baseIface); - } else { - sStackedIfaces.remove(stackedIface); + if (stackedIface != null && baseIface != null) { + sStackedIfaces.put(stackedIface, baseIface); + } + } + + /** + * Get a set of interfaces containing specified ifaces and stacked interfaces. + * + *

            The added stacked interfaces are ifaces stacked on top of the specified ones, or ifaces + * on which the specified ones are stacked. Stacked interfaces are those noted with + * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method + * is called are guaranteed to be included. + */ + public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) { + if (requiredIfaces == NetworkStats.INTERFACES_ALL) { + return null; + } + + HashSet relatedIfaces = new HashSet<>(Arrays.asList(requiredIfaces)); + // ConcurrentHashMap's EntrySet iterators are "guaranteed to traverse + // elements as they existed upon construction exactly once, and may + // (but are not guaranteed to) reflect any modifications subsequent to construction". + // This is enough here. + for (Map.Entry entry : sStackedIfaces.entrySet()) { + if (relatedIfaces.contains(entry.getKey())) { + relatedIfaces.add(entry.getValue()); + } else if (relatedIfaces.contains(entry.getValue())) { + relatedIfaces.add(entry.getKey()); } } + + String[] outArray = new String[relatedIfaces.size()]; + return relatedIfaces.toArray(outArray); + } + + @VisibleForTesting + public static void clearStackedIfaces() { + sStackedIfaces.clear(); } public NetworkStatsFactory() { @@ -252,12 +289,9 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - final ArrayMap stackedIfaces; - synchronized (sStackedIfaces) { - stackedIfaces = new ArrayMap<>(sStackedIfaces); - } // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); + // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. + final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size()); NetworkStats.Entry entry = null; // For recycling @@ -271,7 +305,7 @@ public class NetworkStatsFactory { if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { continue; } - final String baseIface = stackedIfaces.get(entry.iface); + final String baseIface = sStackedIfaces.get(entry.iface); if (baseIface == null) { continue; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 93c04fe206..57828ca5dc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.SET_ALL; @@ -34,6 +35,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.SET_FOREGROUND; import static android.net.NetworkStats.STATS_PER_IFACE; import static android.net.NetworkStats.STATS_PER_UID; +import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; @@ -127,6 +129,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; @@ -145,6 +148,7 @@ import java.time.ZoneOffset; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Map; /** * Collect and persist detailed network statistics, and provide this data to @@ -739,7 +743,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long token = Binder.clearCallingIdentity(); final NetworkStats networkLayer; try { - networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid); + networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid, + NetworkStats.INTERFACES_ALL); } finally { Binder.restoreCallingIdentity(token); } @@ -760,6 +765,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return dataLayer; } + @Override + public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + try { + final String[] ifacesToQuery = + NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces); + return getNetworkStatsUidDetail(ifacesToQuery); + } catch (RemoteException e) { + Log.wtf(TAG, "Error compiling UID stats", e); + return new NetworkStats(0L, 0); + } + } + @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1119,6 +1136,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (isMobile) { mobileIfaces.add(stackedIface); } + + NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); } } } @@ -1141,7 +1160,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. - final NetworkStats uidSnapshot = getNetworkStatsUidDetail(); + final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); final NetworkStats xtSnapshot = getNetworkStatsXt(); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); @@ -1501,12 +1520,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} * values. + * + * @param ifaces A list of interfaces the stats should be restricted to, or + * {@link NetworkStats#INTERFACES_ALL}. */ - private NetworkStats getNetworkStatsUidDetail() throws RemoteException { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL); + private NetworkStats getNetworkStatsUidDetail(String[] ifaces) + throws RemoteException { + + final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, + ifaces); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); + tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1515,10 +1541,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold video calling data usage stats into uid snapshot final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { + vtStats.filter(UID_ALL, ifaces, TAG_ALL); uidSnapshot.combineAllValues(vtStats); } + uidSnapshot.combineAllValues(mUidOperations); + // TODO: apply tethering & VC 464xlat adjustments here + return uidSnapshot; } From 76d2f53927826ac4a159479e32fc1944d6f39bed Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 2 Apr 2018 16:48:31 +0900 Subject: [PATCH 0516/1150] Allow applications to query for foreground/background data usage. Currently the NetworkStatsManager APIs allow applications to query for their own data usage by UID and tag, but do not allow applications to query by foreground/background state. This is causing popular apps to resort to parsing xt_qtaguid stats files directly. Because this is no longer allowed for apps targeting P and above, provide replacement functionality. This API allows apps to query for data usage for a given state, but not to receive data usage broken down by state. This is consistent with how the current UID and tag APIs work. It is also not an undue burden on apps: there are currently only two states of interest (FOREGROUND and everything else), and even if we add states in the future, unmodified apps can still obtain total traffic using STATE_ALL. Bug: 72977484 Test: New CTS test added in other change in this topic. Change-Id: Ic8c9194569ffd599b49e4a8197c5c2ea0ec3f7f7 --- core/java/android/app/usage/NetworkStats.java | 35 ++++++++++------- .../app/usage/NetworkStatsManager.java | 38 ++++++++++++------- 2 files changed, 47 insertions(+), 26 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index e315e9115f..7252f028d7 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -67,6 +67,11 @@ public final class NetworkStats implements AutoCloseable { */ private int mTag = android.net.NetworkStats.TAG_NONE; + /** + * State in case it was not specified in the query. + */ + private int mState = Bucket.STATE_ALL; + /** * The session while the query requires it, null if all the stats have been collected or close() * has been called. @@ -267,6 +272,15 @@ public final class NetworkStats implements AutoCloseable { private long mTxBytes; private long mTxPackets; + private static int convertSet(@State int state) { + switch (state) { + case STATE_ALL: return android.net.NetworkStats.SET_ALL; + case STATE_DEFAULT: return android.net.NetworkStats.SET_DEFAULT; + case STATE_FOREGROUND: return android.net.NetworkStats.SET_FOREGROUND; + } + return 0; + } + private static @State int convertState(int networkStatsSet) { switch (networkStatsSet) { case android.net.NetworkStats.SET_ALL : return STATE_ALL; @@ -527,20 +541,13 @@ public final class NetworkStats implements AutoCloseable { /** * Collects history results for uid and resets history enumeration index. */ - void startHistoryEnumeration(int uid) { - startHistoryEnumeration(uid, android.net.NetworkStats.TAG_NONE); - } - - /** - * Collects history results for uid and resets history enumeration index. - */ - void startHistoryEnumeration(int uid, int tag) { + void startHistoryEnumeration(int uid, int tag, int state) { mHistory = null; try { mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, - android.net.NetworkStats.SET_ALL, tag, - NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); - setSingleUidTag(uid, tag); + Bucket.convertSet(state), tag, NetworkStatsHistory.FIELD_ALL, + mStartTimeStamp, mEndTimeStamp); + setSingleUidTagState(uid, tag, state); } catch (RemoteException e) { Log.w(TAG, e); // Leaving mHistory null @@ -636,6 +643,7 @@ public final class NetworkStats implements AutoCloseable { fillBucketFromSummaryEntry(bucket); return bucket; } + /** * Getting the next item in a history enumeration. * @param bucketOut Next item will be set here. @@ -648,7 +656,7 @@ public final class NetworkStats implements AutoCloseable { mRecycledHistoryEntry); bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); - bucketOut.mState = Bucket.STATE_ALL; + bucketOut.mState = mState; bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL; bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; @@ -691,9 +699,10 @@ public final class NetworkStats implements AutoCloseable { return mUidOrUidIndex; } - private void setSingleUidTag(int uid, int tag) { + private void setSingleUidTagState(int uid, int tag, int state) { mUidOrUidIndex = uid; mTag = tag; + mState = state; } private void stepUid() { diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 2357637b72..b2fe958691 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -263,20 +263,31 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid. * - * #see queryDetailsForUidTag(int, String, long, long, int, int) + * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) */ public NetworkStats queryDetailsForUid(int networkType, String subscriberId, - long startTime, long endTime, int uid) throws SecurityException, RemoteException { - return queryDetailsForUidTag(networkType, subscriberId, startTime, endTime, uid, - NetworkStats.Bucket.TAG_NONE); + long startTime, long endTime, int uid) throws SecurityException { + return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, + NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); } /** - * Query network usage statistics details for a given uid and tag. Only usable for uids - * belonging to calling user. Result is aggregated over state but not aggregated over time. - * This means buckets' start and end timestamps are going to be between 'startTime' and - * 'endTime' parameters. State is going to be {@link NetworkStats.Bucket#STATE_ALL}, uid the - * same as the 'uid' parameter and tag the same as 'tag' parameter. + * Query network usage statistics details for a given uid and tag. + * + * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) + */ + public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, + long startTime, long endTime, int uid, int tag) throws SecurityException { + return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, + tag, NetworkStats.Bucket.STATE_ALL); + } + + /** + * Query network usage statistics details for a given uid, tag, and state. Only usable for uids + * belonging to calling user. Result is not aggregated over time. This means buckets' start and + * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going + * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state + * the same as the 'state' parameter. * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. @@ -297,17 +308,18 @@ public class NetworkStatsManager { * @return Statistics object or null if an error happened during statistics collection. * @throws SecurityException if permissions are insufficient to read network statistics. */ - public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, - long startTime, long endTime, int uid, int tag) throws SecurityException { + public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, + long startTime, long endTime, int uid, int tag, int state) throws SecurityException { NetworkTemplate template; template = createTemplate(networkType, subscriberId); NetworkStats result; try { result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryEnumeration(uid, tag); + result.startHistoryEnumeration(uid, tag, state); } catch (RemoteException e) { - Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag, e); + Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag + + " state=" + state, e); return null; } From f2822d3a239278a8a77849d3d62ce35551160257 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 27 Feb 2018 16:47:22 +0900 Subject: [PATCH 0517/1150] Fix network usage stats on 464xlat tethered. Usage stats corrections for 464xlat in NetworkStatsFactory are not applied to tethered traffic. Add adjustments in NetworkStatsService. After migrating external callers off NetworkStatsFactory, we will be able to only apply adjustments in NetworkStatsService and remove stacked interface tracking from NetworkStatsFactory. Bug: 72107146 Fixes: 72107146 Test: runtest frameworks-net & manual - checked corrected network usage Merged-In: Ieb25c41c651499fdd01225ae5ac21d95e3d823f5 Merged-In: I016722f3a0ae2ae0a1d48bfacc4fe07ee3578ef7 (cherry-pick of aosp I5ce450e616b4fddf21f2a491fe5d0c9e9f969bda) Change-Id: Id41cf22a0f9a63cb1832e9375bfb045861f08e52 --- core/java/android/net/NetworkStats.java | 75 +++++++++++++++++++ .../internal/net/NetworkStatsFactory.java | 60 ++++----------- .../server/net/NetworkStatsService.java | 8 +- 3 files changed, 92 insertions(+), 51 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 292bf8e196..f0dd2629f9 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -31,6 +31,7 @@ import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Objects; /** @@ -97,6 +98,11 @@ public class NetworkStats implements Parcelable { /** Denotes a request for stats at the interface and UID level. */ public static final int STATS_PER_UID = 1; + private static final String CLATD_INTERFACE_PREFIX = "v4-"; + // Delta between IPv4 header (20b) and IPv6 header (40b). + // Used for correct stats accounting on clatd interfaces. + private static final int IPV4V6_HEADER_DELTA = 20; + // TODO: move fields to "mVariable" notation /** @@ -758,6 +764,75 @@ public class NetworkStats implements Parcelable { return result; } + /** + * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * + *

            This mutates both base and stacked traffic stats, to account respectively for + * double-counted traffic and IPv4/IPv6 header size difference. + * + *

            For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 + * packet on the stacked interface, and once as translated to an IPv6 packet on the + * base interface. For correct stats accounting on the base interface, every 464xlat + * packet needs to be subtracted from the root UID on the base interface both for tx + * and rx traffic (http://b/12249687, http:/b/33681750). + * + *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only + * {@code ConcurrentHashMap} + * @param baseTraffic Traffic on the base interfaces. Will be mutated. + * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. + * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + */ + public static void apply464xlatAdjustments(NetworkStats baseTraffic, + NetworkStats stackedTraffic, Map stackedIfaces) { + // Total 464xlat traffic to subtract from uid 0 on all base interfaces. + // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. + final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); + + // For recycling + Entry entry = null; + Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); + + for (int i = 0; i < stackedTraffic.size; i++) { + entry = stackedTraffic.getValues(i, entry); + if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { + continue; + } + final String baseIface = stackedIfaces.get(entry.iface); + if (baseIface == null) { + continue; + } + // Subtract any 464lat traffic seen for the root UID on the current base interface. + adjust.iface = baseIface; + adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets = -entry.rxPackets; + adjust.txPackets = -entry.txPackets; + adjustments.combineValues(adjust); + + // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent + // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes + // difference for all packets (http://b/12249687, http:/b/33681750). + entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; + entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; + stackedTraffic.setValues(i, entry); + } + + baseTraffic.combineAllValues(adjustments); + } + + /** + * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * + *

            This mutates the object this method is called on. Equivalent to calling + * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as + * base and stacked traffic. + * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + */ + public void apply464xlatAdjustments(Map stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); + } + /** * Return total statistics grouped by {@link #iface}; doesn't mutate the * original structure. diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 0cf5375076..98afebc51b 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -56,11 +56,6 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; - private static final String CLATD_INTERFACE_PREFIX = "v4-"; - // Delta between IPv4 header (20b) and IPv6 header (40b). - // Used for correct stats accounting on clatd interfaces. - private static final int IPV4V6_HEADER_DELTA = 20; - /** Path to {@code /proc/net/dev}. */ private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ @@ -96,7 +91,7 @@ public class NetworkStatsFactory { * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method * is called are guaranteed to be included. */ - public static String[] augmentWithStackedInterfacesLocked(@Nullable String[] requiredIfaces) { + public static String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { if (requiredIfaces == NetworkStats.INTERFACES_ALL) { return null; } @@ -118,6 +113,15 @@ public class NetworkStatsFactory { return relatedIfaces.toArray(outArray); } + /** + * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) + */ + public static void apply464xlatAdjustments(NetworkStats baseTraffic, + NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces); + } + @VisibleForTesting public static void clearStackedIfaces() { sStackedIfaces.clear(); @@ -289,48 +293,10 @@ public class NetworkStatsFactory { NetworkStats lastStats) throws IOException { final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // sStackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, sStackedIfaces.size()); - NetworkStats.Entry entry = null; // For recycling - - // For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - // packet on the stacked interface, and once as translated to an IPv6 packet on the - // base interface. For correct stats accounting on the base interface, every 464xlat - // packet needs to be subtracted from the root UID on the base interface both for tx - // and rx traffic (http://b/12249687, http:/b/33681750). - for (int i = 0; i < stats.size(); i++) { - entry = stats.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = sStackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - - NetworkStats.Entry adjust = - new NetworkStats.Entry(baseIface, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - // Subtract any 464lat traffic seen for the root UID on the current base interface. - adjust.rxBytes -= (entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.txBytes -= (entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets -= entry.rxPackets; - adjust.txPackets -= entry.txPackets; - adjustments.combineValues(adjust); - - // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent - // on the stacked interface with prefix "v4-" and drops the IPv6 header size after - // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes - // difference for all packets (http://b/12249687, http:/b/33681750). - entry.rxBytes = entry.rxPackets * IPV4V6_HEADER_DELTA; - entry.txBytes = entry.txPackets * IPV4V6_HEADER_DELTA; - entry.rxPackets = 0; - entry.txPackets = 0; - stats.combineValues(entry); - } - - stats.combineAllValues(adjustments); + // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. + // TODO: remove this and only apply adjustments in NetworkStatsService. + stats.apply464xlatAdjustments(sStackedIfaces); return stats; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 57828ca5dc..4e848f8f36 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -148,7 +148,6 @@ import java.time.ZoneOffset; import java.util.Arrays; import java.util.HashSet; import java.util.List; -import java.util.Map; /** * Collect and persist detailed network statistics, and provide this data to @@ -769,7 +768,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { final String[] ifacesToQuery = - NetworkStatsFactory.augmentWithStackedInterfacesLocked(requiredIfaces); + NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); @@ -1527,12 +1526,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats getNetworkStatsUidDetail(String[] ifaces) throws RemoteException { + // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here. final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, ifaces); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1542,13 +1543,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats); uidSnapshot.combineAllValues(vtStats); } uidSnapshot.combineAllValues(mUidOperations); - // TODO: apply tethering & VC 464xlat adjustments here - return uidSnapshot; } From a10a7f99c4b3de81bbbd246eeecc95d77730aced Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 15 Mar 2018 18:06:06 -0700 Subject: [PATCH 0518/1150] Add AppOps Checks for MANAGE_IPSEC_TUNNELS Adds support for a new AppOp to permit services to use IpSec tunnel mode. The IpSecService now needs a context so change the service mode to a cached service rather than a static service. Bug: 66955045 Test: runtest frameworks-net Change-Id: I17a4a286225b432c3e15ea1587d946189931b4f4 --- core/java/android/net/IIpSecService.aidl | 20 ++++--- core/java/android/net/IpSecManager.java | 25 +++++--- core/java/android/net/IpSecTransform.java | 3 +- .../java/com/android/server/IpSecService.java | 59 ++++++++++++++----- 4 files changed, 76 insertions(+), 31 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3a3ddcc483..d6774d47b4 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -45,25 +45,31 @@ interface IIpSecService in String localAddr, in String remoteAddr, in Network underlyingNetwork, - in IBinder binder); + in IBinder binder, + in String callingPackage); void addAddressToTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); void removeAddressFromTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); - void deleteTunnelInterface(int resourceId); + void deleteTunnelInterface(int resourceId, in String callingPackage); - IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder); + IpSecTransformResponse createTransform( + in IpSecConfig c, in IBinder binder, in String callingPackage); void deleteTransform(int transformId); - void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); + void applyTransportModeTransform( + in ParcelFileDescriptor socket, int direction, int transformId); - void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId); + void applyTunnelModeTransform( + int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 1525508326..e0654fde6e 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -140,6 +140,7 @@ public final class IpSecManager { } } + private final Context mContext; private final IIpSecService mService; /** @@ -661,6 +662,7 @@ public final class IpSecManager { */ @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { + private final String mOpPackageName; private final IIpSecService mService; private final InetAddress mRemoteAddress; private final InetAddress mLocalAddress; @@ -688,7 +690,8 @@ public final class IpSecManager { @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull LinkAddress address) throws IOException { try { - mService.addAddressToTunnelInterface(mResourceId, address); + mService.addAddressToTunnelInterface( + mResourceId, address, mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -706,16 +709,18 @@ public final class IpSecManager { @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull LinkAddress address) throws IOException { try { - mService.removeAddressFromTunnelInterface(mResourceId, address); + mService.removeAddressFromTunnelInterface( + mResourceId, address, mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private IpSecTunnelInterface(@NonNull IIpSecService service, + private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { + mOpPackageName = ctx.getOpPackageName(); mService = service; mLocalAddress = localAddress; mRemoteAddress = remoteAddress; @@ -727,7 +732,8 @@ public final class IpSecManager { localAddress.getHostAddress(), remoteAddress.getHostAddress(), underlyingNetwork, - new Binder()); + new Binder(), + mOpPackageName); switch (result.status) { case Status.OK: break; @@ -756,7 +762,7 @@ public final class IpSecManager { @Override public void close() { try { - mService.deleteTunnelInterface(mResourceId); + mService.deleteTunnelInterface(mResourceId, mOpPackageName); mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -801,7 +807,8 @@ public final class IpSecManager { public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { - return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); + return new IpSecTunnelInterface( + mContext, mService, localAddress, remoteAddress, underlyingNetwork); } /** @@ -827,7 +834,8 @@ public final class IpSecManager { @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( - tunnel.getResourceId(), direction, transform.getResourceId()); + tunnel.getResourceId(), direction, + transform.getResourceId(), mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -839,7 +847,8 @@ public final class IpSecManager { * @param context the application context for this manager * @hide */ - public IpSecManager(IIpSecService service) { + public IpSecManager(Context ctx, IIpSecService service) { + mContext = ctx; mService = checkNotNull(service, "missing service"); } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 099fe02fdd..fb5f46c117 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -130,7 +130,8 @@ public final class IpSecTransform implements AutoCloseable { synchronized (this) { try { IIpSecService svc = getIpSecService(); - IpSecTransformResponse result = svc.createTransform(mConfig, new Binder()); + IpSecTransformResponse result = svc.createTransform( + mConfig, new Binder(), mContext.getOpPackageName()); int status = result.status; checkResultStatus(status); mResourceId = result.resourceId; diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index bde6bd8db6..cd90e3f9b0 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -24,6 +24,8 @@ import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.IIpSecService; @@ -42,6 +44,7 @@ import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; +import android.os.DeadSystemException; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -974,6 +977,13 @@ public class IpSecService extends IIpSecService.Stub { return service; } + @NonNull + private AppOpsManager getAppOpsManager() { + AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); + return appOps; + } + /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { @@ -1240,7 +1250,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( - String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) { + String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, + String callingPackage) { + enforceTunnelPermissions(callingPackage); checkNotNull(binder, "Null Binder passed to createTunnelInterface"); checkNotNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); @@ -1320,8 +1332,8 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void addAddressToTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1352,10 +1364,10 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw // IllegalArgumentException TunnelInterfaceRecord tunnelInterfaceInfo = @@ -1383,7 +1395,9 @@ public class IpSecService extends IIpSecService.Stub { * server */ @Override - public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException { + public synchronized void deleteTunnelInterface( + int resourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); } @@ -1469,7 +1483,6 @@ public class IpSecService extends IIpSecService.Stub { case IpSecTransform.MODE_TRANSPORT: break; case IpSecTransform.MODE_TUNNEL: - enforceNetworkStackPermission(); break; default: throw new IllegalArgumentException( @@ -1477,9 +1490,20 @@ public class IpSecService extends IIpSecService.Stub { } } - private void enforceNetworkStackPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, - "IpSecService"); + private void enforceTunnelPermissions(String callingPackage) { + checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); + switch (getAppOpsManager().noteOp( + AppOpsManager.OP_MANAGE_IPSEC_TUNNELS, + Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); + } } private void createOrUpdateTransform( @@ -1535,8 +1559,12 @@ public class IpSecService extends IIpSecService.Stub { * result in all of those sockets becoming unable to send or receive data. */ @Override - public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder) - throws RemoteException { + public synchronized IpSecTransformResponse createTransform( + IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { + checkNotNull(c); + if (c.getMode() == IpSecTransform.MODE_TUNNEL) { + enforceTunnelPermissions(callingPackage); + } checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; @@ -1657,8 +1685,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { - enforceNetworkStackPermission(); + int tunnelResourceId, int direction, + int transformResourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); checkDirection(direction); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From fbbce98bc363363edac120b94a780a9fa1331467 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 2 Apr 2018 18:12:34 -0700 Subject: [PATCH 0519/1150] Force creation of Socket upon Transform application This change forces Socket and DatagramSocket to populate the SocketImpl, ensuring that the socket file descriptor can be retrieved when applying Transport mode Transforms This is done by calling getSoLinger(), triggering a getImpl(), which triggers setImpl() if needed. Bug: 77491294 Test: Added tests in IpSecManagerTest, ran on walleye Change-Id: I40da08b031357710eb794e0f866aec5660c79594 --- core/java/android/net/IpSecManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 719b81c7df..cc227713cb 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -336,6 +336,9 @@ public final class IpSecManager { */ public void applyTransportModeTransform(@NonNull Socket socket, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { + // Ensure creation of FD. See b/77548890 for more details. + socket.getSoLinger(); + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -440,6 +443,9 @@ public final class IpSecManager { * @throws IOException indicating that the transform could not be removed from the socket */ public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { + // Ensure creation of FD. See b/77548890 for more details. + socket.getSoLinger(); + removeTransportModeTransforms(socket.getFileDescriptor$()); } From ad4bca35e7dbce512176dfcd45ccb671b9d3a83b Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 2 Apr 2018 18:12:34 -0700 Subject: [PATCH 0520/1150] Force creation of Socket upon Transform application This change forces Socket and DatagramSocket to populate the SocketImpl, ensuring that the socket file descriptor can be retrieved when applying Transport mode Transforms This is done by calling getSoLinger(), triggering a getImpl(), which triggers setImpl() if needed. Bug: 77491294 Test: Added tests in IpSecManagerTest, ran on walleye Merged-In: I40da08b031357710eb794e0f866aec5660c79594 Change-Id: I40da08b031357710eb794e0f866aec5660c79594 (cherry picked from commit fbbce98bc363363edac120b94a780a9fa1331467) --- core/java/android/net/IpSecManager.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index e0654fde6e..0d04fe5a91 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -337,6 +337,9 @@ public final class IpSecManager { */ public void applyTransportModeTransform(@NonNull Socket socket, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { + // Ensure creation of FD. See b/77548890 for more details. + socket.getSoLinger(); + applyTransportModeTransform(socket.getFileDescriptor$(), direction, transform); } @@ -441,6 +444,9 @@ public final class IpSecManager { * @throws IOException indicating that the transform could not be removed from the socket */ public void removeTransportModeTransforms(@NonNull Socket socket) throws IOException { + // Ensure creation of FD. See b/77548890 for more details. + socket.getSoLinger(); + removeTransportModeTransforms(socket.getFileDescriptor$()); } From a0c566ec9fdf212558f3ab3a903148124e6e49bd Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 30 Mar 2018 16:25:11 -0600 Subject: [PATCH 0521/1150] API council requested tweaks to SubscriptionPlan. Return new shiny Range<> object instead of Pair<>. Tell developers what permission to check on refresh broadcast. Describe what exceptions might be thrown, and that an empty list is okay. Allow creation of plans with richer Period object, instead of forcing them into rigid week or day options. Protect SubscriptionPlan broadcast. Test: atest android.util.RecurrenceRuleTest Test: atest com.android.server.NetworkPolicyManagerServiceTest Bug: 74945820 Change-Id: I7e555798e0cfaa214ca93d9df627c6443fc5d986 --- .../com/android/server/net/NetworkStatsCollection.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 2ef754e2ba..ab525237db 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -47,7 +47,7 @@ import android.util.ArrayMap; import android.util.AtomicFile; import android.util.IntArray; import android.util.MathUtils; -import android.util.Pair; +import android.util.Range; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -266,11 +266,11 @@ public class NetworkStatsCollection implements FileRotator.Reader { long collectEnd = end; if (augmentEnd != SubscriptionPlan.TIME_UNKNOWN) { - final Iterator> it = augmentPlan.cycleIterator(); + final Iterator> it = augmentPlan.cycleIterator(); while (it.hasNext()) { - final Pair cycle = it.next(); - final long cycleStart = cycle.first.toInstant().toEpochMilli(); - final long cycleEnd = cycle.second.toInstant().toEpochMilli(); + final Range cycle = it.next(); + final long cycleStart = cycle.getLower().toInstant().toEpochMilli(); + final long cycleEnd = cycle.getUpper().toInstant().toEpochMilli(); if (cycleStart <= augmentEnd && augmentEnd < cycleEnd) { augmentStart = cycleStart; collectStart = Long.min(collectStart, augmentStart); From e84200fc5b1a7a469822fee2cceb2d469e8aeea2 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 3 Apr 2018 20:30:54 -0700 Subject: [PATCH 0522/1150] Update IpSecManager to use InetAddress and prefixLen LinkAddress constructors are currently @hide; this change updates IpSecManager to use InetAddress and prefixLen, and then construct a LinkAddress internally. LinkAddress is used over the binder interface to IpSecService to ensure validity. Bug: 77528639 Test: CTS, Java unit tests ran on walleye Change-Id: I19e124adef6d9f4992d8293db3190bcf74c95848 --- core/java/android/net/IpSecManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index e0654fde6e..ade6374675 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -684,14 +684,15 @@ public final class IpSecManager { * tunneled traffic. * * @param address the local address for traffic inside the tunnel + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void addAddress(@NonNull LinkAddress address) throws IOException { + public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { mService.addAddressToTunnelInterface( - mResourceId, address, mOpPackageName); + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -703,14 +704,15 @@ public final class IpSecManager { *

            Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void removeAddress(@NonNull LinkAddress address) throws IOException { + public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { mService.removeAddressFromTunnelInterface( - mResourceId, address, mOpPackageName); + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } From e91692a3e38d33a8b33c14d437355e55f6330203 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 6 Apr 2018 22:56:52 +0900 Subject: [PATCH 0523/1150] Add @param tag for state in queryDetailsForUidTagState. Change-Id: I22de424ccb2b30b2a56edd17dc982565b8aa7d4a Fix: 77518425 Test: make doc-comment-check-docs --- core/java/android/app/usage/NetworkStatsManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index b2fe958691..85f4efc3f7 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -305,6 +305,8 @@ public class NetworkStatsManager { * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. + * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate + * traffic from all states. * @return Statistics object or null if an error happened during statistics collection. * @throws SecurityException if permissions are insufficient to read network statistics. */ From 63f789c5e48a34be533d7495208ceb088b048989 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 4 Apr 2018 14:51:26 +0900 Subject: [PATCH 0524/1150] Do not register callback for < MIN_THRESHOLD_BYTES This also avoids returning a nonzero multipath preference if remaining data is low but nonzero. Bug: b/72877610 Change-Id: I2459ded06de77d284ae1fe81a60d9e1df56b0c26 Fixes: b/72877610 Test: Tests in go/ag/3842960 pass --- core/java/android/app/usage/NetworkStatsManager.java | 10 ++++++++++ .../com/android/server/net/NetworkStatsObservers.java | 4 +--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index b2fe958691..34f3a8da95 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -35,6 +35,7 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.util.DataUnit; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -95,6 +96,15 @@ public class NetworkStatsManager { /** @hide */ public static final int CALLBACK_RELEASED = 1; + /** + * Minimum data usage threshold for registering usage callbacks. + * + * Requests registered with a threshold lower than this will only be triggered once this minimum + * is reached. + * @hide + */ + public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2); + private final Context mContext; private final INetworkStatsService mService; diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index 741c2062bd..d8408730dd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -16,7 +16,7 @@ package com.android.server.net; -import static android.net.TrafficStats.MB_IN_BYTES; +import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; import static com.android.internal.util.Preconditions.checkArgument; @@ -52,8 +52,6 @@ class NetworkStatsObservers { private static final String TAG = "NetworkStatsObservers"; private static final boolean LOGV = false; - private static final long MIN_THRESHOLD_BYTES = 2 * MB_IN_BYTES; - private static final int MSG_REGISTER = 1; private static final int MSG_UNREGISTER = 2; private static final int MSG_UPDATE_STATS = 3; From ba804c21251f5da3f4551f22e95ae14d6d55bd94 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 9 Apr 2018 21:24:35 -0700 Subject: [PATCH 0525/1150] [DO NOT MERGE] - Hide Tunnel Mode IpSec API Hide the tunnel mode of the IpSec API because there is a disincentive to launch it without a supported customer use case. That use case, IWLAN is having its APIs hidden, so we should hide these as well to avoid constraining future implementation. Also, due to issues with the lifetime of the NATT management object, this API needs to be hidden until such time as the lifetime of the Keepalive can be handled independently of the lifetime of a Transform. Bug: 72523623 Test: compilation (api removal) Change-Id: I076030bdbab1cd7d69f6a034577d529970b050dc --- core/java/android/net/IpSecManager.java | 6 ------ core/java/android/net/IpSecTransform.java | 5 ----- 2 files changed, 11 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 87323755a9..a61ea50d6f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -20,7 +20,6 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; @@ -666,7 +665,6 @@ public final class IpSecManager { * to create Network objects which are accessible to the Android system. * @hide */ - @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { private final String mOpPackageName; private final IIpSecService mService; @@ -693,7 +691,6 @@ public final class IpSecManager { * @param prefixLen length of the InetAddress prefix * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { @@ -713,7 +710,6 @@ public final class IpSecManager { * @param prefixLen length of the InetAddress prefix * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { @@ -809,7 +805,6 @@ public final class IpSecManager { * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open * @hide */ - @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @@ -836,7 +831,6 @@ public final class IpSecManager { * layer failure. * @hide */ - @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index fb5f46c117..62f7996564 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -22,7 +22,6 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresPermission; -import android.annotation.SystemApi; import android.content.Context; import android.os.Binder; import android.os.Handler; @@ -250,7 +249,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi public static class NattKeepaliveCallback { /** The specified {@code Network} is not connected. */ public static final int ERROR_INVALID_NETWORK = 1; @@ -281,7 +279,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD @@ -324,7 +321,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD @@ -477,7 +473,6 @@ public final class IpSecTransform implements AutoCloseable { * @throws IOException indicating other errors * @hide */ - @SystemApi @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTransform buildTunnelModeTransform( From 9ad30adb820301b3fb1ed002d3d62065423a72f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 2 Apr 2018 19:29:26 +0900 Subject: [PATCH 0526/1150] Address API comments on NetworkStats#getDefaultNetwork. Bug: 76449091 Test: android.app.usage.cts.NetworkUsageStatsTest passes Change-Id: I7f21e0bd7bc4b726058fc2e25542ff2c3173fabe --- core/java/android/app/usage/NetworkStats.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java index 7252f028d7..216a4a0987 100644 --- a/core/java/android/app/usage/NetworkStats.java +++ b/core/java/android/app/usage/NetworkStats.java @@ -237,20 +237,26 @@ public final class NetworkStats implements AutoCloseable { DEFAULT_NETWORK_YES }) @Retention(RetentionPolicy.SOURCE) - public @interface DefaultNetwork {} + public @interface DefaultNetworkStatus {} /** - * Combined usage for this network regardless of whether it was the active default network. + * Combined usage for this network regardless of default network status. */ public static final int DEFAULT_NETWORK_ALL = -1; /** - * Usage that occurs while this network is not the active default network. + * Usage that occurs while this network is not a default network. + * + *

            This implies that the app responsible for this usage requested that it occur on a + * specific network different from the one(s) the system would have selected for it. */ public static final int DEFAULT_NETWORK_NO = 0x1; /** - * Usage that occurs while this network is the active default network. + * Usage that occurs while this network is a default network. + * + *

            This implies that the app either did not select a specific network for this usage, + * or it selected a network that the system could have selected for app traffic. */ public static final int DEFAULT_NETWORK_YES = 0x2; @@ -262,7 +268,7 @@ public final class NetworkStats implements AutoCloseable { private int mUid; private int mTag; private int mState; - private int mDefaultNetwork; + private int mDefaultNetworkStatus; private int mMetered; private int mRoaming; private long mBeginTimeStamp; @@ -323,8 +329,9 @@ public final class NetworkStats implements AutoCloseable { return 0; } - private static @DefaultNetwork int convertDefaultNetwork(int defaultNetwork) { - switch (defaultNetwork) { + private static @DefaultNetworkStatus int convertDefaultNetworkStatus( + int defaultNetworkStatus) { + switch (defaultNetworkStatus) { case android.net.NetworkStats.DEFAULT_NETWORK_ALL : return DEFAULT_NETWORK_ALL; case android.net.NetworkStats.DEFAULT_NETWORK_NO: return DEFAULT_NETWORK_NO; case android.net.NetworkStats.DEFAULT_NETWORK_YES: return DEFAULT_NETWORK_YES; @@ -397,18 +404,15 @@ public final class NetworkStats implements AutoCloseable { } /** - * Default network state. One of the following values:

            + * Default network status. One of the following values:

            *

              *
            • {@link #DEFAULT_NETWORK_ALL}
            • *
            • {@link #DEFAULT_NETWORK_NO}
            • *
            • {@link #DEFAULT_NETWORK_YES}
            • *
            - *

            Indicates whether the network usage occurred on the system default network for this - * type of traffic, or whether the application chose to send this traffic on a network that - * was not the one selected by the system. */ - public @DefaultNetwork int getDefaultNetwork() { - return mDefaultNetwork; + public @DefaultNetworkStatus int getDefaultNetworkStatus() { + return mDefaultNetworkStatus; } /** @@ -605,7 +609,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(mRecycledSummaryEntry.uid); bucketOut.mTag = Bucket.convertTag(mRecycledSummaryEntry.tag); bucketOut.mState = Bucket.convertState(mRecycledSummaryEntry.set); - bucketOut.mDefaultNetwork = Bucket.convertDefaultNetwork( + bucketOut.mDefaultNetworkStatus = Bucket.convertDefaultNetworkStatus( mRecycledSummaryEntry.defaultNetwork); bucketOut.mMetered = Bucket.convertMetered(mRecycledSummaryEntry.metered); bucketOut.mRoaming = Bucket.convertRoaming(mRecycledSummaryEntry.roaming); @@ -657,7 +661,7 @@ public final class NetworkStats implements AutoCloseable { bucketOut.mUid = Bucket.convertUid(getUid()); bucketOut.mTag = Bucket.convertTag(mTag); bucketOut.mState = mState; - bucketOut.mDefaultNetwork = Bucket.DEFAULT_NETWORK_ALL; + bucketOut.mDefaultNetworkStatus = Bucket.DEFAULT_NETWORK_ALL; bucketOut.mMetered = Bucket.METERED_ALL; bucketOut.mRoaming = Bucket.ROAMING_ALL; bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart; From badc54893b0b2585a477c6eaee75c783776dc1e4 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 12 Apr 2018 19:26:34 +0900 Subject: [PATCH 0527/1150] Add rate limiting and logging for NetworkStats. Bug: 77908520, 77808546, 77853238, 77154412 Test: atest com.android.server.net.NetworkStatsServiceTest Test: manual: flashed, verified network usage updated Change-Id: I905dbea85e00f80103916939f6d4bf8cab931d03 --- .../server/net/NetworkStatsService.java | 65 +++++++++++++++++-- 1 file changed, 60 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4e848f8f36..e3ff72b9a9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -286,6 +286,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long mPersistThreshold = 2 * MB_IN_BYTES; private long mGlobalAlertBytes; + private static final long POLL_RATE_LIMIT_MS = 15_000; + + private long mLastStatsSessionPoll; + + /** Map from UID to number of opened sessions */ + @GuardedBy("mOpenSessionCallsPerUid") + private final SparseIntArray mOpenSessionCallsPerUid = new SparseIntArray(); + + private final static int DUMP_STATS_SESSION_COUNT = 20; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -509,10 +519,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return openSessionInternal(flags, callingPackage); } + private boolean isRateLimitedForPoll(int callingUid) { + if (callingUid == android.os.Process.SYSTEM_UID) { + return false; + } + + final long lastCallTime; + final long now = SystemClock.elapsedRealtime(); + synchronized (mOpenSessionCallsPerUid) { + int calls = mOpenSessionCallsPerUid.get(callingUid, 0); + mOpenSessionCallsPerUid.put(callingUid, calls + 1); + lastCallTime = mLastStatsSessionPoll; + mLastStatsSessionPoll = now; + } + + return now - lastCallTime < POLL_RATE_LIMIT_MS; + } + private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { assertBandwidthControlEnabled(); - if ((flags & NetworkStatsManager.FLAG_POLL_ON_OPEN) != 0) { + final int callingUid = Binder.getCallingUid(); + final int usedFlags = isRateLimitedForPoll(callingUid) + ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) + : flags; + if ((usedFlags & NetworkStatsManager.FLAG_POLL_ON_OPEN) != 0) { final long ident = Binder.clearCallingIdentity(); try { performPoll(FLAG_PERSIST_ALL); @@ -525,7 +556,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // for its lifetime; when caller closes only weak references remain. return new INetworkStatsSession.Stub() { - private final int mCallingUid = Binder.getCallingUid(); + private final int mCallingUid = callingUid; private final String mCallingPackage = callingPackage; private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( callingPackage); @@ -559,20 +590,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDeviceSummaryForNetwork( NetworkTemplate template, long start, long end) { - return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel, + return internalGetSummaryForNetwork(template, usedFlags, start, end, mAccessLevel, mCallingUid); } @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { - return internalGetSummaryForNetwork(template, flags, start, end, mAccessLevel, + return internalGetSummaryForNetwork(template, usedFlags, start, end, mAccessLevel, mCallingUid); } @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return internalGetHistoryForNetwork(template, flags, fields, mAccessLevel, + return internalGetHistoryForNetwork(template, usedFlags, fields, mAccessLevel, mCallingUid); } @@ -1461,6 +1492,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } pw.decreaseIndent(); + // Get the top openSession callers + final SparseIntArray calls; + synchronized (mOpenSessionCallsPerUid) { + calls = mOpenSessionCallsPerUid.clone(); + } + + final int N = calls.size(); + final long[] values = new long[N]; + for (int j = 0; j < N; j++) { + values[j] = ((long) calls.valueAt(j) << 32) | calls.keyAt(j); + } + Arrays.sort(values); + + pw.println("Top openSession callers (uid=count):"); + pw.increaseIndent(); + final int end = Math.max(0, N - DUMP_STATS_SESSION_COUNT); + for (int j = N - 1; j >= end; j--) { + final int uid = (int) (values[j] & 0xffffffff); + final int count = (int) (values[j] >> 32); + pw.print(uid); pw.print("="); pw.println(count); + } + pw.decreaseIndent(); + pw.println(); + pw.println("Dev stats:"); pw.increaseIndent(); mDevRecorder.dumpLocked(pw, fullHistory); From c0318d130e66ed6eeea0578b76b20e29aa09c499 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 13 Apr 2018 13:29:59 -0600 Subject: [PATCH 0528/1150] OP_GET_USAGE_STATS should be noted, not checked. Per email feedback, we should be using "noteOp" instead of "checkOp" when testing if caller holds OP_GET_USAGE_STATS, so that we record that caller used the operation. Bug: 77662908 Test: builds, boots Exempt-From-Owner-Approval: keep tests passing Change-Id: I3a60345d590534fdbc2c1248e0d30dc85a5d6772 --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 98fe770774..cebc472178 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -174,7 +174,7 @@ public final class NetworkStatsAccess { AppOpsManager appOps = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); - final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app From 53323c2812ff8fcf47976360d5e398ee5a744502 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 13 Apr 2018 14:28:30 -0600 Subject: [PATCH 0529/1150] Don't process broadcasts until really ready. Someone started setting mSystemReady too early, when we really want to know SystemServer's real ready state. Add a variable to track that, and don't process broadcasts until that's set. Bug: 78020762 Test: builds, boots Change-Id: I65213e46044c95fb0a8a4b09b9aa463bb15c1844 --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e3ff72b9a9..e7f92dca60 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -282,7 +282,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private Handler mHandler; private Handler.Callback mHandlerCallback; - private boolean mSystemReady; + private volatile boolean mSystemReady; private long mPersistThreshold = 2 * MB_IN_BYTES; private long mGlobalAlertBytes; From f28796042a83ac44c79a8c37511d5263b5e13a30 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 16 Apr 2018 16:39:55 +0000 Subject: [PATCH 0530/1150] Revert "OP_GET_USAGE_STATS should be noted, not checked." This reverts commit c0318d130e66ed6eeea0578b76b20e29aa09c499. Reason for revert: ijpedowitz@ Bug: 77662908 Change-Id: I5dd0ad5038df90ea8a80ba6f583ee46fb24600c2 Exempt-From-Owner-Approval: keep tests passing --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index cebc472178..98fe770774 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -174,7 +174,7 @@ public final class NetworkStatsAccess { AppOpsManager appOps = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); - final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, + final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app From 2f036210f4ca7a6ada7079d5593f483290956218 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 16 Apr 2018 16:50:34 +0000 Subject: [PATCH 0531/1150] Revert "Revert "OP_GET_USAGE_STATS should be noted, not checked."" This reverts commit f28796042a83ac44c79a8c37511d5263b5e13a30. Reason for revert: ijpedowitz@ Bug: 77662908 Change-Id: I596d330d64942105f447bb613012bb11e281a805 Exempt-From-Owner-Approval: keep tests passing --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 98fe770774..cebc472178 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -174,7 +174,7 @@ public final class NetworkStatsAccess { AppOpsManager appOps = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); - final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, + final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app From f2a431ac181a374807745e3a9858911a601c6ef8 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 12 Apr 2018 14:26:32 -0600 Subject: [PATCH 0532/1150] Add tracing for network statistics and policy. These trace points surround areas of heavy lifting to help us debug code that might be taking longer than expected. (For example, slow getting data from eBPF, slow recording into data structures, slow writing to disk, or slow evaluating policy.) Typical timings on a taimen: performPollLocked: 25.5ms snapshotUid: 4.4ms snapshotXt: 1.4ms [persisting]: 13.4ms updateNotifications: 3.3ms Bug: 77908520, 77808546, 77853238, 77154412 Test: builds, boots Change-Id: I072bfecffee01eeec7e4cbad439bd1cdc166febc --- .../server/net/NetworkStatsService.java | 44 +++++++++++++++---- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e7f92dca60..7ee17bc2f8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -43,6 +43,7 @@ import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; @@ -109,6 +110,7 @@ import android.os.Messenger; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; @@ -1190,27 +1192,43 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void recordSnapshotLocked(long currentTime) throws RemoteException { // snapshot and record current counters; read UID stats first to // avoid over counting dev stats. + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotUid"); final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); + Trace.traceEnd(TRACE_TAG_NETWORK); + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); final NetworkStats xtSnapshot = getNetworkStatsXt(); + Trace.traceEnd(TRACE_TAG_NETWORK); + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + Trace.traceEnd(TRACE_TAG_NETWORK); // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats // providers that isn't already counted by dev and XT stats. + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotTether"); final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + Trace.traceEnd(TRACE_TAG_NETWORK); xtSnapshot.combineAllValues(tetherSnapshot); devSnapshot.combineAllValues(tetherSnapshot); // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. + Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); mDevRecorder.recordSnapshotLocked( devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + Trace.traceEnd(TRACE_TAG_NETWORK); + Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); mXtRecorder.recordSnapshotLocked( xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + Trace.traceEnd(TRACE_TAG_NETWORK); + Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + Trace.traceEnd(TRACE_TAG_NETWORK); // We need to make copies of member fields that are sent to the observer to avoid // a race condition between the service handler thread and the observer's @@ -1255,8 +1273,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void performPollLocked(int flags) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); - - final long startRealtime = SystemClock.elapsedRealtime(); + Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked"); final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; @@ -1276,6 +1293,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // persist any pending data depending on requested flags + Trace.traceBegin(TRACE_TAG_NETWORK, "[persisting]"); if (persistForce) { mDevRecorder.forcePersistLocked(currentTime); mXtRecorder.forcePersistLocked(currentTime); @@ -1291,11 +1309,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidTagRecorder.maybePersistLocked(currentTime); } } - - if (LOGV) { - final long duration = SystemClock.elapsedRealtime() - startRealtime; - Slog.v(TAG, "performPollLocked() took " + duration + "ms"); - } + Trace.traceEnd(TRACE_TAG_NETWORK); if (mSettings.getSampleEnabled()) { // sample stats after each full poll @@ -1307,6 +1321,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, READ_NETWORK_USAGE_HISTORY); + + Trace.traceEnd(TRACE_TAG_NETWORK); } /** @@ -1389,12 +1405,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal { @Override public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - return NetworkStatsService.this.getNetworkTotalBytes(template, start, end); + Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes"); + try { + return NetworkStatsService.this.getNetworkTotalBytes(template, start, end); + } finally { + Trace.traceEnd(TRACE_TAG_NETWORK); + } } @Override public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { - return NetworkStatsService.this.getNetworkUidBytes(template, start, end); + Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes"); + try { + return NetworkStatsService.this.getNetworkUidBytes(template, start, end); + } finally { + Trace.traceEnd(TRACE_TAG_NETWORK); + } } @Override From 4eade4d5eb5089d484e3ed1b760d0f499241af34 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 16 Apr 2018 16:39:55 +0000 Subject: [PATCH 0533/1150] Revert "OP_GET_USAGE_STATS should be noted, not checked." This reverts commit c0318d130e66ed6eeea0578b76b20e29aa09c499. Reason for revert: ijpedowitz@ Bug: 77662908 Change-Id: I5dd0ad5038df90ea8a80ba6f583ee46fb24600c2 Exempt-From-Owner-Approval: keep tests passing (cherry picked from commit f28796042a83ac44c79a8c37511d5263b5e13a30) --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index cebc472178..98fe770774 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -174,7 +174,7 @@ public final class NetworkStatsAccess { AppOpsManager appOps = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); - final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, + final int mode = appOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, callingUid, callingPackage); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app From 02ad62281bb72ab7a061bbcce873da7d68af108a Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 18 Apr 2018 15:42:57 -0600 Subject: [PATCH 0534/1150] Never interact with "phone" while holding locks. We've seen devices where heavy communication between "system_server" and the "phone" process can exhuast Binder threads, especially when calling while holding locks. To mitigate this, we now interact with the "phone" process before acquiring any locks. Update our internal data structures either when we see a connectivity change, or when SubscriptionManager tells us something changed. Fix bug in resolveSubscriptionPlan() that always picked the 0'th SubscriptionPlan instead of looking for the currently active plan; we now use the same logic for both NSS and NPMS. Bug: 77908520, 77154412 Test: atest com.android.server.NetworkPolicyManagerServiceTest Test: atest com.android.server.net.NetworkStatsServiceTest Change-Id: I177d3fa6cddc78d745b35a9ede12451d458b892c --- .../android/server/net/NetworkStatsService.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7ee17bc2f8..ae7058d42e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -116,7 +116,6 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; -import android.telephony.SubscriptionManager; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; @@ -679,22 +678,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private SubscriptionPlan resolveSubscriptionPlan(NetworkTemplate template, int flags) { SubscriptionPlan plan = null; if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 - && (template.getMatchRule() == NetworkTemplate.MATCH_MOBILE) && mSettings.getAugmentEnabled()) { if (LOGD) Slog.d(TAG, "Resolving plan for " + template); final long token = Binder.clearCallingIdentity(); try { - final SubscriptionManager sm = mContext.getSystemService(SubscriptionManager.class); - final TelephonyManager tm = mContext.getSystemService(TelephonyManager.class); - for (int subId : sm.getActiveSubscriptionIdList()) { - if (template.matchesSubscriberId(tm.getSubscriberId(subId))) { - if (LOGD) Slog.d(TAG, "Found active matching subId " + subId); - final List plans = sm.getSubscriptionPlans(subId); - if (!plans.isEmpty()) { - plan = plans.get(0); - } - } - } + plan = LocalServices.getService(NetworkPolicyManagerInternal.class) + .getSubscriptionPlan(template); } finally { Binder.restoreCallingIdentity(token); } From 32181a737930828ab077a218878549a48b41866f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 20 Apr 2018 10:59:09 -0600 Subject: [PATCH 0535/1150] Give CTS a way to force-poll network stats. Collecting network statistics is pretty heavy, which is why we're throttling callers. However, to keep CTS running fast, we provide a way for tests to force a poll event, instead of making them wait for the throttle timeout. Bug: 77908520 Test: atest cts/tests/tests/app.usage/src/android/app/usage/cts/NetworkUsageStatsTest.java Change-Id: Ia792f0cd495023366ff8c4839df54e7da2ae8331 --- .../android/app/usage/NetworkStatsManager.java | 15 ++++++++++++++- .../android/server/net/NetworkStatsService.java | 3 ++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 0b21196f5d..9f46f207d6 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -20,6 +20,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; import android.annotation.SystemService; +import android.annotation.TestApi; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; @@ -111,7 +112,9 @@ public class NetworkStatsManager { /** @hide */ public static final int FLAG_POLL_ON_OPEN = 1 << 0; /** @hide */ - public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 1; + public static final int FLAG_POLL_FORCE = 1 << 1; + /** @hide */ + public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; private int mFlags; @@ -140,6 +143,16 @@ public class NetworkStatsManager { } } + /** @hide */ + @TestApi + public void setPollForce(boolean pollForce) { + if (pollForce) { + mFlags |= FLAG_POLL_FORCE; + } else { + mFlags &= ~FLAG_POLL_FORCE; + } + } + /** @hide */ public void setAugmentWithSubscriptionPlan(boolean augmentWithSubscriptionPlan) { if (augmentWithSubscriptionPlan) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ae7058d42e..9ef6c66b07 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -544,7 +544,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int usedFlags = isRateLimitedForPoll(callingUid) ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) : flags; - if ((usedFlags & NetworkStatsManager.FLAG_POLL_ON_OPEN) != 0) { + if ((usedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN + | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) { final long ident = Binder.clearCallingIdentity(); try { performPoll(FLAG_PERSIST_ALL); From 21c4188a979c55f336728397e18273978d11f7f4 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 3 Apr 2018 16:13:19 -0700 Subject: [PATCH 0536/1150] Rework Exception Handling for IpSecManager In order to properly support EOPNOTSUPP this CL applies a consistent approach to handling Exceptions. Hereafter, all exceptions that aren't of a special method-specific type (such as SpiUnavailableException) will all be returned to the calling process unchanged. At the API call site, the ServiceSpecificException, which is really an Errno, will be inspected and either converted to an unchecked exception for types we know, or it will be converted to an IOException in cases where that method can return a checked exception. In cases where we do not expect an errno, we will simply throw a generic RuntimeException. This means all API calls will now properly throw UnsupportedOperationException and may be CTS tested accordingly. Bug: 72420898 Test: runtest frameworks-net Change-Id: I4a00e221618896223fcdb4b4279fb14cd14e34d8 --- core/java/android/net/IpSecManager.java | 147 ++++++++++++++++-- core/java/android/net/IpSecTransform.java | 16 ++ .../java/com/android/server/IpSecService.java | 71 +++------ 3 files changed, 173 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index a61ea50d6f..d4c3edca43 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -26,6 +26,9 @@ import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.system.OsConstants; import android.util.AndroidException; import android.util.Log; @@ -172,11 +175,16 @@ public final class IpSecManager { public void close() { try { mService.releaseSecurityParameterIndex(mResourceId); - mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the SPI was closed properly. */ @@ -227,7 +235,6 @@ public final class IpSecManager { throw new RuntimeException( "Invalid Resource ID returned by IpSecService: " + status); } - } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -239,6 +246,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("SecurityParameterIndex{spi=") + .append(mSpi) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -261,7 +279,11 @@ public final class IpSecManager { mService, destinationAddress, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (SpiUnavailableException unlikely) { + // Because this function allocates a totally random SPI, it really shouldn't ever + // fail to allocate an SPI; we simply need this because the exception is checked. throw new ResourceUnavailableException("No SPIs available"); } } @@ -274,8 +296,8 @@ public final class IpSecManager { * * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is - * reserved and may not be used. See RFC 4303 Section 2.1. + * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See + * RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user @@ -289,7 +311,11 @@ public final class IpSecManager { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); } - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + try { + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); + } } /** @@ -424,6 +450,8 @@ public final class IpSecManager { // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -482,6 +510,8 @@ public final class IpSecManager { public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.removeTransportModeTransforms(pfd); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -575,6 +605,13 @@ public final class IpSecManager { mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } try { @@ -583,7 +620,6 @@ public final class IpSecManager { Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); throw e; } - mCloseGuard.close(); } /** Check that the socket was closed properly. */ @@ -600,6 +636,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("UdpEncapsulationSocket{port=") + .append(mPort) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } }; /** @@ -627,7 +674,11 @@ public final class IpSecManager { if (port == 0) { throw new IllegalArgumentException("Specified port must be a valid port number!"); } - return new UdpEncapsulationSocket(mService, port); + try { + return new UdpEncapsulationSocket(mService, port); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -650,7 +701,11 @@ public final class IpSecManager { @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { - return new UdpEncapsulationSocket(mService, 0); + try { + return new UdpEncapsulationSocket(mService, 0); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -696,6 +751,8 @@ public final class IpSecManager { try { mService.addAddressToTunnelInterface( mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -715,6 +772,8 @@ public final class IpSecManager { try { mService.removeAddressFromTunnelInterface( mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -767,11 +826,16 @@ public final class IpSecManager { public void close() { try { mService.deleteTunnelInterface(mResourceId, mOpPackageName); - mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the Interface was closed properly. */ @@ -788,6 +852,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTunnelInterface{ifname=") + .append(mInterfaceName) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -810,8 +885,12 @@ public final class IpSecManager { public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { - return new IpSecTunnelInterface( - mContext, mService, localAddress, remoteAddress, underlyingNetwork); + try { + return new IpSecTunnelInterface( + mContext, mService, localAddress, remoteAddress, underlyingNetwork); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -838,6 +917,8 @@ public final class IpSecManager { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId(), mContext.getOpPackageName()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -853,4 +934,44 @@ public final class IpSecManager { mContext = ctx; mService = checkNotNull(service, "missing service"); } + + private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { + // OsConstants are late binding, so switch statements can't be used. + if (sse.errorCode == OsConstants.EINVAL) { + throw new IllegalArgumentException(sse); + } else if (sse.errorCode == OsConstants.EAGAIN) { + throw new IllegalStateException(sse); + } else if (sse.errorCode == OsConstants.EOPNOTSUPP) { + throw new UnsupportedOperationException(sse); + } + } + + /** + * Convert an Errno SSE to the correct Unchecked exception type. + * + * This method never actually returns. + */ + // package + static RuntimeException + rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) { + maybeHandleServiceSpecificException(sse); + throw new RuntimeException(sse); + } + + /** + * Convert an Errno SSE to the correct Checked or Unchecked exception type. + * + * This method may throw IOException, or it may throw an unchecked exception; it will never + * actually return. + */ + // package + static IOException rethrowCheckedExceptionFromServiceSpecificException( + ServiceSpecificException sse) throws IOException { + // First see if this is an unchecked exception of a type we know. + // If so, then we prefer the unchecked (specific) type of exception. + maybeHandleServiceSpecificException(sse); + // If not, then all we can do is provide the SSE in the form of an IOException. + throw new ErrnoException( + "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException(); + } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 62f7996564..a12df28eac 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -28,6 +28,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -136,6 +137,8 @@ public final class IpSecTransform implements AutoCloseable { mResourceId = result.resourceId; Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); + } catch (ServiceSpecificException e) { + throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -180,6 +183,10 @@ public final class IpSecTransform implements AutoCloseable { stopNattKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); } finally { mResourceId = INVALID_RESOURCE_ID; mCloseGuard.close(); @@ -502,4 +509,13 @@ public final class IpSecTransform implements AutoCloseable { mConfig = new IpSecConfig(); } } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTransform{resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index cd90e3f9b0..33ca02fecb 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1101,9 +1101,11 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResource( new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { - // TODO: Add appropriate checks when other ServiceSpecificException types are supported - return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + if (e.errorCode == OsConstants.ENOENT) { + return new IpSecSpiResponse( + IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + } + throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1115,7 +1117,6 @@ public class IpSecService extends IIpSecService.Stub { */ private void releaseResource(RefcountedResourceArray resArray, int resourceId) throws RemoteException { - resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); } @@ -1315,15 +1316,12 @@ public class IpSecService extends IIpSecService.Stub { releaseNetId(ikey); releaseNetId(okey); throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (Throwable t) { + // Release keys if we got an error. + releaseNetId(ikey); + releaseNetId(okey); + throw t; } - - // If we make it to here, then something has gone wrong and we couldn't create a VTI. - // Release the keys that we reserved, and return an error status. - releaseNetId(ikey); - releaseNetId(okey); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } /** @@ -1352,9 +1350,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1384,9 +1379,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1590,12 +1582,7 @@ public class IpSecService extends IIpSecService.Stub { dependencies.add(refcountedSpiRecord); SpiRecord spiRecord = refcountedSpiRecord.getResource(); - try { - createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } + createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); // SA was created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( @@ -1642,23 +1629,15 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - try { - mSrvConfig - .getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); - } catch (ServiceSpecificException e) { - if (e.errorCode == EINVAL) { - throw new IllegalArgumentException(e.toString()); - } else { - throw e; - } - } + mSrvConfig + .getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } /** @@ -1670,13 +1649,9 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - try { - mSrvConfig - .getNetdInstance() - .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } + mSrvConfig + .getNetdInstance() + .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); } /** From dd65497239c3e4a57d6e2c263b70142352089354 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 18 Apr 2018 15:44:46 -0700 Subject: [PATCH 0537/1150] Use eBPF map data for per iface stats After adding the xt_bpf module and ifaceStatsMap, eBPF tool can now support reading per interface data. So networkStatsFactory should move away from parsing proc/net/dev and use the eBPF map stats instead. Bug: 72111305 Test: atest com.android.server.net.NetworkStatsServiceTest Change-Id: Ibcc6150d00835b3bd33af22a72e4a86e172581cf --- .../internal/net/NetworkStatsFactory.java | 19 ++++- ...droid_internal_net_NetworkStatsFactory.cpp | 81 +++++++++++-------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 8561bf0279..814b811e64 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -176,6 +176,14 @@ public class NetworkStatsFactory { return stats; } + public NetworkStats readBpfNetworkStatsDev() throws IOException { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + if (nativeReadNetworkStatsDev(stats) != 0) { + throw new IOException("Failed to parse bpf iface stats"); + } + return stats; + } + /** * Parse and return interface-level summary {@link NetworkStats} measured * using {@code /proc/net/dev} style hooks, which may include non IP layer @@ -186,9 +194,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { - // Return the stats get from /proc/net/dev if switched to bpf module. + // Return xt_bpf stats if switched to bpf module. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -242,9 +250,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { - // Return the stats get from /proc/net/dev if qtaguid module is replaced. + // Return xt_bpf stats if qtaguid module is replaced. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -406,4 +414,7 @@ public class NetworkStatsFactory { @VisibleForTesting public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); + + @VisibleForTesting + public static native int nativeReadNetworkStatsDev(NetworkStats stats); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 99d9839570..c15b7ee4fe 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -205,37 +205,8 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, return 0; } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, - jint limitUid, jobjectArray limitIfacesObj, jint limitTag, - jboolean useBpfStats) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } - - std::vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } - std::vector lines; - - - if (useBpfStats) { - if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) - return -1; - } else { - if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, - limitUid, path8.c_str()) < 0) - return -1; - } - +static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, + std::vector& lines) { int size = lines.size(); bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); @@ -308,14 +279,58 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); } - return 0; } +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, + jint limitUid, jobjectArray limitIfacesObj, jint limitTag, + jboolean useBpfStats) { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + return -1; + } + + std::vector limitIfaces; + if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { + int num = env->GetArrayLength(limitIfacesObj); + for (int i = 0; i < num; i++) { + jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); + ScopedUtfChars string8(env, string); + if (string8.c_str() != NULL) { + limitIfaces.push_back(std::string(string8.c_str())); + } + } + } + std::vector lines; + + + if (useBpfStats) { + if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) + return -1; + } else { + if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, + limitUid, path8.c_str()) < 0) + return -1; + } + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + +static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) { + std::vector lines; + + if (parseBpfNetworkStatsDev(&lines) < 0) + return -1; + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", - (void*) readNetworkStatsDetail } + (void*) readNetworkStatsDetail }, + { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", + (void*) readNetworkStatsDev }, }; int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { From 1199060152d65d20104020dcfa9852fdec6be470 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 1 May 2018 13:51:13 -0700 Subject: [PATCH 0538/1150] Remove the unused file parsing function With the new xt_bpf support for iface stats. We no longer need to parse the per interface stats from /proc/net/dev. And since the old xt_qtaguid code path also not depend on it, we can completly remove that helper function since no caller is depending on it now. Bug: 72111305 Test: runtest frameworks-net -c com.android.internal.net.NetworkStatsFactoryTest Change-Id: Icb7eaeef0eeb9fdffd32a90316c76ee05bafffbe --- .../internal/net/NetworkStatsFactory.java | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 814b811e64..41802cc606 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -54,8 +54,6 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; - /** Path to {@code /proc/net/dev}. */ - private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ @@ -131,51 +129,12 @@ public class NetworkStatsFactory { @VisibleForTesting public NetworkStatsFactory(File procRoot, boolean useBpfStats) { - mStatsIfaceDev = new File(procRoot, "net/dev"); mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; } - @VisibleForTesting - public NetworkStats readNetworkStatsIfaceDev() throws IOException { - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(mStatsIfaceDev)); - - // skip first two header lines - reader.readLine(); - reader.readLine(); - - // parse remaining lines - String line; - while ((line = reader.readLine()) != null) { - String[] values = line.trim().split("\\:?\\s+"); - entry.iface = values[0]; - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.rxBytes = Long.parseLong(values[1]); - entry.rxPackets = Long.parseLong(values[2]); - entry.txBytes = Long.parseLong(values[9]); - entry.txPackets = Long.parseLong(values[10]); - stats.addValues(entry); - } - } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - public NetworkStats readBpfNetworkStatsDev() throws IOException { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); if (nativeReadNetworkStatsDev(stats) != 0) { From 5497c0e3a3adf8e7d44a5ef1a21ea9324bcc57ad Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 18 Apr 2018 15:44:46 -0700 Subject: [PATCH 0539/1150] Use eBPF map data for per iface stats After adding the xt_bpf module and ifaceStatsMap, eBPF tool can now support reading per interface data. So networkStatsFactory should move away from parsing proc/net/dev and use the eBPF map stats instead. Bug: 72111305 Test: atest com.android.server.net.NetworkStatsServiceTest Change-Id: Ibcc6150d00835b3bd33af22a72e4a86e172581cf Merged-In: Ibcc6150d00835b3bd33af22a72e4a86e172581cf (cherry picked from aosp commit dd65497239c3e4a57d6e2c263b70142352089354) --- .../internal/net/NetworkStatsFactory.java | 19 ++++- ...droid_internal_net_NetworkStatsFactory.cpp | 81 +++++++++++-------- 2 files changed, 63 insertions(+), 37 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 98afebc51b..e5cbdde544 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -178,6 +178,14 @@ public class NetworkStatsFactory { return stats; } + public NetworkStats readBpfNetworkStatsDev() throws IOException { + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); + if (nativeReadNetworkStatsDev(stats) != 0) { + throw new IOException("Failed to parse bpf iface stats"); + } + return stats; + } + /** * Parse and return interface-level summary {@link NetworkStats} measured * using {@code /proc/net/dev} style hooks, which may include non IP layer @@ -188,9 +196,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryDev() throws IOException { - // Return the stats get from /proc/net/dev if switched to bpf module. + // Return xt_bpf stats if switched to bpf module. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -244,9 +252,9 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsSummaryXt() throws IOException { - // Return the stats get from /proc/net/dev if qtaguid module is replaced. + // Return xt_bpf stats if qtaguid module is replaced. if (mUseBpfStats) - return readNetworkStatsIfaceDev(); + return readBpfNetworkStatsDev(); final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); @@ -408,4 +416,7 @@ public class NetworkStatsFactory { @VisibleForTesting public static native int nativeReadNetworkStatsDetail(NetworkStats stats, String path, int limitUid, String[] limitIfaces, int limitTag, boolean useBpfStats); + + @VisibleForTesting + public static native int nativeReadNetworkStatsDev(NetworkStats stats); } diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 99d9839570..c15b7ee4fe 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -205,37 +205,8 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, return 0; } -static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, - jint limitUid, jobjectArray limitIfacesObj, jint limitTag, - jboolean useBpfStats) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } - - std::vector limitIfaces; - if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { - int num = env->GetArrayLength(limitIfacesObj); - for (int i = 0; i < num; i++) { - jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); - ScopedUtfChars string8(env, string); - if (string8.c_str() != NULL) { - limitIfaces.push_back(std::string(string8.c_str())); - } - } - } - std::vector lines; - - - if (useBpfStats) { - if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) - return -1; - } else { - if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, - limitUid, path8.c_str()) < 0) - return -1; - } - +static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, + std::vector& lines) { int size = lines.size(); bool grow = size > env->GetIntField(stats, gNetworkStatsClassInfo.capacity); @@ -308,14 +279,58 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr env->SetObjectField(stats, gNetworkStatsClassInfo.txPackets, txPackets.getJavaArray()); env->SetObjectField(stats, gNetworkStatsClassInfo.operations, operations.getJavaArray()); } - return 0; } +static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, + jint limitUid, jobjectArray limitIfacesObj, jint limitTag, + jboolean useBpfStats) { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + return -1; + } + + std::vector limitIfaces; + if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { + int num = env->GetArrayLength(limitIfacesObj); + for (int i = 0; i < num; i++) { + jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i); + ScopedUtfChars string8(env, string); + if (string8.c_str() != NULL) { + limitIfaces.push_back(std::string(string8.c_str())); + } + } + } + std::vector lines; + + + if (useBpfStats) { + if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) + return -1; + } else { + if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, + limitUid, path8.c_str()) < 0) + return -1; + } + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + +static int readNetworkStatsDev(JNIEnv* env, jclass clazz, jobject stats) { + std::vector lines; + + if (parseBpfNetworkStatsDev(&lines) < 0) + return -1; + + return statsLinesToNetworkStats(env, clazz, stats, lines); +} + static const JNINativeMethod gMethods[] = { { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;IZ)I", - (void*) readNetworkStatsDetail } + (void*) readNetworkStatsDetail }, + { "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I", + (void*) readNetworkStatsDev }, }; int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { From 030dfa0f74c1a58a275c054db827c950014558ae Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 1 May 2018 13:51:13 -0700 Subject: [PATCH 0540/1150] Remove the unused file parsing function With the new xt_bpf support for iface stats. We no longer need to parse the per interface stats from /proc/net/dev. And since the old xt_qtaguid code path also not depend on it, we can completly remove that helper function since no caller is depending on it now. Bug: 72111305 Test: runtest frameworks-net -c com.android.internal.net.NetworkStatsFactoryTest Change-Id: Icb7eaeef0eeb9fdffd32a90316c76ee05bafffbe Merged-In: Icb7eaeef0eeb9fdffd32a90316c76ee05bafffbe (cherry picked from aosp commit 1199060152d65d20104020dcfa9852fdec6be470) --- .../internal/net/NetworkStatsFactory.java | 41 ------------------- 1 file changed, 41 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index e5cbdde544..c4d08c7dc5 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -56,8 +56,6 @@ public class NetworkStatsFactory { private static final boolean USE_NATIVE_PARSING = true; private static final boolean SANITY_CHECK_NATIVE = false; - /** Path to {@code /proc/net/dev}. */ - private final File mStatsIfaceDev; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_fmt}. */ @@ -133,51 +131,12 @@ public class NetworkStatsFactory { @VisibleForTesting public NetworkStatsFactory(File procRoot, boolean useBpfStats) { - mStatsIfaceDev = new File(procRoot, "net/dev"); mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; } - @VisibleForTesting - public NetworkStats readNetworkStatsIfaceDev() throws IOException { - final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads(); - - final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); - final NetworkStats.Entry entry = new NetworkStats.Entry(); - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader(mStatsIfaceDev)); - - // skip first two header lines - reader.readLine(); - reader.readLine(); - - // parse remaining lines - String line; - while ((line = reader.readLine()) != null) { - String[] values = line.trim().split("\\:?\\s+"); - entry.iface = values[0]; - entry.uid = UID_ALL; - entry.set = SET_ALL; - entry.tag = TAG_NONE; - entry.rxBytes = Long.parseLong(values[1]); - entry.rxPackets = Long.parseLong(values[2]); - entry.txBytes = Long.parseLong(values[9]); - entry.txPackets = Long.parseLong(values[10]); - stats.addValues(entry); - } - } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); - } finally { - IoUtils.closeQuietly(reader); - StrictMode.setThreadPolicy(savedPolicy); - } - return stats; - } - public NetworkStats readBpfNetworkStatsDev() throws IOException { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 6); if (nativeReadNetworkStatsDev(stats) != 0) { From e6f4604404b1f52cebe8207c7155234f729363f5 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 26 Apr 2018 11:47:14 -0700 Subject: [PATCH 0541/1150] [DO NOT MERGE] Use INetd Constant for IpSec Interface Prefix Convert to using a constant in INetd to ensure that there is a consistent tunnel prefix between Java and native code. Bug: 74560705 Test: atest FramworksNetTest; atest CtsNetTestCases Change-Id: Ida233aac2e6c6b26567463964e0ebac9d52eff1e --- services/core/java/com/android/server/IpSecService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 33ca02fecb..60f1877d37 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -107,7 +107,6 @@ public class IpSecService extends IIpSecService.Stub { static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer - static final String TUNNEL_INTERFACE_PREFIX = "ipsec"; /* Binder context for this service */ private final Context mContext; @@ -1270,7 +1269,7 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; final int ikey = reserveNetId(); final int okey = reserveNetId(); - String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId); + String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId); try { // Calls to netd: From a43eb59a079fd340f032bedf96af7e1238af464a Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 26 Apr 2018 11:47:14 -0700 Subject: [PATCH 0542/1150] Use INetd Constant for IpSec Interface Prefix Convert to using a constant in INetd to ensure that there is a consistent tunnel prefix between Java and native code. Bug: 74560705 Test: atest FramworksNetTest; atest CtsNetTestCases Change-Id: Ida233aac2e6c6b26567463964e0ebac9d52eff1e (cherry picked from commit e6f4604404b1f52cebe8207c7155234f729363f5) --- services/core/java/com/android/server/IpSecService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index bde6bd8db6..35bde8e18d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -104,7 +104,6 @@ public class IpSecService extends IIpSecService.Stub { static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer - static final String TUNNEL_INTERFACE_PREFIX = "ipsec"; /* Binder context for this service */ private final Context mContext; @@ -1257,7 +1256,7 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; final int ikey = reserveNetId(); final int okey = reserveNetId(); - String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId); + String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId); try { // Calls to netd: From ae2fabaae0d066183e74af5937daa7e9cf08d5dc Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 26 Apr 2018 11:47:14 -0700 Subject: [PATCH 0543/1150] Use INetd Constant for IpSec Interface Prefix Convert to using a constant in INetd to ensure that there is a consistent tunnel prefix between Java and native code. Bug: 74560705 Test: atest FramworksNetTest; atest CtsNetTestCases Change-Id: Ida233aac2e6c6b26567463964e0ebac9d52eff1e (cherry picked from commit e6f4604404b1f52cebe8207c7155234f729363f5) --- services/core/java/com/android/server/IpSecService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 33ca02fecb..60f1877d37 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -107,7 +107,6 @@ public class IpSecService extends IIpSecService.Stub { static final int FREE_PORT_MIN = 1024; // ports 1-1023 are reserved static final int PORT_MAX = 0xFFFF; // ports are an unsigned 16-bit integer - static final String TUNNEL_INTERFACE_PREFIX = "ipsec"; /* Binder context for this service */ private final Context mContext; @@ -1270,7 +1269,7 @@ public class IpSecService extends IIpSecService.Stub { final int resourceId = mNextResourceId++; final int ikey = reserveNetId(); final int okey = reserveNetId(); - String intfName = String.format("%s%d", TUNNEL_INTERFACE_PREFIX, resourceId); + String intfName = String.format("%s%d", INetd.IPSEC_INTERFACE_PREFIX, resourceId); try { // Calls to netd: From ca8601efd10d22eb1694e8708a9aa80764b23856 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 18 May 2018 17:10:07 -0700 Subject: [PATCH 0544/1150] Check for bpf support at NetworkStatsService start The current implementation check for bpf map existance whenever a NetworkStats request comes in. The check is not efficient and may require additional permission for threads. So a member variable is added to NetworkStatsService to store the bpf configuration status and is initialized when NetworkStatsService start. Test: -m CtsNetTestCases -t android.net.cts.TrafficStatsTest -m CtsUsageStatsTestCases -t android.app.usage.cts.NetworkUsageStatsTest Bug: 79994577 Change-Id: I872ae18fb3e9631a4e6c4d773fefbba32e60a03b --- .../java/com/android/server/net/NetworkStatsService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9ef6c66b07..492c6d6d51 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -184,6 +184,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final PowerManager.WakeLock mWakeLock; + private final boolean mUseBpfTrafficStats; + private IConnectivityManager mConnManager; @VisibleForTesting @@ -347,6 +349,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); + mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); LocalServices.addService(NetworkStatsManagerInternal.class, new NetworkStatsManagerInternalImpl()); @@ -947,7 +950,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private boolean checkBpfStatsEnable() { - return new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + return mUseBpfTrafficStats; } /** From 82739ed5848ca150737acc2bd16edc4066b227da Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 22 May 2018 11:35:29 -0600 Subject: [PATCH 0545/1150] Last-ditch clamping of negative NetworkStats. We've seen reports of negative values flowing through to attempt being recorded, which will outright crash. This change does one last-ditch check to see if we're about to work with negative values, reporting any trouble and clamping them to zero so we don't crash. This gives us the data we need to continue investigating without triggering runtime restarts in the field. Bug: 80057433 Test: atest android.net.NetworkStatsTest Change-Id: I8174391c6cf5dadc2c2c10a8d841ee07e1f7d934 --- core/java/android/net/NetworkStats.java | 2 ++ .../server/net/NetworkStatsRecorder.java | 14 +++++++++++++ .../server/net/NetworkStatsService.java | 20 +++++++++++++++---- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f0dd2629f9..edf9bc1c6b 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1100,6 +1100,8 @@ public class NetworkStats implements Parcelable { public interface NonMonotonicObserver { public void foundNonMonotonic( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); + public void foundNonMonotonic( + NetworkStats stats, int statsIndex, C cookie); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index 4bee55ef8b..a16dcf358d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -241,6 +241,20 @@ public class NetworkStatsRecorder { NetworkStats.Entry entry = null; for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); + + // As a last-ditch sanity check, report any negative values and + // clamp them so recording below doesn't croak. + if (entry.isNegative()) { + if (mObserver != null) { + mObserver.foundNonMonotonic(delta, i, mCookie); + } + entry.rxBytes = Math.max(entry.rxBytes, 0); + entry.rxPackets = Math.max(entry.rxPackets, 0); + entry.txBytes = Math.max(entry.txBytes, 0); + entry.txPackets = Math.max(entry.txPackets, 0); + entry.operations = Math.max(entry.operations, 0); + } + final NetworkIdentitySet ident = ifaceIdent.get(entry.iface); if (ident == null) { unknownIfaces.add(entry.iface); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9ef6c66b07..3354525498 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1713,7 +1713,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, String cookie) { - Log.w(TAG, "found non-monotonic values; saving to dropbox"); + Log.w(TAG, "Found non-monotonic values; saving to dropbox"); // record error for debugging final StringBuilder builder = new StringBuilder(); @@ -1722,9 +1722,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { builder.append("left=").append(left).append('\n'); builder.append("right=").append(right).append('\n'); - final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService( - Context.DROPBOX_SERVICE); - dropBox.addText(TAG_NETSTATS_ERROR, builder.toString()); + mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, + builder.toString()); + } + + @Override + public void foundNonMonotonic( + NetworkStats stats, int statsIndex, String cookie) { + Log.w(TAG, "Found non-monotonic values; saving to dropbox"); + + final StringBuilder builder = new StringBuilder(); + builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n"); + builder.append("stats=").append(stats).append('\n'); + + mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR, + builder.toString()); } } From 3fb56e2ff43ba23e4674a8c98abbe58d015b8934 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 26 Apr 2018 17:52:03 +0900 Subject: [PATCH 0546/1150] Fix testRegisterUsageCallback failure in setUp LocalServices.addService in NetworkStatsService is currently failing with IllegalStateException "Overriding service registration". Setting up LocalServices in the test to avoid this issue might be possible, but moving the registration to the only non-test caller of that constructor as done here solves the issue and avoids side-effects from a constructor. Test: this test passes in master through runtest frameworks-net Bug: b/78487385 Bug: b/80082746 Change-Id: I884a7a8bd7db3fcd220b785ba9914ac8c77720f0 --- .../java/com/android/server/net/NetworkStatsService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 31072415dc..2e8e4a9a29 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -324,6 +324,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { wakeLock, getDefaultClock(), TelephonyManager.getDefault(), new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); + service.registerLocalService(); HandlerThread handlerThread = new HandlerThread(TAG); Handler.Callback callback = new HandlerCallback(service); @@ -333,6 +334,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return service; } + // This must not be called outside of tests, even within the same package, as this constructor + // does not register the local service. Use the create() helper above. @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, @@ -349,7 +352,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + } + private void registerLocalService() { LocalServices.addService(NetworkStatsManagerInternal.class, new NetworkStatsManagerInternalImpl()); } From 9e316bdc17715754422ce87748a70dd507abec9d Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 18 May 2018 17:10:07 -0700 Subject: [PATCH 0547/1150] Check for bpf support at NetworkStatsService start The current implementation check for bpf map existance whenever a NetworkStats request comes in. The check is not efficient and may require additional permission for threads. So a member variable is added to NetworkStatsService to store the bpf configuration status and is initialized when NetworkStatsService start. Test: -m CtsNetTestCases -t android.net.cts.TrafficStatsTest -m CtsUsageStatsTestCases -t android.app.usage.cts.NetworkUsageStatsTest Bug: 79994577 Change-Id: I872ae18fb3e9631a4e6c4d773fefbba32e60a03b Merged-In: I872ae18fb3e9631a4e6c4d773fefbba32e60a03b --- .../java/com/android/server/net/NetworkStatsService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index da40692a43..e5cf394e5a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -179,6 +179,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final PowerManager.WakeLock mWakeLock; + private final boolean mUseBpfTrafficStats; + private IConnectivityManager mConnManager; @VisibleForTesting @@ -328,6 +330,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); + mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); } @VisibleForTesting @@ -916,7 +919,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private boolean checkBpfStatsEnable() { - return new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + return mUseBpfTrafficStats; } /** From a9a8f0389b3d54d44633743a5ef3d2009437d4c5 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Wed, 21 Mar 2018 15:32:42 -0700 Subject: [PATCH 0548/1150] Add MANAGE_IPSEC_TUNNELS Permission Add a new MANAGE_IPSEC_TUNNELS permission and protect all IPsec Tunnel mode APIs with it. This permission is only granted to the system or through an AppOp. Bug: 66955045 Test: compilation Merged-In: I0f618373b500c493ef2211bece681f74652a1833 Change-Id: I0f618373b500c493ef2211bece681f74652a1833 (cherry picked from commit 9a713bd28ec77d361041025496d73a8935621f79) --- core/java/android/net/IpSecManager.java | 6 ++++-- core/java/android/net/IpSecTransform.java | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index cc227713cb..d2c83e2b5e 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -691,6 +691,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull LinkAddress address) throws IOException { try { mService.addAddressToTunnelInterface(mResourceId, address); @@ -708,6 +709,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull LinkAddress address) throws IOException { try { mService.removeAddressFromTunnelInterface(mResourceId, address); @@ -801,7 +803,7 @@ public final class IpSecManager { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { @@ -826,7 +828,7 @@ public final class IpSecManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index cf58647bbb..099fe02fdd 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -282,7 +282,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, @@ -325,7 +325,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @RequiresPermission(anyOf = { - android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD }) public void stopNattKeepalive() { @@ -478,7 +478,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @NonNull - @RequiresPermission(android.Manifest.permission.NETWORK_STACK) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, @NonNull IpSecManager.SecurityParameterIndex spi) From a78f084edb21acc55883903dac0a0911aed4e721 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 15 Mar 2018 18:06:06 -0700 Subject: [PATCH 0549/1150] Add AppOps Checks for MANAGE_IPSEC_TUNNELS Adds support for a new AppOp to permit services to use IpSec tunnel mode. The IpSecService now needs a context so change the service mode to a cached service rather than a static service. Bug: 66955045 Test: runtest frameworks-net Merged-In: I17a4a286225b432c3e15ea1587d946189931b4f4 Change-Id: I17a4a286225b432c3e15ea1587d946189931b4f4 (cherry picked from commit a10a7f99c4b3de81bbbd246eeecc95d77730aced) --- core/java/android/net/IIpSecService.aidl | 20 ++++--- core/java/android/net/IpSecManager.java | 25 +++++--- core/java/android/net/IpSecTransform.java | 3 +- .../java/com/android/server/IpSecService.java | 59 ++++++++++++++----- 4 files changed, 76 insertions(+), 31 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index 3a3ddcc483..d6774d47b4 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -45,25 +45,31 @@ interface IIpSecService in String localAddr, in String remoteAddr, in Network underlyingNetwork, - in IBinder binder); + in IBinder binder, + in String callingPackage); void addAddressToTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); void removeAddressFromTunnelInterface( int tunnelResourceId, - in LinkAddress localAddr); + in LinkAddress localAddr, + in String callingPackage); - void deleteTunnelInterface(int resourceId); + void deleteTunnelInterface(int resourceId, in String callingPackage); - IpSecTransformResponse createTransform(in IpSecConfig c, in IBinder binder); + IpSecTransformResponse createTransform( + in IpSecConfig c, in IBinder binder, in String callingPackage); void deleteTransform(int transformId); - void applyTransportModeTransform(in ParcelFileDescriptor socket, int direction, int transformId); + void applyTransportModeTransform( + in ParcelFileDescriptor socket, int direction, int transformId); - void applyTunnelModeTransform(int tunnelResourceId, int direction, int transformResourceId); + void applyTunnelModeTransform( + int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); void removeTransportModeTransforms(in ParcelFileDescriptor socket); } diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d2c83e2b5e..0d04fe5a91 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -140,6 +140,7 @@ public final class IpSecManager { } } + private final Context mContext; private final IIpSecService mService; /** @@ -667,6 +668,7 @@ public final class IpSecManager { */ @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { + private final String mOpPackageName; private final IIpSecService mService; private final InetAddress mRemoteAddress; private final InetAddress mLocalAddress; @@ -694,7 +696,8 @@ public final class IpSecManager { @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull LinkAddress address) throws IOException { try { - mService.addAddressToTunnelInterface(mResourceId, address); + mService.addAddressToTunnelInterface( + mResourceId, address, mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -712,16 +715,18 @@ public final class IpSecManager { @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull LinkAddress address) throws IOException { try { - mService.removeAddressFromTunnelInterface(mResourceId, address); + mService.removeAddressFromTunnelInterface( + mResourceId, address, mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - private IpSecTunnelInterface(@NonNull IIpSecService service, + private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { + mOpPackageName = ctx.getOpPackageName(); mService = service; mLocalAddress = localAddress; mRemoteAddress = remoteAddress; @@ -733,7 +738,8 @@ public final class IpSecManager { localAddress.getHostAddress(), remoteAddress.getHostAddress(), underlyingNetwork, - new Binder()); + new Binder(), + mOpPackageName); switch (result.status) { case Status.OK: break; @@ -762,7 +768,7 @@ public final class IpSecManager { @Override public void close() { try { - mService.deleteTunnelInterface(mResourceId); + mService.deleteTunnelInterface(mResourceId, mOpPackageName); mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -807,7 +813,8 @@ public final class IpSecManager { public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { - return new IpSecTunnelInterface(mService, localAddress, remoteAddress, underlyingNetwork); + return new IpSecTunnelInterface( + mContext, mService, localAddress, remoteAddress, underlyingNetwork); } /** @@ -833,7 +840,8 @@ public final class IpSecManager { @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { try { mService.applyTunnelModeTransform( - tunnel.getResourceId(), direction, transform.getResourceId()); + tunnel.getResourceId(), direction, + transform.getResourceId(), mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -845,7 +853,8 @@ public final class IpSecManager { * @param context the application context for this manager * @hide */ - public IpSecManager(IIpSecService service) { + public IpSecManager(Context ctx, IIpSecService service) { + mContext = ctx; mService = checkNotNull(service, "missing service"); } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 099fe02fdd..fb5f46c117 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -130,7 +130,8 @@ public final class IpSecTransform implements AutoCloseable { synchronized (this) { try { IIpSecService svc = getIpSecService(); - IpSecTransformResponse result = svc.createTransform(mConfig, new Binder()); + IpSecTransformResponse result = svc.createTransform( + mConfig, new Binder(), mContext.getOpPackageName()); int status = result.status; checkResultStatus(status); mResourceId = result.resourceId; diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 35bde8e18d..9709885887 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -24,6 +24,8 @@ import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; +import android.annotation.NonNull; +import android.app.AppOpsManager; import android.content.Context; import android.net.ConnectivityManager; import android.net.IIpSecService; @@ -42,6 +44,7 @@ import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; +import android.os.DeadSystemException; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -973,6 +976,13 @@ public class IpSecService extends IIpSecService.Stub { return service; } + @NonNull + private AppOpsManager getAppOpsManager() { + AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); + if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); + return appOps; + } + /** @hide */ @VisibleForTesting public IpSecService(Context context, IpSecServiceConfiguration config) { @@ -1239,7 +1249,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( - String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder) { + String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, + String callingPackage) { + enforceTunnelPermissions(callingPackage); checkNotNull(binder, "Null Binder passed to createTunnelInterface"); checkNotNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); @@ -1319,8 +1331,8 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void addAddressToTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1351,10 +1363,10 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void removeAddressFromTunnelInterface( - int tunnelResourceId, LinkAddress localAddr) { - enforceNetworkStackPermission(); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int tunnelResourceId, LinkAddress localAddr, String callingPackage) { + enforceTunnelPermissions(callingPackage); + UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw // IllegalArgumentException TunnelInterfaceRecord tunnelInterfaceInfo = @@ -1382,7 +1394,9 @@ public class IpSecService extends IIpSecService.Stub { * server */ @Override - public synchronized void deleteTunnelInterface(int resourceId) throws RemoteException { + public synchronized void deleteTunnelInterface( + int resourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); } @@ -1468,7 +1482,6 @@ public class IpSecService extends IIpSecService.Stub { case IpSecTransform.MODE_TRANSPORT: break; case IpSecTransform.MODE_TUNNEL: - enforceNetworkStackPermission(); break; default: throw new IllegalArgumentException( @@ -1476,9 +1489,20 @@ public class IpSecService extends IIpSecService.Stub { } } - private void enforceNetworkStackPermission() { - mContext.enforceCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK, - "IpSecService"); + private void enforceTunnelPermissions(String callingPackage) { + checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); + switch (getAppOpsManager().noteOp( + AppOpsManager.OP_MANAGE_IPSEC_TUNNELS, + Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); + } } private void createOrUpdateTransform( @@ -1534,8 +1558,12 @@ public class IpSecService extends IIpSecService.Stub { * result in all of those sockets becoming unable to send or receive data. */ @Override - public synchronized IpSecTransformResponse createTransform(IpSecConfig c, IBinder binder) - throws RemoteException { + public synchronized IpSecTransformResponse createTransform( + IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { + checkNotNull(c); + if (c.getMode() == IpSecTransform.MODE_TUNNEL) { + enforceTunnelPermissions(callingPackage); + } checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; @@ -1656,8 +1684,9 @@ public class IpSecService extends IIpSecService.Stub { */ @Override public synchronized void applyTunnelModeTransform( - int tunnelResourceId, int direction, int transformResourceId) throws RemoteException { - enforceNetworkStackPermission(); + int tunnelResourceId, int direction, + int transformResourceId, String callingPackage) throws RemoteException { + enforceTunnelPermissions(callingPackage); checkDirection(direction); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); From ed6562e362d2e66867e4531ee957e7a85d5ab7b8 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 3 Apr 2018 20:30:54 -0700 Subject: [PATCH 0550/1150] Update IpSecManager to use InetAddress and prefixLen LinkAddress constructors are currently @hide; this change updates IpSecManager to use InetAddress and prefixLen, and then construct a LinkAddress internally. LinkAddress is used over the binder interface to IpSecService to ensure validity. Bug: 77528639 Test: CTS, Java unit tests ran on walleye Merged-In: I19e124adef6d9f4992d8293db3190bcf74c95848 Change-Id: I19e124adef6d9f4992d8293db3190bcf74c95848 (cherry picked from commit e84200fc5b1a7a469822fee2cceb2d469e8aeea2) --- core/java/android/net/IpSecManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 0d04fe5a91..87323755a9 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -690,14 +690,15 @@ public final class IpSecManager { * tunneled traffic. * * @param address the local address for traffic inside the tunnel + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void addAddress(@NonNull LinkAddress address) throws IOException { + public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { mService.addAddressToTunnelInterface( - mResourceId, address, mOpPackageName); + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -709,14 +710,15 @@ public final class IpSecManager { *

            Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed + * @param prefixLen length of the InetAddress prefix * @hide */ @SystemApi @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public void removeAddress(@NonNull LinkAddress address) throws IOException { + public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { mService.removeAddressFromTunnelInterface( - mResourceId, address, mOpPackageName); + mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } From a6722e470f30801baaf7636a088bc8bea583bd7d Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 3 Apr 2018 16:13:19 -0700 Subject: [PATCH 0551/1150] Rework Exception Handling for IpSecManager In order to properly support EOPNOTSUPP this CL applies a consistent approach to handling Exceptions. Hereafter, all exceptions that aren't of a special method-specific type (such as SpiUnavailableException) will all be returned to the calling process unchanged. At the API call site, the ServiceSpecificException, which is really an Errno, will be inspected and either converted to an unchecked exception for types we know, or it will be converted to an IOException in cases where that method can return a checked exception. In cases where we do not expect an errno, we will simply throw a generic RuntimeException. This means all API calls will now properly throw UnsupportedOperationException and may be CTS tested accordingly. Bug: 72420898 Test: runtest frameworks-net Merged-In: I4a00e221618896223fcdb4b4279fb14cd14e34d8 Change-Id: I4a00e221618896223fcdb4b4279fb14cd14e34d8 (cherry picked from commit 21c4188a979c55f336728397e18273978d11f7f4) --- core/java/android/net/IpSecManager.java | 147 ++++++++++++++++-- core/java/android/net/IpSecTransform.java | 16 ++ .../java/com/android/server/IpSecService.java | 71 +++------ 3 files changed, 173 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 87323755a9..1145d5bd4d 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -27,6 +27,9 @@ import android.content.Context; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.system.OsConstants; import android.util.AndroidException; import android.util.Log; @@ -173,11 +176,16 @@ public final class IpSecManager { public void close() { try { mService.releaseSecurityParameterIndex(mResourceId); - mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the SPI was closed properly. */ @@ -228,7 +236,6 @@ public final class IpSecManager { throw new RuntimeException( "Invalid Resource ID returned by IpSecService: " + status); } - } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -240,6 +247,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("SecurityParameterIndex{spi=") + .append(mSpi) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -262,7 +280,11 @@ public final class IpSecManager { mService, destinationAddress, IpSecManager.INVALID_SECURITY_PARAMETER_INDEX); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (SpiUnavailableException unlikely) { + // Because this function allocates a totally random SPI, it really shouldn't ever + // fail to allocate an SPI; we simply need this because the exception is checked. throw new ResourceUnavailableException("No SPIs available"); } } @@ -275,8 +297,8 @@ public final class IpSecManager { * * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. - * @param requestedSpi the requested SPI, or '0' to allocate a random SPI. The range 1-255 is - * reserved and may not be used. See RFC 4303 Section 2.1. + * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See + * RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are * currently allocated for this user @@ -290,7 +312,11 @@ public final class IpSecManager { if (requestedSpi == IpSecManager.INVALID_SECURITY_PARAMETER_INDEX) { throw new IllegalArgumentException("Requested SPI must be a valid (non-zero) SPI"); } - return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + try { + return new SecurityParameterIndex(mService, destinationAddress, requestedSpi); + } catch (ServiceSpecificException e) { + throw rethrowUncheckedExceptionFromServiceSpecificException(e); + } } /** @@ -425,6 +451,8 @@ public final class IpSecManager { // constructor takes control and closes the user's FD when we exit the method. try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.applyTransportModeTransform(pfd, direction, transform.getResourceId()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -483,6 +511,8 @@ public final class IpSecManager { public void removeTransportModeTransforms(@NonNull FileDescriptor socket) throws IOException { try (ParcelFileDescriptor pfd = ParcelFileDescriptor.dup(socket)) { mService.removeTransportModeTransforms(pfd); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -576,6 +606,13 @@ public final class IpSecManager { mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } try { @@ -584,7 +621,6 @@ public final class IpSecManager { Log.e(TAG, "Failed to close UDP Encapsulation Socket with Port= " + mPort); throw e; } - mCloseGuard.close(); } /** Check that the socket was closed properly. */ @@ -601,6 +637,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("UdpEncapsulationSocket{port=") + .append(mPort) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } }; /** @@ -628,7 +675,11 @@ public final class IpSecManager { if (port == 0) { throw new IllegalArgumentException("Specified port must be a valid port number!"); } - return new UdpEncapsulationSocket(mService, port); + try { + return new UdpEncapsulationSocket(mService, port); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -651,7 +702,11 @@ public final class IpSecManager { @NonNull public UdpEncapsulationSocket openUdpEncapsulationSocket() throws IOException, ResourceUnavailableException { - return new UdpEncapsulationSocket(mService, 0); + try { + return new UdpEncapsulationSocket(mService, 0); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -699,6 +754,8 @@ public final class IpSecManager { try { mService.addAddressToTunnelInterface( mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -719,6 +776,8 @@ public final class IpSecManager { try { mService.removeAddressFromTunnelInterface( mResourceId, new LinkAddress(address, prefixLen), mOpPackageName); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -771,11 +830,16 @@ public final class IpSecManager { public void close() { try { mService.deleteTunnelInterface(mResourceId, mOpPackageName); - mResourceId = INVALID_RESOURCE_ID; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); + } finally { + mResourceId = INVALID_RESOURCE_ID; + mCloseGuard.close(); } - mCloseGuard.close(); } /** Check that the Interface was closed properly. */ @@ -792,6 +856,17 @@ public final class IpSecManager { public int getResourceId() { return mResourceId; } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTunnelInterface{ifname=") + .append(mInterfaceName) + .append(",resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } /** @@ -815,8 +890,12 @@ public final class IpSecManager { public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) throws ResourceUnavailableException, IOException { - return new IpSecTunnelInterface( - mContext, mService, localAddress, remoteAddress, underlyingNetwork); + try { + return new IpSecTunnelInterface( + mContext, mService, localAddress, remoteAddress, underlyingNetwork); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); + } } /** @@ -844,6 +923,8 @@ public final class IpSecManager { mService.applyTunnelModeTransform( tunnel.getResourceId(), direction, transform.getResourceId(), mContext.getOpPackageName()); + } catch (ServiceSpecificException e) { + throw rethrowCheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -859,4 +940,44 @@ public final class IpSecManager { mContext = ctx; mService = checkNotNull(service, "missing service"); } + + private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { + // OsConstants are late binding, so switch statements can't be used. + if (sse.errorCode == OsConstants.EINVAL) { + throw new IllegalArgumentException(sse); + } else if (sse.errorCode == OsConstants.EAGAIN) { + throw new IllegalStateException(sse); + } else if (sse.errorCode == OsConstants.EOPNOTSUPP) { + throw new UnsupportedOperationException(sse); + } + } + + /** + * Convert an Errno SSE to the correct Unchecked exception type. + * + * This method never actually returns. + */ + // package + static RuntimeException + rethrowUncheckedExceptionFromServiceSpecificException(ServiceSpecificException sse) { + maybeHandleServiceSpecificException(sse); + throw new RuntimeException(sse); + } + + /** + * Convert an Errno SSE to the correct Checked or Unchecked exception type. + * + * This method may throw IOException, or it may throw an unchecked exception; it will never + * actually return. + */ + // package + static IOException rethrowCheckedExceptionFromServiceSpecificException( + ServiceSpecificException sse) throws IOException { + // First see if this is an unchecked exception of a type we know. + // If so, then we prefer the unchecked (specific) type of exception. + maybeHandleServiceSpecificException(sse); + // If not, then all we can do is provide the SSE in the form of an IOException. + throw new ErrnoException( + "IpSec encountered errno=" + sse.errorCode, sse.errorCode).rethrowAsIOException(); + } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index fb5f46c117..23c8aa368d 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -29,6 +29,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -137,6 +138,8 @@ public final class IpSecTransform implements AutoCloseable { mResourceId = result.resourceId; Log.d(TAG, "Added Transform with Id " + mResourceId); mCloseGuard.open("build"); + } catch (ServiceSpecificException e) { + throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } @@ -181,6 +184,10 @@ public final class IpSecTransform implements AutoCloseable { stopNattKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); + } catch (Exception e) { + // On close we swallow all random exceptions since failure to close is not + // actionable by the user. + Log.e(TAG, "Failed to close " + this + ", Exception=" + e); } finally { mResourceId = INVALID_RESOURCE_ID; mCloseGuard.close(); @@ -507,4 +514,13 @@ public final class IpSecTransform implements AutoCloseable { mConfig = new IpSecConfig(); } } + + @Override + public String toString() { + return new StringBuilder() + .append("IpSecTransform{resourceId=") + .append(mResourceId) + .append("}") + .toString(); + } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 9709885887..60f1877d37 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1100,9 +1100,11 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResource( new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { - // TODO: Add appropriate checks when other ServiceSpecificException types are supported - return new IpSecSpiResponse( - IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + if (e.errorCode == OsConstants.ENOENT) { + return new IpSecSpiResponse( + IpSecManager.Status.SPI_UNAVAILABLE, INVALID_RESOURCE_ID, spi); + } + throw e; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1114,7 +1116,6 @@ public class IpSecService extends IIpSecService.Stub { */ private void releaseResource(RefcountedResourceArray resArray, int resourceId) throws RemoteException { - resArray.getRefcountedResourceOrThrow(resourceId).userRelease(); } @@ -1314,15 +1315,12 @@ public class IpSecService extends IIpSecService.Stub { releaseNetId(ikey); releaseNetId(okey); throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception + } catch (Throwable t) { + // Release keys if we got an error. + releaseNetId(ikey); + releaseNetId(okey); + throw t; } - - // If we make it to here, then something has gone wrong and we couldn't create a VTI. - // Release the keys that we reserved, and return an error status. - releaseNetId(ikey); - releaseNetId(okey); - return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } /** @@ -1351,9 +1349,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1383,9 +1378,6 @@ public class IpSecService extends IIpSecService.Stub { localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); - } catch (ServiceSpecificException e) { - // If we get here, one of the arguments provided was invalid. Wrap the SSE, and throw. - throw new IllegalArgumentException(e); } } @@ -1589,12 +1581,7 @@ public class IpSecService extends IIpSecService.Stub { dependencies.add(refcountedSpiRecord); SpiRecord spiRecord = refcountedSpiRecord.getResource(); - try { - createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - return new IpSecTransformResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); - } + createOrUpdateTransform(c, resourceId, spiRecord, socketRecord); // SA was created successfully, time to construct a record and lock it away userRecord.mTransformRecords.put( @@ -1641,23 +1628,15 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - try { - mSrvConfig - .getNetdInstance() - .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), - resourceId, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); - } catch (ServiceSpecificException e) { - if (e.errorCode == EINVAL) { - throw new IllegalArgumentException(e.toString()); - } else { - throw e; - } - } + mSrvConfig + .getNetdInstance() + .ipSecApplyTransportModeTransform( + socket.getFileDescriptor(), + resourceId, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } /** @@ -1669,13 +1648,9 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - try { - mSrvConfig - .getNetdInstance() - .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); - } catch (ServiceSpecificException e) { - // FIXME: get the error code and throw is at an IOException from Errno Exception - } + mSrvConfig + .getNetdInstance() + .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); } /** From c80723f01be2642eddb5c85dedd82c0c2eedb684 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 15 May 2018 19:18:38 -0700 Subject: [PATCH 0552/1150] Disable the AppOp Restriction for IpSec Tunnels This CL temporarily removes the AppOp restriction that disallows creation of IpSec tunnels due to the lack of the appropriate AppOp in AOSP/master. When the relevant framework merges out to master, this CL should be reverted. Bug: none Test: compilation Change-Id: Ic06c193f85f6bcdd0ead4238825c1add78703cde --- .../java/com/android/server/IpSecService.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 60f1877d37..744ed25f16 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1481,19 +1481,23 @@ public class IpSecService extends IIpSecService.Stub { } } + private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + private void enforceTunnelPermissions(String callingPackage) { checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - switch (getAppOpsManager().noteOp( - AppOpsManager.OP_MANAGE_IPSEC_TUNNELS, - Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); + if (false) { // STOPSHIP if this line is present + switch (getAppOpsManager().noteOp( + TUNNEL_OP, + Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); + } } } From 4300caf11631f9f9470752ffc3cfa4fc014c6a37 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Tue, 15 May 2018 19:18:38 -0700 Subject: [PATCH 0553/1150] Disable the AppOp Restriction for IpSec Tunnels This CL temporarily removes the AppOp restriction that disallows creation of IpSec tunnels due to the lack of the appropriate AppOp in AOSP/master. When the relevant framework merges out to master, this CL should be reverted. Manually merging this due to skipping a merge conflict at ef9f2740a790feceaa47a24b1a179e93c4ffb5e6 Bug: none Test: compilation Change-Id: Ic06c193f85f6bcdd0ead4238825c1add78703cde --- .../java/com/android/server/IpSecService.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 60f1877d37..744ed25f16 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1481,19 +1481,23 @@ public class IpSecService extends IIpSecService.Stub { } } + private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + private void enforceTunnelPermissions(String callingPackage) { checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - switch (getAppOpsManager().noteOp( - AppOpsManager.OP_MANAGE_IPSEC_TUNNELS, - Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); + if (false) { // STOPSHIP if this line is present + switch (getAppOpsManager().noteOp( + TUNNEL_OP, + Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); + } } } From 334a7559650b4d630e18b405d0744c9e0254f0cd Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 25 Jun 2018 21:51:14 +0800 Subject: [PATCH 0554/1150] DO NOT MERGE: use legacy way to get tcp packet count The current networkStats getIfaceStats implementation check if bpf is enabled, and use bpf to get all traffic stats. However, the bpf implementation did not contain tcp packet counts. So data stall detection in DcTracker could not get the packet count to trigger data stall. Hence the data stall never triggers for device that enables bpf. This solution is for short term solution that rollback the design to use xt_qtaguid for bpf enabled device. Bug: 110443385 Test: 1. fake data stall to trigger data stall recovery 2. enable debug log to make sure tcp packet count is correct 3. runtest frameworks-net 4. run cts -m CtsUsageStatsTestCases Change-Id: I1ce9e92fe194da2ea0a3eec014fd50bb50cdd44a --- .../java/com/android/server/net/NetworkStatsService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index addc479404..fec510f28a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -941,7 +941,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getIfaceStats(String iface, int type) { - return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + // eBPF code doesn't provide per-interface TCP counters. Use xt_qtaguid for now. + // TODO: delete getMobileTcp(Rx|Tx)Packets entirely. See b/110443385 . + if (type == TYPE_TCP_TX_PACKETS || type == TYPE_TCP_RX_PACKETS) { + return nativeGetIfaceStat(iface, type, false); + } else { + return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + } } @Override From 8352975df0299fd9c8a3e1bc056321750915c435 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Tue, 3 Jul 2018 19:22:45 +0100 Subject: [PATCH 0555/1150] Track constructor changes in libcore/ The 2-arg constructor is being removed. Test: build / boot Bug: 111055375 Change-Id: I72413a8c7885f9514a88f59deb649fa755deff92 --- .../android/internal/net/NetworkStatsFactory.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 41802cc606..fb54e69400 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -192,7 +192,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); + throw protocolExceptionWithCause("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -242,7 +242,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing stats", e); + throw protocolExceptionWithCause("problem parsing stats", e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -339,7 +339,7 @@ public class NetworkStatsFactory { reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { - throw new ProtocolException("problem parsing idx " + idx, e); + throw protocolExceptionWithCause("problem parsing idx " + idx, e); } finally { IoUtils.closeQuietly(reader); StrictMode.setThreadPolicy(savedPolicy); @@ -376,4 +376,10 @@ public class NetworkStatsFactory { @VisibleForTesting public static native int nativeReadNetworkStatsDev(NetworkStats stats); + + private static ProtocolException protocolExceptionWithCause(String message, Throwable cause) { + ProtocolException pe = new ProtocolException(message); + pe.initCause(cause); + return pe; + } } From b02b6403f967af2d8f26d3025b291f4d9a9170ce Mon Sep 17 00:00:00 2001 From: kopriva Date: Mon, 23 Jul 2018 18:19:39 -0700 Subject: [PATCH 0556/1150] docs: added Android P behavior change note to untagSocket reference staged here: https://android-dot-devsite.googleplex.com/reference/android/net/TrafficStats#untagSocket(java.net.Socket) Test: make ds-docs Exempt-From-Owner-Approval: Docs-only change Bug: 110484513 Change-Id: I24575e6f4451a019b60c5bf60e17e14a928c6cc3 --- core/java/android/net/TrafficStats.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 40d53b741d..f033268698 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -329,6 +329,14 @@ public class TrafficStats { /** * Remove any statistics parameters from the given {@link Socket}. + *

            + * In Android 8.1 (API level 27) and lower, a socket is automatically + * untagged when it's sent to another process using binder IPC with a + * {@code ParcelFileDescriptor} container. In Android 9.0 (API level 28) + * and higher, the socket tag is kept when the socket is sent to another + * process using binder IPC. You can mimic the previous behavior by + * calling {@code untagSocket()} before sending the socket to another + * process. */ public static void untagSocket(Socket socket) throws SocketException { SocketTagger.get().untag(socket); From c84693ee4e1a045b027020cd0b0c2608f77a7c47 Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Mon, 23 Jul 2018 13:08:30 -0700 Subject: [PATCH 0557/1150] Migrate frameworks/base/services/tests/servicestests to androidx.test See go/jetpack-test-android-migration cherrypicked from ag/4608401 Test: atest FrameworksServicesTests Change-Id: I2d9641c681489135aa3167bb4c9b1296a1a6a4f7 --- .../src/com/android/server/net/IpConfigStoreTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java index 9f4b754621..7767a2810a 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -27,9 +27,10 @@ import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; -import android.support.test.runner.AndroidJUnit4; import android.util.ArrayMap; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; From d5f95cda0740599f474b22460573dcd9bc054b8c Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 26 Apr 2018 17:52:03 +0900 Subject: [PATCH 0558/1150] Fix testRegisterUsageCallback failure in setUp LocalServices.addService in NetworkStatsService is currently failing with IllegalStateException "Overriding service registration". Setting up LocalServices in the test to avoid this issue might be possible, but moving the registration to the only non-test caller of that constructor as done here solves the issue and avoids side-effects from a constructor. Test: atest FrameworksNetTests does not choke on this test Bug: b/78487385 Bug: b/80082746 Change-Id: I5dba98fc79aec0800c8b71e6c7e23d1cfbcae852 Merged-In: I884a7a8bd7db3fcd220b785ba9914ac8c77720f0 (Clean cherry-pick of go/ag/4061255) --- .../java/com/android/server/net/NetworkStatsService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index aba75ddb45..60e9eaab57 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -324,6 +324,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { wakeLock, getDefaultClock(), TelephonyManager.getDefault(), new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); + service.registerLocalService(); HandlerThread handlerThread = new HandlerThread(TAG); Handler.Callback callback = new HandlerCallback(service); @@ -333,6 +334,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return service; } + // This must not be called outside of tests, even within the same package, as this constructor + // does not register the local service. Use the create() helper above. @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, @@ -349,7 +352,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + } + private void registerLocalService() { LocalServices.addService(NetworkStatsManagerInternal.class, new NetworkStatsManagerInternalImpl()); } From af185b2266f5506ab8dcd5545cb252c25687dc47 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 14 Aug 2018 14:17:44 +0100 Subject: [PATCH 0559/1150] Add @UnsupportedAppUsage annotations For packages: android.app.usage android.app.trust android.app.timezonedetector android.app.timezone android.app.timedetector android.app.job android.app.backup android.app.assist android.app.admin android.app This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I618c5dc4462ae990d9df45c3e9ed3f092cc5138c --- core/java/android/app/usage/NetworkStatsManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f46f207d6..59ae3347f4 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; @@ -121,6 +122,7 @@ public class NetworkStatsManager { /** * {@hide} */ + @UnsupportedAppUsage public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); From 3e0fe9f02ee99ac85e4fd8f386a6b7564fdd66bf Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 14 Aug 2018 14:25:44 +0100 Subject: [PATCH 0560/1150] Add @UnsupportedAppUsage annotations For packages: android.app.usage android.app.trust android.app.timezonedetector android.app.timezone android.app.timedetector android.app.job android.app.backup android.app.assist android.app.admin android.app This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I5d15d50344d7178617418846917f693cfabf006b Merged-In: I618c5dc4462ae990d9df45c3e9ed3f092cc5138c --- core/java/android/app/usage/NetworkStatsManager.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f46f207d6..59ae3347f4 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.app.usage.NetworkStats.Bucket; import android.content.Context; import android.net.ConnectivityManager; @@ -121,6 +122,7 @@ public class NetworkStatsManager { /** * {@hide} */ + @UnsupportedAppUsage public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); From e93928d758dd3c347c429ee9330e2ec1eb23fade Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 8 Aug 2018 14:44:44 +0100 Subject: [PATCH 0561/1150] Add @UnsupportedAppUsage annotations For packages: android.net.wimax android.net.wifi.p2p.nsd android.net.wifi.p2p android.net.wifi.hotspot2.pps android.net.wifi.hotspot2.omadm android.net.wifi.hotspot2 android.net.wifi.aware android.net.wifi android.net.util android.net.sip android.net.rtp android.net.nsd android.net.metrics android.net.lowpan android.net.http android.net.captiveportal android.net This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I520be7a4c79e68310c12e4f55bf66acaa94145a1 --- core/java/android/net/EthernetManager.java | 9 +++++ core/java/android/net/NetworkStats.java | 36 +++++++++++++++++++ .../java/android/net/NetworkStatsHistory.java | 18 ++++++++++ core/java/android/net/NetworkTemplate.java | 11 ++++++ core/java/android/net/TrafficStats.java | 7 ++++ core/java/android/net/nsd/NsdServiceInfo.java | 2 ++ 6 files changed, 83 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index ecccda588a..72565024d3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.SystemService; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Message; @@ -66,6 +67,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. */ + @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -84,6 +86,7 @@ public class EthernetManager { * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ + @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -95,6 +98,7 @@ public class EthernetManager { /** * Set Ethernet configuration. */ + @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -106,6 +110,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. */ + @UnsupportedAppUsage public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -115,6 +120,7 @@ public class EthernetManager { * * @param iface Ethernet interface name */ + @UnsupportedAppUsage public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -128,6 +134,7 @@ public class EthernetManager { * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. */ + @UnsupportedAppUsage public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -145,6 +152,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. */ + @UnsupportedAppUsage public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -158,6 +166,7 @@ public class EthernetManager { * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. */ + @UnsupportedAppUsage public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index edf9bc1c6b..e270fc2e39 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -110,25 +111,43 @@ public class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; + @UnsupportedAppUsage private int size; + @UnsupportedAppUsage private int capacity; + @UnsupportedAppUsage private String[] iface; + @UnsupportedAppUsage private int[] uid; + @UnsupportedAppUsage private int[] set; + @UnsupportedAppUsage private int[] tag; + @UnsupportedAppUsage private int[] metered; + @UnsupportedAppUsage private int[] roaming; + @UnsupportedAppUsage private int[] defaultNetwork; + @UnsupportedAppUsage private long[] rxBytes; + @UnsupportedAppUsage private long[] rxPackets; + @UnsupportedAppUsage private long[] txBytes; + @UnsupportedAppUsage private long[] txPackets; + @UnsupportedAppUsage private long[] operations; public static class Entry { + @UnsupportedAppUsage public String iface; + @UnsupportedAppUsage public int uid; + @UnsupportedAppUsage public int set; + @UnsupportedAppUsage public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -148,12 +167,17 @@ public class NetworkStats implements Parcelable { * getSummary(). */ public int defaultNetwork; + @UnsupportedAppUsage public long rxBytes; + @UnsupportedAppUsage public long rxPackets; + @UnsupportedAppUsage public long txBytes; + @UnsupportedAppUsage public long txPackets; public long operations; + @UnsupportedAppUsage public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -240,6 +264,7 @@ public class NetworkStats implements Parcelable { } } + @UnsupportedAppUsage public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; @@ -263,6 +288,7 @@ public class NetworkStats implements Parcelable { } } + @UnsupportedAppUsage public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); @@ -399,6 +425,7 @@ public class NetworkStats implements Parcelable { /** * Return specific stats entry. */ + @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = iface[i]; @@ -432,6 +459,7 @@ public class NetworkStats implements Parcelable { return SystemClock.elapsedRealtime() - elapsedRealtime; } + @UnsupportedAppUsage public int size() { return size; } @@ -460,6 +488,7 @@ public class NetworkStats implements Parcelable { * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can * also be used to subtract values from existing rows. */ + @UnsupportedAppUsage public NetworkStats combineValues(Entry entry) { final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, entry.defaultNetwork); @@ -479,6 +508,7 @@ public class NetworkStats implements Parcelable { /** * Combine all values from another {@link NetworkStats} into this object. */ + @UnsupportedAppUsage public void combineAllValues(NetworkStats another) { NetworkStats.Entry entry = null; for (int i = 0; i < another.size; i++) { @@ -564,6 +594,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique UIDs known by this data structure. */ + @UnsupportedAppUsage public int[] getUniqueUids() { final SparseBooleanArray uids = new SparseBooleanArray(); for (int uid : this.uid) { @@ -582,6 +613,7 @@ public class NetworkStats implements Parcelable { * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. */ + @UnsupportedAppUsage public long getTotalBytes() { final Entry entry = getTotal(null); return entry.rxBytes + entry.txBytes; @@ -590,6 +622,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object. */ + @UnsupportedAppUsage public Entry getTotal(Entry recycle) { return getTotal(recycle, null, UID_ALL, false); } @@ -598,6 +631,7 @@ public class NetworkStats implements Parcelable { * Return total of all fields represented by this snapshot object matching * the requested {@link #uid}. */ + @UnsupportedAppUsage public Entry getTotal(Entry recycle, int limitUid) { return getTotal(recycle, null, limitUid, false); } @@ -610,6 +644,7 @@ public class NetworkStats implements Parcelable { return getTotal(recycle, limitIface, UID_ALL, false); } + @UnsupportedAppUsage public Entry getTotalIncludingTags(Entry recycle) { return getTotal(recycle, null, UID_ALL, true); } @@ -1085,6 +1120,7 @@ public class NetworkStats implements Parcelable { return 0; } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkStats createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a13ad659e7..d53e0326ae 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -30,6 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -89,16 +90,23 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; + @UnsupportedAppUsage public long bucketDuration; + @UnsupportedAppUsage public long bucketStart; public long activeTime; + @UnsupportedAppUsage public long rxBytes; + @UnsupportedAppUsage public long rxPackets; + @UnsupportedAppUsage public long txBytes; + @UnsupportedAppUsage public long txPackets; public long operations; } + @UnsupportedAppUsage public NetworkStatsHistory(long bucketDuration) { this(bucketDuration, 10, FIELD_ALL); } @@ -125,6 +133,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } + @UnsupportedAppUsage public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -210,6 +219,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } + @UnsupportedAppUsage public int size() { return bucketCount; } @@ -218,6 +228,7 @@ public class NetworkStatsHistory implements Parcelable { return bucketDuration; } + @UnsupportedAppUsage public long getStart() { if (bucketCount > 0) { return bucketStart[0]; @@ -226,6 +237,7 @@ public class NetworkStatsHistory implements Parcelable { } } + @UnsupportedAppUsage public long getEnd() { if (bucketCount > 0) { return bucketStart[bucketCount - 1] + bucketDuration; @@ -245,6 +257,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ + @UnsupportedAppUsage public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -272,6 +285,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ + @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; @@ -373,6 +387,7 @@ public class NetworkStatsHistory implements Parcelable { * Record an entire {@link NetworkStatsHistory} into this history. Usually * for combining together stats for external reporting. */ + @UnsupportedAppUsage public void recordEntireHistory(NetworkStatsHistory input) { recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); } @@ -509,6 +524,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ + @UnsupportedAppUsage public Entry getValues(long start, long end, Entry recycle) { return getValues(start, end, Long.MAX_VALUE, recycle); } @@ -517,6 +533,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ + @UnsupportedAppUsage public Entry getValues(long start, long end, long now, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketDuration = end - start; @@ -701,6 +718,7 @@ public class NetworkStatsHistory implements Parcelable { return writer.toString(); } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkStatsHistory createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 74233fd990..bb75c63436 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; @@ -96,6 +97,7 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); } @@ -104,6 +106,7 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } @@ -112,11 +115,13 @@ public class NetworkTemplate implements Parcelable { * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @Deprecated + @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifi() { return buildTemplateWifiWildcard(); } @@ -133,6 +138,7 @@ public class NetworkTemplate implements Parcelable { * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style * networks together. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateEthernet() { return new NetworkTemplate(MATCH_ETHERNET, null, null); } @@ -173,6 +179,7 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } @@ -293,10 +300,12 @@ public class NetworkTemplate implements Parcelable { } } + @UnsupportedAppUsage public int getMatchRule() { return mMatchRule; } + @UnsupportedAppUsage public String getSubscriberId() { return mSubscriberId; } @@ -460,6 +469,7 @@ public class NetworkTemplate implements Parcelable { * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. */ + @UnsupportedAppUsage public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { // Requested template subscriber is part of the merge group; return @@ -471,6 +481,7 @@ public class NetworkTemplate implements Parcelable { } } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkTemplate createFromParcel(Parcel in) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index f033268698..a463afa2e1 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; @@ -141,6 +142,7 @@ public class TrafficStats { private static INetworkStatsService sStatsService; + @UnsupportedAppUsage private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { sStatsService = INetworkStatsService.Stub.asInterface( @@ -536,6 +538,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -551,6 +554,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -584,6 +588,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getTxBytes(String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); @@ -593,6 +598,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getRxBytes(String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); @@ -948,6 +954,7 @@ public class TrafficStats { * Interfaces are never removed from this list, so counters should always be * monotonic. */ + @UnsupportedAppUsage private static String[] getMobileIfaces() { try { return getStatsService().getMobileIfaces(); diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index bccaf60e69..9ba17edfb9 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -17,6 +17,7 @@ package android.net.nsd; import android.annotation.NonNull; +import android.annotation.UnsupportedAppUsage; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; @@ -185,6 +186,7 @@ public final class NsdServiceInfo implements Parcelable { } /** @hide */ + @UnsupportedAppUsage public void setAttribute(String key, byte[] value) { if (TextUtils.isEmpty(key)) { throw new IllegalArgumentException("Key cannot be empty"); From 05f61129dc8b28288e3b5404964d6e36315333a9 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 8 Aug 2018 14:52:47 +0100 Subject: [PATCH 0562/1150] Add @UnsupportedAppUsage annotations For packages: android.net.wimax android.net.wifi.p2p.nsd android.net.wifi.p2p android.net.wifi.hotspot2.pps android.net.wifi.hotspot2.omadm android.net.wifi.hotspot2 android.net.wifi.aware android.net.wifi android.net.util android.net.sip android.net.rtp android.net.nsd android.net.metrics android.net.lowpan android.net.http android.net.captiveportal android.net This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: Ie25423113ee1a8071cd5039382c00de6ce0af7fd Merged-In: I520be7a4c79e68310c12e4f55bf66acaa94145a1 --- core/java/android/net/EthernetManager.java | 9 +++++ core/java/android/net/NetworkStats.java | 36 +++++++++++++++++++ .../java/android/net/NetworkStatsHistory.java | 18 ++++++++++ core/java/android/net/NetworkTemplate.java | 11 ++++++ core/java/android/net/TrafficStats.java | 7 ++++ core/java/android/net/nsd/NsdServiceInfo.java | 2 ++ 6 files changed, 83 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index ecccda588a..72565024d3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.SystemService; +import android.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; import android.os.Message; @@ -66,6 +67,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. */ + @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -84,6 +86,7 @@ public class EthernetManager { * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. */ + @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -95,6 +98,7 @@ public class EthernetManager { /** * Set Ethernet configuration. */ + @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -106,6 +110,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. */ + @UnsupportedAppUsage public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -115,6 +120,7 @@ public class EthernetManager { * * @param iface Ethernet interface name */ + @UnsupportedAppUsage public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -128,6 +134,7 @@ public class EthernetManager { * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. */ + @UnsupportedAppUsage public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -145,6 +152,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. */ + @UnsupportedAppUsage public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -158,6 +166,7 @@ public class EthernetManager { * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. */ + @UnsupportedAppUsage public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index edf9bc1c6b..e270fc2e39 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -110,25 +111,43 @@ public class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; + @UnsupportedAppUsage private int size; + @UnsupportedAppUsage private int capacity; + @UnsupportedAppUsage private String[] iface; + @UnsupportedAppUsage private int[] uid; + @UnsupportedAppUsage private int[] set; + @UnsupportedAppUsage private int[] tag; + @UnsupportedAppUsage private int[] metered; + @UnsupportedAppUsage private int[] roaming; + @UnsupportedAppUsage private int[] defaultNetwork; + @UnsupportedAppUsage private long[] rxBytes; + @UnsupportedAppUsage private long[] rxPackets; + @UnsupportedAppUsage private long[] txBytes; + @UnsupportedAppUsage private long[] txPackets; + @UnsupportedAppUsage private long[] operations; public static class Entry { + @UnsupportedAppUsage public String iface; + @UnsupportedAppUsage public int uid; + @UnsupportedAppUsage public int set; + @UnsupportedAppUsage public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -148,12 +167,17 @@ public class NetworkStats implements Parcelable { * getSummary(). */ public int defaultNetwork; + @UnsupportedAppUsage public long rxBytes; + @UnsupportedAppUsage public long rxPackets; + @UnsupportedAppUsage public long txBytes; + @UnsupportedAppUsage public long txPackets; public long operations; + @UnsupportedAppUsage public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -240,6 +264,7 @@ public class NetworkStats implements Parcelable { } } + @UnsupportedAppUsage public NetworkStats(long elapsedRealtime, int initialSize) { this.elapsedRealtime = elapsedRealtime; this.size = 0; @@ -263,6 +288,7 @@ public class NetworkStats implements Parcelable { } } + @UnsupportedAppUsage public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); @@ -399,6 +425,7 @@ public class NetworkStats implements Parcelable { /** * Return specific stats entry. */ + @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = iface[i]; @@ -432,6 +459,7 @@ public class NetworkStats implements Parcelable { return SystemClock.elapsedRealtime() - elapsedRealtime; } + @UnsupportedAppUsage public int size() { return size; } @@ -460,6 +488,7 @@ public class NetworkStats implements Parcelable { * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can * also be used to subtract values from existing rows. */ + @UnsupportedAppUsage public NetworkStats combineValues(Entry entry) { final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered, entry.roaming, entry.defaultNetwork); @@ -479,6 +508,7 @@ public class NetworkStats implements Parcelable { /** * Combine all values from another {@link NetworkStats} into this object. */ + @UnsupportedAppUsage public void combineAllValues(NetworkStats another) { NetworkStats.Entry entry = null; for (int i = 0; i < another.size; i++) { @@ -564,6 +594,7 @@ public class NetworkStats implements Parcelable { /** * Return list of unique UIDs known by this data structure. */ + @UnsupportedAppUsage public int[] getUniqueUids() { final SparseBooleanArray uids = new SparseBooleanArray(); for (int uid : this.uid) { @@ -582,6 +613,7 @@ public class NetworkStats implements Parcelable { * Return total bytes represented by this snapshot object, usually used when * checking if a {@link #subtract(NetworkStats)} delta passes a threshold. */ + @UnsupportedAppUsage public long getTotalBytes() { final Entry entry = getTotal(null); return entry.rxBytes + entry.txBytes; @@ -590,6 +622,7 @@ public class NetworkStats implements Parcelable { /** * Return total of all fields represented by this snapshot object. */ + @UnsupportedAppUsage public Entry getTotal(Entry recycle) { return getTotal(recycle, null, UID_ALL, false); } @@ -598,6 +631,7 @@ public class NetworkStats implements Parcelable { * Return total of all fields represented by this snapshot object matching * the requested {@link #uid}. */ + @UnsupportedAppUsage public Entry getTotal(Entry recycle, int limitUid) { return getTotal(recycle, null, limitUid, false); } @@ -610,6 +644,7 @@ public class NetworkStats implements Parcelable { return getTotal(recycle, limitIface, UID_ALL, false); } + @UnsupportedAppUsage public Entry getTotalIncludingTags(Entry recycle) { return getTotal(recycle, null, UID_ALL, true); } @@ -1085,6 +1120,7 @@ public class NetworkStats implements Parcelable { return 0; } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkStats createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index a13ad659e7..d53e0326ae 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -30,6 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -89,16 +90,23 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; + @UnsupportedAppUsage public long bucketDuration; + @UnsupportedAppUsage public long bucketStart; public long activeTime; + @UnsupportedAppUsage public long rxBytes; + @UnsupportedAppUsage public long rxPackets; + @UnsupportedAppUsage public long txBytes; + @UnsupportedAppUsage public long txPackets; public long operations; } + @UnsupportedAppUsage public NetworkStatsHistory(long bucketDuration) { this(bucketDuration, 10, FIELD_ALL); } @@ -125,6 +133,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } + @UnsupportedAppUsage public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -210,6 +219,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } + @UnsupportedAppUsage public int size() { return bucketCount; } @@ -218,6 +228,7 @@ public class NetworkStatsHistory implements Parcelable { return bucketDuration; } + @UnsupportedAppUsage public long getStart() { if (bucketCount > 0) { return bucketStart[0]; @@ -226,6 +237,7 @@ public class NetworkStatsHistory implements Parcelable { } } + @UnsupportedAppUsage public long getEnd() { if (bucketCount > 0) { return bucketStart[bucketCount - 1] + bucketDuration; @@ -245,6 +257,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ + @UnsupportedAppUsage public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -272,6 +285,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ + @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; @@ -373,6 +387,7 @@ public class NetworkStatsHistory implements Parcelable { * Record an entire {@link NetworkStatsHistory} into this history. Usually * for combining together stats for external reporting. */ + @UnsupportedAppUsage public void recordEntireHistory(NetworkStatsHistory input) { recordHistory(input, Long.MIN_VALUE, Long.MAX_VALUE); } @@ -509,6 +524,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ + @UnsupportedAppUsage public Entry getValues(long start, long end, Entry recycle) { return getValues(start, end, Long.MAX_VALUE, recycle); } @@ -517,6 +533,7 @@ public class NetworkStatsHistory implements Parcelable { * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. */ + @UnsupportedAppUsage public Entry getValues(long start, long end, long now, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketDuration = end - start; @@ -701,6 +718,7 @@ public class NetworkStatsHistory implements Parcelable { return writer.toString(); } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkStatsHistory createFromParcel(Parcel in) { diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 74233fd990..bb75c63436 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.removeDoubleQuotes; +import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.util.BackupUtils; @@ -96,6 +97,7 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { return new NetworkTemplate(MATCH_MOBILE, subscriberId, null); } @@ -104,6 +106,7 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } @@ -112,11 +115,13 @@ public class NetworkTemplate implements Parcelable { * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @Deprecated + @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifi() { return buildTemplateWifiWildcard(); } @@ -133,6 +138,7 @@ public class NetworkTemplate implements Parcelable { * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style * networks together. */ + @UnsupportedAppUsage public static NetworkTemplate buildTemplateEthernet() { return new NetworkTemplate(MATCH_ETHERNET, null, null); } @@ -173,6 +179,7 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } @@ -293,10 +300,12 @@ public class NetworkTemplate implements Parcelable { } } + @UnsupportedAppUsage public int getMatchRule() { return mMatchRule; } + @UnsupportedAppUsage public String getSubscriberId() { return mSubscriberId; } @@ -460,6 +469,7 @@ public class NetworkTemplate implements Parcelable { * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. */ + @UnsupportedAppUsage public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { // Requested template subscriber is part of the merge group; return @@ -471,6 +481,7 @@ public class NetworkTemplate implements Parcelable { } } + @UnsupportedAppUsage public static final Creator CREATOR = new Creator() { @Override public NetworkTemplate createFromParcel(Parcel in) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 40d53b741d..44f7e48eda 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -19,6 +19,7 @@ package android.net; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; +import android.annotation.UnsupportedAppUsage; import android.app.DownloadManager; import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; @@ -141,6 +142,7 @@ public class TrafficStats { private static INetworkStatsService sStatsService; + @UnsupportedAppUsage private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { sStatsService = INetworkStatsService.Stub.asInterface( @@ -528,6 +530,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -543,6 +546,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -576,6 +580,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getTxBytes(String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); @@ -585,6 +590,7 @@ public class TrafficStats { } /** {@hide} */ + @UnsupportedAppUsage public static long getRxBytes(String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); @@ -940,6 +946,7 @@ public class TrafficStats { * Interfaces are never removed from this list, so counters should always be * monotonic. */ + @UnsupportedAppUsage private static String[] getMobileIfaces() { try { return getStatsService().getMobileIfaces(); diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index bccaf60e69..9ba17edfb9 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -17,6 +17,7 @@ package android.net.nsd; import android.annotation.NonNull; +import android.annotation.UnsupportedAppUsage; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; @@ -185,6 +186,7 @@ public final class NsdServiceInfo implements Parcelable { } /** @hide */ + @UnsupportedAppUsage public void setAttribute(String key, byte[] value) { if (TextUtils.isEmpty(key)) { throw new IllegalArgumentException("Key cannot be empty"); From 1f7f52b16ec7c65c5ebd36450f9a36b45a0a0e1d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 13 Aug 2018 15:54:27 +0900 Subject: [PATCH 0563/1150] Add DhcpServer This first version can serve discover/request/release, although there are some small behavior changes with current implementation which will be addressed later. Also removes final modifiers on start() and stop() in FdEventsReader, to allow mocking the methods in tests with the current mockito lib. Test: Added tests pass, manual: flashed a device using the server Change-Id: I025366ff7d51c4ba31152af50f3dd2b5e280a54d --- core/java/android/net/TrafficStats.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 44f7e48eda..1b22911f0c 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -139,6 +139,8 @@ public class TrafficStats { public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; /** @hide */ public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; + /** @hide */ + public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; From 780297fa130217ca9023a1e085079fe278717ddf Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 7 May 2018 20:06:44 -0700 Subject: [PATCH 0564/1150] Use tunnel local/remote addresses in security policies This patch changes tunnel mode security policies to use the actual tunnel's local and remote addresses to select the SA. This prevents the kernel from calling xfrm_get_saddr(), which does a route lookup, potentially resolving an incorrect saddr. Bug: 79384676 Test: CTS, IpSecService* tests passing Change-Id: I8223225e2363a79591a0bb0040aa8619cf84c184 --- .../java/com/android/server/IpSecService.java | 84 ++++++++++--------- 1 file changed, 46 insertions(+), 38 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 744ed25f16..01e81525d5 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -27,7 +27,6 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; -import android.net.ConnectivityManager; import android.net.IIpSecService; import android.net.INetd; import android.net.IpSecAlgorithm; @@ -44,7 +43,6 @@ import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; -import android.os.DeadSystemException; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -89,9 +87,8 @@ public class IpSecService extends IIpSecService.Stub { private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); private static final String NETD_SERVICE_NAME = "netd"; - private static final int[] DIRECTIONS = - new int[] {IpSecManager.DIRECTION_OUT, IpSecManager.DIRECTION_IN}; - private static final String[] WILDCARD_ADDRESSES = new String[]{"0.0.0.0", "::"}; + private static final int[] ADDRESS_FAMILIES = + new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms private static final int MAX_PORT_BIND_ATTEMPTS = 10; @@ -819,16 +816,22 @@ public class IpSecService extends IIpSecService.Stub { // Teardown VTI // Delete global policies try { - mSrvConfig.getNetdInstance().removeVirtualTunnelInterface(mInterfaceName); + final INetd netd = mSrvConfig.getNetdInstance(); + netd.removeVirtualTunnelInterface(mInterfaceName); - for(String wildcardAddr : WILDCARD_ADDRESSES) { - for (int direction : DIRECTIONS) { - int mark = (direction == IpSecManager.DIRECTION_IN) ? mIkey : mOkey; - mSrvConfig - .getNetdInstance() - .ipSecDeleteSecurityPolicy( - 0, direction, wildcardAddr, wildcardAddr, mark, 0xffffffff); - } + for (int selAddrFamily : ADDRESS_FAMILIES) { + netd.ipSecDeleteSecurityPolicy( + 0, + selAddrFamily, + IpSecManager.DIRECTION_OUT, + mOkey, + 0xffffffff); + netd.ipSecDeleteSecurityPolicy( + 0, + selAddrFamily, + IpSecManager.DIRECTION_IN, + mIkey, + 0xffffffff); } } catch (ServiceSpecificException | RemoteException e) { Log.e( @@ -1276,25 +1279,29 @@ public class IpSecService extends IIpSecService.Stub { // Create VTI // Add inbound/outbound global policies // (use reqid = 0) - mSrvConfig - .getNetdInstance() - .addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); + final INetd netd = mSrvConfig.getNetdInstance(); + netd.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); - for(String wildcardAddr : WILDCARD_ADDRESSES) { - for (int direction : DIRECTIONS) { - int mark = (direction == IpSecManager.DIRECTION_OUT) ? okey : ikey; - - mSrvConfig - .getNetdInstance() - .ipSecAddSecurityPolicy( - 0, // Use 0 for reqId - direction, - wildcardAddr, - wildcardAddr, - 0, - mark, - 0xffffffff); - } + for (int selAddrFamily : ADDRESS_FAMILIES) { + // Always send down correct local/remote addresses for template. + netd.ipSecAddSecurityPolicy( + 0, // Use 0 for reqId + selAddrFamily, + IpSecManager.DIRECTION_OUT, + localAddr, + remoteAddr, + 0, + okey, + 0xffffffff); + netd.ipSecAddSecurityPolicy( + 0, // Use 0 for reqId + selAddrFamily, + IpSecManager.DIRECTION_IN, + remoteAddr, + localAddr, + 0, + ikey, + 0xffffffff); } userRecord.mTunnelInterfaceRecords.put( @@ -1693,9 +1700,9 @@ public class IpSecService extends IIpSecService.Stub { SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId()); int mark = - (direction == IpSecManager.DIRECTION_IN) - ? tunnelInterfaceInfo.getIkey() - : tunnelInterfaceInfo.getOkey(); + (direction == IpSecManager.DIRECTION_OUT) + ? tunnelInterfaceInfo.getOkey() + : tunnelInterfaceInfo.getIkey(); try { c.setMarkValue(mark); @@ -1706,14 +1713,15 @@ public class IpSecService extends IIpSecService.Stub { c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); // If outbound, also add SPI to the policy. - for(String wildcardAddr : WILDCARD_ADDRESSES) { + for (int selAddrFamily : ADDRESS_FAMILIES) { mSrvConfig .getNetdInstance() .ipSecUpdateSecurityPolicy( 0, // Use 0 for reqId + selAddrFamily, direction, - wildcardAddr, - wildcardAddr, + tunnelInterfaceInfo.getLocalAddress(), + tunnelInterfaceInfo.getRemoteAddress(), transformInfo.getSpiRecord().getSpi(), mark, 0xffffffff); From 0df4ff77dba0407775ac764924f84c386471c44e Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 25 Jul 2018 13:06:29 -0700 Subject: [PATCH 0565/1150] Use UID as requestID This change makes all requestIDs use the UID of the creator, ensuring that rekeys always use the same requestID. This also has the nice property of separating app's resources from each other, and allowing for identification of which app/UID allocated the resources from command-line dumps (eg ip xfrm state show) Bug: 111841561 Test: Updated tests & passing taimen Change-Id: I4f1eadcdb795766ae4682b15e41727359c52fa38 --- .../java/com/android/server/IpSecService.java | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 01e81525d5..380f6a7e58 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -612,7 +612,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, + uid, mConfig.getSourceAddress(), mConfig.getDestinationAddress(), spi, @@ -679,7 +679,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - mResourceId, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -821,13 +821,13 @@ public class IpSecService extends IIpSecService.Stub { for (int selAddrFamily : ADDRESS_FAMILIES) { netd.ipSecDeleteSecurityPolicy( - 0, + uid, selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, 0xffffffff); netd.ipSecDeleteSecurityPolicy( - 0, + uid, selAddrFamily, IpSecManager.DIRECTION_IN, mIkey, @@ -1083,7 +1083,8 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); final int resourceId = mNextResourceId++; int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; @@ -1096,7 +1097,7 @@ public class IpSecService extends IIpSecService.Stub { spi = mSrvConfig .getNetdInstance() - .ipSecAllocateSpi(resourceId, "", destinationAddress, requestedSpi); + .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, @@ -1264,7 +1265,8 @@ public class IpSecService extends IIpSecService.Stub { // TODO: Check that underlying network exists, and IP addresses not assigned to a different // network (b/72316676). - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callerUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callerUid); if (!userRecord.mTunnelQuotaTracker.isAvailable()) { return new IpSecTunnelInterfaceResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } @@ -1285,7 +1287,7 @@ public class IpSecService extends IIpSecService.Stub { for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. netd.ipSecAddSecurityPolicy( - 0, // Use 0 for reqId + callerUid, selAddrFamily, IpSecManager.DIRECTION_OUT, localAddr, @@ -1294,7 +1296,7 @@ public class IpSecService extends IIpSecService.Stub { okey, 0xffffffff); netd.ipSecAddSecurityPolicy( - 0, // Use 0 for reqId + callerUid, selAddrFamily, IpSecManager.DIRECTION_IN, remoteAddr, @@ -1532,7 +1534,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecAddSecurityAssociation( - resourceId, + Binder.getCallingUid(), c.getMode(), c.getSourceAddress(), c.getDestinationAddress(), @@ -1623,13 +1625,14 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void applyTransportModeTransform( ParcelFileDescriptor socket, int direction, int resourceId) throws RemoteException { - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); checkDirection(direction); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); // TODO: make this a function. - if (info.pid != getCallingPid() || info.uid != getCallingUid()) { + if (info.pid != getCallingPid() || info.uid != callingUid) { throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); } @@ -1643,7 +1646,7 @@ public class IpSecService extends IIpSecService.Stub { .getNetdInstance() .ipSecApplyTransportModeTransform( socket.getFileDescriptor(), - resourceId, + callingUid, direction, c.getSourceAddress(), c.getDestinationAddress(), @@ -1675,7 +1678,8 @@ public class IpSecService extends IIpSecService.Stub { enforceTunnelPermissions(callingPackage); checkDirection(direction); - UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + int callingUid = Binder.getCallingUid(); + UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); // Get transform record; if no transform is found, will throw IllegalArgumentException TransformRecord transformInfo = @@ -1717,7 +1721,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecUpdateSecurityPolicy( - 0, // Use 0 for reqId + callingUid, selAddrFamily, direction, tunnelInterfaceInfo.getLocalAddress(), From c61623c4a1fddc9ed9104df29dd3bae9c26e0893 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Sep 2018 16:45:12 -0700 Subject: [PATCH 0566/1150] Re-enable checks for MANAGE_IPSEC_TUNNELS This patch ensures that creation and modification of IPsec tunnels requires the MANAGE_IPSEC_TUNNELS appop. Bug: 115685048 Test: IpSecManagerTunnelTest fails without appops set Change-Id: I6c60a2573ca521717877f36e28a392b0d3b62754 --- .../java/com/android/server/IpSecService.java | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 01e81525d5..8c5187e41e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1488,23 +1488,19 @@ public class IpSecService extends IIpSecService.Stub { } } - private static final String TUNNEL_OP = "STOPSHIP"; // = AppOpsManager.OP_MANAGE_IPSEC_TUNNELS; + private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; private void enforceTunnelPermissions(String callingPackage) { checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - if (false) { // STOPSHIP if this line is present - switch (getAppOpsManager().noteOp( - TUNNEL_OP, - Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); - } + switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { + case AppOpsManager.MODE_DEFAULT: + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); + break; + case AppOpsManager.MODE_ALLOWED: + return; + default: + throw new SecurityException("Request to ignore AppOps for non-legacy API"); } } From f10b7f4730d12ca55a750e084ac5d163ec1ce70b Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 14 Sep 2018 15:16:48 -0700 Subject: [PATCH 0567/1150] Don't check qtaguid file unless using them The proc file of xt_qtaguid module is not necessarily exist on future devices. We should only check it if the device need to read the stats file for network usage information. Bug: 79938294 Test: NetworkUsageStatsTest TrafficStatsTest Change-Id: I5ac6feef8b9a26daa68b381a985925e24b0d80af --- .../jni/com_android_internal_net_NetworkStatsFactory.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c15b7ee4fe..109e65c4a1 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -285,10 +285,6 @@ static int statsLinesToNetworkStats(JNIEnv* env, jclass clazz, jobject stats, static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstring path, jint limitUid, jobjectArray limitIfacesObj, jint limitTag, jboolean useBpfStats) { - ScopedUtfChars path8(env, path); - if (path8.c_str() == NULL) { - return -1; - } std::vector limitIfaces; if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) { @@ -308,6 +304,11 @@ static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jstr if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0) return -1; } else { + ScopedUtfChars path8(env, path); + if (path8.c_str() == NULL) { + ALOGE("the qtaguid legacy path is invalid: %s", path8.c_str()); + return -1; + } if (legacyReadNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid, path8.c_str()) < 0) return -1; From 1d13372c11749ad43e33fb35922ace60a4a95b39 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 Aug 2018 10:21:26 +0900 Subject: [PATCH 0568/1150] Delay global alerts by 1s for high thresholds By skipping updates if an alert is already scheduled, this avoids firing the global alert too often on devices with high transfer speeds and high quota. Test: with tethering watching videos. Also runtest frameworks-net Bug: 117243748 Change-Id: Idce6059832db7a0e4a7117bbb3e424ec62ae3b21 --- .../server/net/NetworkStatsService.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 60e9eaab57..3f031699bd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -159,8 +159,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); + // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_REGISTER_GLOBAL_ALERT = 2; + // Perform polling, persist network, and register the global alert again. + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -168,6 +170,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_FORCE = 0x100; + /** + * When global alert quota is high, wait for this delay before processing each polling, + * and do not schedule further polls once there is already one queued. + * This avoids firing the global alert too often on devices with high transfer speeds and + * high quota. + */ + private static final int PERFORM_POLL_DELAY_MS = 1000; + private static final String TAG_NETSTATS_ERROR = "netstats_error"; private final Context mContext; @@ -920,7 +930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Create baseline stats - mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL)); return normalizedRequest; } @@ -1055,13 +1065,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { - // kick off background poll to collect network stats; UID stats - // are handled during normal polling interval. - final int flags = FLAG_PERSIST_NETWORK; - mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); - - // re-arm global alert for next update - mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget(); + // kick off background poll to collect network stats unless there is already + // such a call pending; UID stats are handled during normal polling interval. + if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { + mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, + PERFORM_POLL_DELAY_MS); + } } } }; @@ -1673,11 +1682,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { - final int flags = msg.arg1; - mService.performPoll(flags); + mService.performPoll(FLAG_PERSIST_ALL); return true; } - case MSG_REGISTER_GLOBAL_ALERT: { + case MSG_PERFORM_POLL_REGISTER_ALERT: { + mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); return true; } From 9105f824286dd3526c6746041d820b1a440dac8f Mon Sep 17 00:00:00 2001 From: evitayan Date: Thu, 22 Mar 2018 17:53:08 -0700 Subject: [PATCH 0569/1150] Check to ensure UDP-encap is used only for IPv4 This commit checks if UDP-encapsulation is used for unsupported address family and throws IllegalArgumentException when it happens. Bug: 74213459 Test: Tests added in testCreateTransportModeTransformWithEncap and testCreateTunnelModeTransformWithEncap. Command: runtest frameworks-net Verified on taimen. Change-Id: I10c01f2bad6aca23430849ea9ef6c1eb157ae131 --- .../java/com/android/server/IpSecService.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a69d41683c..8c25917c74 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -19,6 +19,8 @@ package com.android.server; import static android.Manifest.permission.DUMP; import static android.net.IpSecManager.INVALID_RESOURCE_ID; import static android.system.OsConstants.AF_INET; +import static android.system.OsConstants.AF_INET6; +import static android.system.OsConstants.AF_UNSPEC; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; @@ -63,6 +65,8 @@ import com.android.internal.util.Preconditions; import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; +import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; @@ -1426,6 +1430,17 @@ public class IpSecService extends IIpSecService.Stub { + "or Encryption algorithms"); } + private int getFamily(String inetAddress) { + int family = AF_UNSPEC; + InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress); + if (checkAddress instanceof Inet4Address) { + family = AF_INET; + } else if (checkAddress instanceof Inet6Address) { + family = AF_INET6; + } + return family; + } + /** * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an * IllegalArgumentException if they are not. @@ -1479,6 +1494,26 @@ public class IpSecService extends IIpSecService.Stub { // Require a valid source address for all transforms. checkInetAddress(config.getSourceAddress()); + // Check to ensure source and destination have the same address family. + String sourceAddress = config.getSourceAddress(); + String destinationAddress = config.getDestinationAddress(); + int sourceFamily = getFamily(sourceAddress); + int destinationFamily = getFamily(destinationAddress); + if (sourceFamily != destinationFamily) { + throw new IllegalArgumentException( + "Source address (" + + sourceAddress + + ") and destination address (" + + destinationAddress + + ") have different address families."); + } + + // Throw an error if UDP Encapsulation is not used in IPv4. + if (config.getEncapType() != IpSecTransform.ENCAP_NONE && sourceFamily != AF_INET) { + throw new IllegalArgumentException( + "UDP Encapsulation is not supported for this address family"); + } + switch (config.getMode()) { case IpSecTransform.MODE_TRANSPORT: break; From aeaeaefcef78d9d2bdcf8df3dc58b6a810b0cf0b Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 22 Aug 2018 10:21:26 +0900 Subject: [PATCH 0570/1150] Delay global alerts by 1s for high thresholds This is a cherry-pick of aosp/735725 with a minor conflict. By skipping updates if an alert is already scheduled, this avoids firing the global alert too often on devices with high transfer speeds and high quota. Test: with tethering watching videos. Also runtest frameworks-net Bug: 117243748 Change-Id: Ia0ed76141dfb33546529786eb0118138ef3708c2 Merged-In: Ie0ba5c1d1a2139606e63fcfe46ec77a89accd8d9 Merged-In: Iaabb31586e9e747871a526dc7ebb7deeb65d8f83 --- .../server/net/NetworkStatsService.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index fec510f28a..9bf3874088 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -159,9 +159,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); + // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; private static final int MSG_UPDATE_IFACES = 2; - private static final int MSG_REGISTER_GLOBAL_ALERT = 3; + // Perform polling, persist network, and register the global alert again. + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -169,6 +171,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int FLAG_PERSIST_ALL = FLAG_PERSIST_NETWORK | FLAG_PERSIST_UID; private static final int FLAG_PERSIST_FORCE = 0x100; + /** + * When global alert quota is high, wait for this delay before processing each polling, + * and do not schedule further polls once there is already one queued. + * This avoids firing the global alert too often on devices with high transfer speeds and + * high quota. + */ + private static final int PERFORM_POLL_DELAY_MS = 1000; + private static final String TAG_NETSTATS_ERROR = "netstats_error"; private final Context mContext; @@ -916,7 +926,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Create baseline stats - mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL, FLAG_PERSIST_ALL)); + mHandler.sendMessage(mHandler.obtainMessage(MSG_PERFORM_POLL)); return normalizedRequest; } @@ -1057,13 +1067,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { - // kick off background poll to collect network stats; UID stats - // are handled during normal polling interval. - final int flags = FLAG_PERSIST_NETWORK; - mHandler.obtainMessage(MSG_PERFORM_POLL, flags, 0).sendToTarget(); - - // re-arm global alert for next update - mHandler.obtainMessage(MSG_REGISTER_GLOBAL_ALERT).sendToTarget(); + // kick off background poll to collect network stats unless there is already + // such a call pending; UID stats are handled during normal polling interval. + if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { + mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, + PERFORM_POLL_DELAY_MS); + } } } }; @@ -1675,15 +1684,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public boolean handleMessage(Message msg) { switch (msg.what) { case MSG_PERFORM_POLL: { - final int flags = msg.arg1; - mService.performPoll(flags); + mService.performPoll(FLAG_PERSIST_ALL); return true; } case MSG_UPDATE_IFACES: { mService.updateIfaces(null); return true; } - case MSG_REGISTER_GLOBAL_ALERT: { + case MSG_PERFORM_POLL_REGISTER_ALERT: { + mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); return true; } From fe39697d034bfce99000ac2b4a419dfa2c91300a Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 15 Oct 2018 17:31:43 -0700 Subject: [PATCH 0571/1150] Move bpf project to system/bpf The bpf project now have a new project directory in system/bpf instead of inside netd. The network related bpf library is renamed to libnetdbpf. Fix the dependency issue in framework to make sure no regression. Test: -m CtsNetTestCases -t android.net.cts.TrafficStatsTest Bug: 112334572 Change-Id: Ibd477bf17d18d516aa520fb1569f4a395ef9abf0 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 2 +- .../core/jni/com_android_server_net_NetworkStatsService.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 109e65c4a1..b3ff4dbf8b 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -32,8 +32,8 @@ #include #include "android-base/unique_fd.h" -#include "bpf/BpfNetworkStats.h" #include "bpf/BpfUtils.h" +#include "netdbpf/BpfNetworkStats.h" using android::bpf::hasBpfSupport; using android::bpf::parseBpfNetworkStatsDetail; diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 3302dea535..649f1a56f0 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -30,8 +30,8 @@ #include #include "android-base/unique_fd.h" -#include "bpf/BpfNetworkStats.h" #include "bpf/BpfUtils.h" +#include "netdbpf/BpfNetworkStats.h" using android::bpf::Stats; using android::bpf::hasBpfSupport; From fe47da6786e7814b62fa8bf4643a476f78c70d43 Mon Sep 17 00:00:00 2001 From: Olivier Gaillard Date: Mon, 10 Sep 2018 15:35:58 +0100 Subject: [PATCH 0572/1150] Update a few runnable/handler to use a static class instead of a runnable. It will help collecting better data for handler stats (we can get a fully qualified class name). Test: tested manually Change-Id: I674cf03909153fd87d97f600e246e04800cbb624 --- .../java/com/android/server/net/NetworkStatsService.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3f031699bd..6d3a3b69bc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -105,6 +105,7 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; +import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; @@ -323,6 +324,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Clock.systemUTC()); } + private static final class NetworkStatsHandler extends Handler { + NetworkStatsHandler(Looper looper, Handler.Callback callback) { + super(looper, callback); + } + } + public static NetworkStatsService create(Context context, INetworkManagementService networkManager) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); @@ -339,7 +346,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { HandlerThread handlerThread = new HandlerThread(TAG); Handler.Callback callback = new HandlerCallback(service); handlerThread.start(); - Handler handler = new Handler(handlerThread.getLooper(), callback); + Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback); service.setHandler(handler, callback); return service; } From 74c19b8e92970d123ddc80312bd5c74222348525 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 19 Oct 2018 15:57:05 +0900 Subject: [PATCH 0573/1150] Refactor UidRange by using stable aidl structure Use stable aidl generated structure instead of UidRange Test: runtest frameworks-net passes Test: manual testing of UidRange related function works Change-Id: Iaf1c10777dc1e71df2be2a57533a10257b12626b --- core/java/android/net/UidRange.aidl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl new file mode 100644 index 0000000000..f70fc8e2fe --- /dev/null +++ b/core/java/android/net/UidRange.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +parcelable UidRange; \ No newline at end of file From f1307561ad5ac6861229f5d1b26601af8a365d01 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Oct 2018 21:14:30 +0800 Subject: [PATCH 0574/1150] Fix negative uid stats caused by 464xlat adjust when eBPF is on. When using xt_qtaguid to count per uid stats, NetworkStatsService needs to adjust the 464xlat traffic since iptables module would double count for ipv4 and ipv6 packet. But for eBPF, the per uid stats is collected in a different hook, so the adjustment on root uid would only be needed in tx direction. Bug: 112226716 Test: 1. Make ipv4 traffic in ipv6-only network and check data usage. 2. Make ipv4 traffic in a client which connect to ipv6-only hotspot. 3. runtest frameworks-net 4. cts-tradefed run cts -m CtsNetTestCases -t \ android.net.cts.TrafficStatsTest 5. cts-tradefed run cts -m CtsUsageStatsTestCases Change-Id: Ic9a84f5446eddc943c255d5f3b89dad171f53cac --- core/java/android/net/NetworkStats.java | 24 +++++++++++++------ .../internal/net/NetworkStatsFactory.java | 9 +++---- .../server/net/NetworkStatsService.java | 6 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e270fc2e39..5447f595ca 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -811,14 +811,19 @@ public class NetworkStats implements Parcelable { * packet needs to be subtracted from the root UID on the base interface both for tx * and rx traffic (http://b/12249687, http:/b/33681750). * + * As for eBPF, the per uid stats is collected by different hook, the rx packets on base + * interface will not be counted. Thus, the adjustment on root uid is only needed in tx + * direction. + * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + * @param useBpfStats True if eBPF is in use. */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces) { + NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { // Total 464xlat traffic to subtract from uid 0 on all base interfaces. // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); @@ -837,15 +842,20 @@ public class NetworkStats implements Parcelable { continue; } // Subtract any 464lat traffic seen for the root UID on the current base interface. + // However, for eBPF, the per uid stats is collected by different hook, the rx packets + // on base interface will not be counted. Thus, the adjustment on root uid is only + // needed in tx direction. adjust.iface = baseIface; - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + if (!useBpfStats) { + adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets = -entry.rxPackets; + } adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; adjust.txPackets = -entry.txPackets; adjustments.combineValues(adjust); - // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent - // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet + // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; @@ -864,8 +874,8 @@ public class NetworkStats implements Parcelable { * base and stacked traffic. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. */ - public void apply464xlatAdjustments(Map stackedIfaces) { - apply464xlatAdjustments(this, this, stackedIfaces); + public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { + apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); } /** diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index d1c279918b..0a7cff6856 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -113,11 +113,12 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces); + NetworkStats stackedTraffic, boolean useBpfStats) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces, + useBpfStats); } @VisibleForTesting @@ -263,7 +264,7 @@ public class NetworkStatsFactory { // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. // TODO: remove this and only apply adjustments in NetworkStatsService. - stats.apply464xlatAdjustments(sStackedIfaces); + stats.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); return stats; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3f031699bd..383e1e0288 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1620,7 +1620,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1630,7 +1631,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(vtStats); } From a5dc562cf860e903dbd08bbc40baf88485547820 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Oct 2018 21:14:30 +0800 Subject: [PATCH 0575/1150] Fix negative uid stats caused by 464xlat adjust when eBPF is on. When using xt_qtaguid to count per uid stats, NetworkStatsService needs to adjust the 464xlat traffic since iptables module would double count for ipv4 and ipv6 packet. But for eBPF, the per uid stats is collected in a different hook, so the adjustment on root uid would only be needed in tx direction. Bug: 112226716 Test: 1. Make ipv4 traffic in ipv6-only network and check data usage. 2. Make ipv4 traffic in a client which connect to ipv6-only hotspot. 3. runtest frameworks-net 4. cts-tradefed run cts -m CtsNetTestCases -t \ android.net.cts.TrafficStatsTest 5. cts-tradefed run cts -m CtsUsageStatsTestCases Change-Id: Ic9a84f5446eddc943c255d5f3b89dad171f53cac Merged-In: Ic9a84f5446eddc943c255d5f3b89dad171f53cac (cherry picked from commit f1307561ad5ac6861229f5d1b26601af8a365d01) --- core/java/android/net/NetworkStats.java | 24 +++++++++++++------ .../internal/net/NetworkStatsFactory.java | 9 +++---- .../server/net/NetworkStatsService.java | 6 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index edf9bc1c6b..4bcc245368 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -776,14 +776,19 @@ public class NetworkStats implements Parcelable { * packet needs to be subtracted from the root UID on the base interface both for tx * and rx traffic (http://b/12249687, http:/b/33681750). * + * As for eBPF, the per uid stats is collected by different hook, the rx packets on base + * interface will not be counted. Thus, the adjustment on root uid is only needed in tx + * direction. + * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + * @param useBpfStats True if eBPF is in use. */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces) { + NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { // Total 464xlat traffic to subtract from uid 0 on all base interfaces. // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); @@ -802,15 +807,20 @@ public class NetworkStats implements Parcelable { continue; } // Subtract any 464lat traffic seen for the root UID on the current base interface. + // However, for eBPF, the per uid stats is collected by different hook, the rx packets + // on base interface will not be counted. Thus, the adjustment on root uid is only + // needed in tx direction. adjust.iface = baseIface; - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + if (!useBpfStats) { + adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets = -entry.rxPackets; + } adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; adjust.txPackets = -entry.txPackets; adjustments.combineValues(adjust); - // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent - // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet + // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; @@ -829,8 +839,8 @@ public class NetworkStats implements Parcelable { * base and stacked traffic. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. */ - public void apply464xlatAdjustments(Map stackedIfaces) { - apply464xlatAdjustments(this, this, stackedIfaces); + public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { + apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); } /** diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index c4d08c7dc5..b3cf389c1b 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -113,11 +113,12 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces); + NetworkStats stackedTraffic, boolean useBpfStats) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces, + useBpfStats); } @VisibleForTesting @@ -263,7 +264,7 @@ public class NetworkStatsFactory { // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. // TODO: remove this and only apply adjustments in NetworkStatsService. - stats.apply464xlatAdjustments(sStackedIfaces); + stats.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); return stats; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9bf3874088..17ab29d747 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1622,7 +1622,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1632,7 +1633,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(vtStats); } From 99d13c33776db3e1102985d9b73071acca1d29b8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 8 Nov 2018 22:33:09 +0800 Subject: [PATCH 0576/1150] Change types of fields of network stats reported to framework. Currently, NetworkStats use int to handle uid, set and tag, while native side using unsigned int mixing with signed int with that. This commit make necessary changes in JNI part while libnetdbpf unifying the types of fields. Bug: 112226716 Test: 1. manually reconnect vpn 2. update apps from playstore 3. atest libnetdbpf_test 4. runtest frameworks-net 5. cts-tradefed run cts -m CtsUsageStatsTestCases -t \ android.app.usage.cts.NetworkUsageStatsTest Change-Id: I6c27124db8292e2825fba51b8994f013897cb566 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index b3ff4dbf8b..b708735616 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -175,7 +175,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, } } s.tag = rawTag >> 32; - if (limitTag != -1 && s.tag != limitTag) { + if (limitTag != -1 && s.tag != static_cast(limitTag)) { //ALOGI("skipping due to tag: %s", buffer); continue; } @@ -188,7 +188,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 6) { - if (limitUid != -1 && limitUid != s.uid) { + if (limitUid != -1 && static_cast(limitUid) != s.uid) { //ALOGI("skipping due to uid: %s", buffer); continue; } From a6c3c7e35d01949bdd56a3941beb9935ed5e46cb Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 8 Nov 2018 22:33:09 +0800 Subject: [PATCH 0577/1150] Change types of fields of network stats reported to framework. Currently, NetworkStats use int to handle uid, set and tag, while native side using unsigned int mixing with signed int with that. This commit make necessary changes in JNI part while libnetdbpf unifying the types of fields. Bug: 112226716 Bug: 119193941 Test: 1. manually reconnect vpn 2. update apps from playstore 3. atest libnetdbpf_test 4. runtest frameworks-net 5. cts-tradefed run cts -m CtsUsageStatsTestCases -t \ android.app.usage.cts.NetworkUsageStatsTest Change-Id: I6c27124db8292e2825fba51b8994f013897cb566 Merged-In: I6c27124db8292e2825fba51b8994f013897cb566 (cherry picked from commit bf7803eed8283d5a1caa2efe90aa449590ddb94f) --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c15b7ee4fe..de3a78a61a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -175,7 +175,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, } } s.tag = rawTag >> 32; - if (limitTag != -1 && s.tag != limitTag) { + if (limitTag != -1 && s.tag != static_cast(limitTag)) { //ALOGI("skipping due to tag: %s", buffer); continue; } @@ -188,7 +188,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 6) { - if (limitUid != -1 && limitUid != s.uid) { + if (limitUid != -1 && static_cast(limitUid) != s.uid) { //ALOGI("skipping due to uid: %s", buffer); continue; } From 8e262d068af1d1aeae524a8128db98b1ae28bba4 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 25 Jul 2018 18:46:19 -0700 Subject: [PATCH 0578/1150] Disable attempted updating of SA marks SA marks are never updated during the UPDSA call. This change disables the attempts to update the specified SAs, ensuring that the config stored in IpSecService matches that of the allocated kernel resources. Bug: 111854872 Test: Unit, CTS tests passing Change-Id: Ic1fb862c8021ffa260c3e262ec698d8af0a826d9 --- core/java/android/net/IpSecConfig.java | 14 ++++++++++++- .../java/com/android/server/IpSecService.java | 20 ++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 8599f47c62..c7eb2dd7a3 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -65,7 +65,7 @@ public final class IpSecConfig implements Parcelable { // An interval, in seconds between the NattKeepalive packets private int mNattKeepaliveInterval; - // XFRM mark and mask + // XFRM mark and mask; defaults to 0 (no mark/mask) private int mMarkValue; private int mMarkMask; @@ -125,10 +125,22 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = interval; } + /** + * Sets the mark value + * + *

            Internal (System server) use only. Marks passed in by users will be overwritten or + * ignored. + */ public void setMarkValue(int mark) { mMarkValue = mark; } + /** + * Sets the mark mask + * + *

            Internal (System server) use only. Marks passed in by users will be overwritten or + * ignored. + */ public void setMarkMask(int mask) { mMarkMask = mask; } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 8c25917c74..c4b749011a 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -24,6 +24,7 @@ import static android.system.OsConstants.AF_UNSPEC; import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -62,6 +63,8 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import libcore.io.IoUtils; + import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; @@ -73,8 +76,6 @@ import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; -import libcore.io.IoUtils; - /** * A service to manage multiple clients that want to access the IpSec API. The service is * responsible for maintaining a list of clients and managing the resources (and related quotas) @@ -1523,6 +1524,9 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException( "Invalid IpSecTransform.mode: " + config.getMode()); } + + config.setMarkValue(0); + config.setMarkMask(0); } private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; @@ -1740,8 +1744,14 @@ public class IpSecService extends IIpSecService.Stub { : tunnelInterfaceInfo.getIkey(); try { - c.setMarkValue(mark); - c.setMarkMask(0xffffffff); + // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream + // (and backporting) would allow us to narrow the mark space, and ensure that the SA + // and SPs have matching marks (as VTI are meant to be built). + // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the + // config matches the actual allocated resources in the kernel. + // + // c.setMarkValue(mark); + // c.setMarkMask(0xffffffff); if (direction == IpSecManager.DIRECTION_OUT) { // Set output mark via underlying network (output only) @@ -1758,7 +1768,7 @@ public class IpSecService extends IIpSecService.Stub { tunnelInterfaceInfo.getLocalAddress(), tunnelInterfaceInfo.getRemoteAddress(), transformInfo.getSpiRecord().getSpi(), - mark, + mark, // Must always set policy mark; ikey/okey for VTIs 0xffffffff); } } From 823266818fe54179d8c5429ad1159027050405b7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Sep 2018 11:31:25 -0700 Subject: [PATCH 0579/1150] Add XFRM-I support to IpSecService This change adds support for XFRM-I to all IpSecService netd calls. Fallback logic is in netd, and thus both VTI and XFRM-I parameters are always passed down to IpSecService. Bug: 78589502 Test: All java, CTS tests passing Change-Id: Ie4186f0ad7e50763b21831f6fa411b5ee436de78 --- core/java/android/net/IpSecConfig.java | 22 +++++- .../java/com/android/server/IpSecService.java | 76 +++++++++++++------ 2 files changed, 70 insertions(+), 28 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index c7eb2dd7a3..3552655983 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -69,6 +69,9 @@ public final class IpSecConfig implements Parcelable { private int mMarkValue; private int mMarkMask; + // XFRM interface id + private int mXfrmInterfaceId; + /** Set the mode for this IPsec transform */ public void setMode(int mode) { mMode = mode; @@ -145,6 +148,10 @@ public final class IpSecConfig implements Parcelable { mMarkMask = mask; } + public void setXfrmInterfaceId(int xfrmInterfaceId) { + mXfrmInterfaceId = xfrmInterfaceId; + } + // Transport or Tunnel public int getMode() { return mMode; @@ -202,6 +209,10 @@ public final class IpSecConfig implements Parcelable { return mMarkMask; } + public int getXfrmInterfaceId() { + return mXfrmInterfaceId; + } + // Parcelable Methods @Override @@ -225,6 +236,7 @@ public final class IpSecConfig implements Parcelable { out.writeInt(mNattKeepaliveInterval); out.writeInt(mMarkValue); out.writeInt(mMarkMask); + out.writeInt(mXfrmInterfaceId); } @VisibleForTesting @@ -247,6 +259,7 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = c.mNattKeepaliveInterval; mMarkValue = c.mMarkValue; mMarkMask = c.mMarkMask; + mXfrmInterfaceId = c.mXfrmInterfaceId; } private IpSecConfig(Parcel in) { @@ -267,6 +280,7 @@ public final class IpSecConfig implements Parcelable { mNattKeepaliveInterval = in.readInt(); mMarkValue = in.readInt(); mMarkMask = in.readInt(); + mXfrmInterfaceId = in.readInt(); } @Override @@ -301,6 +315,8 @@ public final class IpSecConfig implements Parcelable { .append(mMarkValue) .append(", mMarkMask=") .append(mMarkMask) + .append(", mXfrmInterfaceId=") + .append(mXfrmInterfaceId) .append("}"); return strBuilder.toString(); @@ -332,10 +348,10 @@ public final class IpSecConfig implements Parcelable { && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval && lhs.mSpiResourceId == rhs.mSpiResourceId && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals( - lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) + && IpSecAlgorithm.equals(lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication) && lhs.mMarkValue == rhs.mMarkValue - && lhs.mMarkMask == rhs.mMarkMask); + && lhs.mMarkMask == rhs.mMarkMask + && lhs.mXfrmInterfaceId == rhs.mXfrmInterfaceId); } } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index c4b749011a..71a7a2b5ab 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -622,7 +622,8 @@ public class IpSecService extends IIpSecService.Stub { mConfig.getDestinationAddress(), spi, mConfig.getMarkValue(), - mConfig.getMarkMask()); + mConfig.getMarkMask(), + mConfig.getXfrmInterfaceId()); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } @@ -684,7 +685,8 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - uid, mSourceAddress, mDestinationAddress, mSpi, 0, 0); + uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, + 0 /* mask */, 0 /* if_id */); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -796,6 +798,8 @@ public class IpSecService extends IIpSecService.Stub { private final int mIkey; private final int mOkey; + private final int mIfId; + TunnelInterfaceRecord( int resourceId, String interfaceName, @@ -803,7 +807,8 @@ public class IpSecService extends IIpSecService.Stub { String localAddr, String remoteAddr, int ikey, - int okey) { + int okey, + int intfId) { super(resourceId); mInterfaceName = interfaceName; @@ -812,6 +817,7 @@ public class IpSecService extends IIpSecService.Stub { mRemoteAddress = remoteAddr; mIkey = ikey; mOkey = okey; + mIfId = intfId; } /** always guarded by IpSecService#this */ @@ -822,7 +828,7 @@ public class IpSecService extends IIpSecService.Stub { // Delete global policies try { final INetd netd = mSrvConfig.getNetdInstance(); - netd.removeVirtualTunnelInterface(mInterfaceName); + netd.ipSecRemoveTunnelInterface(mInterfaceName); for (int selAddrFamily : ADDRESS_FAMILIES) { netd.ipSecDeleteSecurityPolicy( @@ -830,13 +836,15 @@ public class IpSecService extends IIpSecService.Stub { selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, - 0xffffffff); + 0xffffffff, + mIfId); netd.ipSecDeleteSecurityPolicy( uid, selAddrFamily, IpSecManager.DIRECTION_IN, mIkey, - 0xffffffff); + 0xffffffff, + mIfId); } } catch (ServiceSpecificException | RemoteException e) { Log.e( @@ -878,6 +886,10 @@ public class IpSecService extends IIpSecService.Stub { return mOkey; } + public int getIfId() { + return mIfId; + } + @Override protected ResourceTracker getResourceTracker() { return getUserRecord().mTunnelQuotaTracker; @@ -1287,7 +1299,7 @@ public class IpSecService extends IIpSecService.Stub { // Add inbound/outbound global policies // (use reqid = 0) final INetd netd = mSrvConfig.getNetdInstance(); - netd.addVirtualTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey); + netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. @@ -1299,7 +1311,8 @@ public class IpSecService extends IIpSecService.Stub { remoteAddr, 0, okey, - 0xffffffff); + 0xffffffff, + resourceId); netd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, @@ -1308,7 +1321,8 @@ public class IpSecService extends IIpSecService.Stub { localAddr, 0, ikey, - 0xffffffff); + 0xffffffff, + resourceId); } userRecord.mTunnelInterfaceRecords.put( @@ -1321,7 +1335,8 @@ public class IpSecService extends IIpSecService.Stub { localAddr, remoteAddr, ikey, - okey), + okey, + resourceId), binder)); return new IpSecTunnelInterfaceResponse(IpSecManager.Status.OK, resourceId, intfName); } catch (RemoteException e) { @@ -1588,7 +1603,8 @@ public class IpSecService extends IIpSecService.Stub { (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, encapType, encapLocalPort, - encapRemotePort); + encapRemotePort, + c.getXfrmInterfaceId()); } /** @@ -1744,6 +1760,11 @@ public class IpSecService extends IIpSecService.Stub { : tunnelInterfaceInfo.getIkey(); try { + // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip + // SPI matching as part of the template resolution. + int spi = IpSecManager.INVALID_SECURITY_PARAMETER_INDEX; + c.setXfrmInterfaceId(tunnelInterfaceInfo.getIfId()); + // TODO: enable this when UPDSA supports updating marks. Adding kernel support upstream // (and backporting) would allow us to narrow the mark space, and ensure that the SA // and SPs have matching marks (as VTI are meant to be built). @@ -1757,20 +1778,25 @@ public class IpSecService extends IIpSecService.Stub { // Set output mark via underlying network (output only) c.setNetwork(tunnelInterfaceInfo.getUnderlyingNetwork()); - // If outbound, also add SPI to the policy. - for (int selAddrFamily : ADDRESS_FAMILIES) { - mSrvConfig - .getNetdInstance() - .ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - tunnelInterfaceInfo.getLocalAddress(), - tunnelInterfaceInfo.getRemoteAddress(), - transformInfo.getSpiRecord().getSpi(), - mark, // Must always set policy mark; ikey/okey for VTIs - 0xffffffff); - } + // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, + // but want to guarantee outbound packets are sent over the new SA. + spi = transformInfo.getSpiRecord().getSpi(); + } + + // Always update the policy with the relevant XFRM_IF_ID + for (int selAddrFamily : ADDRESS_FAMILIES) { + mSrvConfig + .getNetdInstance() + .ipSecUpdateSecurityPolicy( + callingUid, + selAddrFamily, + direction, + transformInfo.getConfig().getSourceAddress(), + transformInfo.getConfig().getDestinationAddress(), + spi, // If outbound, also add SPI to the policy. + mark, // Must always set policy mark; ikey/okey for VTIs + 0xffffffff, + c.getXfrmInterfaceId()); } // Update SA with tunnel mark (ikey or okey based on direction) From e6bc8317f94e8b6b52271055a3c1129638019b07 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 21 Nov 2018 21:24:55 -0800 Subject: [PATCH 0580/1150] Cleanup and update comments SA mark disabling comments This commit cleans up and upates comments with regard to changes in aosp/721999, clarifying the restrictions and potential pitfalls we would see with regards to IPsec tunnel mode without updatable SAs. Bug: 111854872 Test: Compiles, comment-only change Change-Id: I07b0063987463c1a3cf42e112839a31739947c80 --- services/core/java/com/android/server/IpSecService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 71a7a2b5ab..7ee3d3b3bd 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1770,6 +1770,11 @@ public class IpSecService extends IIpSecService.Stub { // and SPs have matching marks (as VTI are meant to be built). // Currently update does nothing with marks. Leave empty (defaulting to 0) to ensure the // config matches the actual allocated resources in the kernel. + // All SAs will have zero marks (from creation time), and any policy that matches the + // same src/dst could match these SAs. Non-IpSecService governed processes that + // establish floating policies with the same src/dst may result in undefined + // behavior. This is generally limited to vendor code due to the permissions + // (CAP_NET_ADMIN) required. // // c.setMarkValue(mark); // c.setMarkMask(0xffffffff); From 724ed1b9218abd8a62f28f18f09fdf53cd74efc2 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Fri, 23 Nov 2018 12:01:41 +0800 Subject: [PATCH 0581/1150] Use ParcelFileDescriptor instead of FileDescriptor in INetd.aidl Stable aidl won't support FileDescriptor but ParcelFileDescriptor. In order to migrate to stable aidl, replace all FileDescriptor in INdetd.aidl. Test: runtest frameworks-net passes Change-Id: Icdf37aed0e0cce0352070a437066e77c0f2fd85a --- services/core/java/com/android/server/IpSecService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 7ee3d3b3bd..126bf65565 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1236,7 +1236,8 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner(sockFd, callingUid); + mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner( + new ParcelFileDescriptor(sockFd), callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); Os.bind(sockFd, INADDR_ANY, port); @@ -1696,7 +1697,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecApplyTransportModeTransform( - socket.getFileDescriptor(), + socket, callingUid, direction, c.getSourceAddress(), @@ -1715,7 +1716,7 @@ public class IpSecService extends IIpSecService.Stub { throws RemoteException { mSrvConfig .getNetdInstance() - .ipSecRemoveTransportModeTransform(socket.getFileDescriptor()); + .ipSecRemoveTransportModeTransform(socket); } /** From b8d6e6fb4cfad501b0d781244cdd7f0c9115a095 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 19 Oct 2018 21:14:30 +0800 Subject: [PATCH 0582/1150] Fix negative uid stats caused by 464xlat adjust when eBPF is on. When using xt_qtaguid to count per uid stats, NetworkStatsService needs to adjust the 464xlat traffic since iptables module would double count for ipv4 and ipv6 packet. But for eBPF, the per uid stats is collected in a different hook, so the adjustment on root uid would only be needed in tx direction. Bug: 112226716 Test: 1. Make ipv4 traffic in ipv6-only network and check data usage. 2. Make ipv4 traffic in a client which connect to ipv6-only hotspot. 3. runtest frameworks-net 4. cts-tradefed run cts -m CtsNetTestCases -t \ android.net.cts.TrafficStatsTest 5. cts-tradefed run cts -m CtsUsageStatsTestCases Change-Id: Ic9a84f5446eddc943c255d5f3b89dad171f53cac Merged-In: Ic9a84f5446eddc943c255d5f3b89dad171f53cac (cherry picked from commit f1307561ad5ac6861229f5d1b26601af8a365d01) (cherry picked from commit a5dc562cf860e903dbd08bbc40baf88485547820) --- core/java/android/net/NetworkStats.java | 24 +++++++++++++------ .../internal/net/NetworkStatsFactory.java | 9 +++---- .../server/net/NetworkStatsService.java | 6 +++-- 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index edf9bc1c6b..4bcc245368 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -776,14 +776,19 @@ public class NetworkStats implements Parcelable { * packet needs to be subtracted from the root UID on the base interface both for tx * and rx traffic (http://b/12249687, http:/b/33681750). * + * As for eBPF, the per uid stats is collected by different hook, the rx packets on base + * interface will not be counted. Thus, the adjustment on root uid is only needed in tx + * direction. + * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + * @param useBpfStats True if eBPF is in use. */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces) { + NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { // Total 464xlat traffic to subtract from uid 0 on all base interfaces. // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); @@ -802,15 +807,20 @@ public class NetworkStats implements Parcelable { continue; } // Subtract any 464lat traffic seen for the root UID on the current base interface. + // However, for eBPF, the per uid stats is collected by different hook, the rx packets + // on base interface will not be counted. Thus, the adjustment on root uid is only + // needed in tx direction. adjust.iface = baseIface; - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + if (!useBpfStats) { + adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); + adjust.rxPackets = -entry.rxPackets; + } adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; adjust.txPackets = -entry.txPackets; adjustments.combineValues(adjust); - // For 464xlat traffic, xt_qtaguid only counts the bytes of the native IPv4 packet sent - // on the stacked interface with prefix "v4-" and drops the IPv6 header size after + // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet + // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; @@ -829,8 +839,8 @@ public class NetworkStats implements Parcelable { * base and stacked traffic. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. */ - public void apply464xlatAdjustments(Map stackedIfaces) { - apply464xlatAdjustments(this, this, stackedIfaces); + public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { + apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); } /** diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index c4d08c7dc5..b3cf389c1b 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -113,11 +113,12 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces); + NetworkStats stackedTraffic, boolean useBpfStats) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces, + useBpfStats); } @VisibleForTesting @@ -263,7 +264,7 @@ public class NetworkStatsFactory { // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. // TODO: remove this and only apply adjustments in NetworkStatsService. - stats.apply464xlatAdjustments(sStackedIfaces); + stats.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); return stats; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9bf3874088..17ab29d747 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1622,7 +1622,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1632,7 +1633,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats); + NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, + mUseBpfTrafficStats); uidSnapshot.combineAllValues(vtStats); } From 4dfcd506751d80f80ed513f76ebd67818e9d128c Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 8 Nov 2018 22:33:09 +0800 Subject: [PATCH 0583/1150] Change types of fields of network stats reported to framework. Currently, NetworkStats use int to handle uid, set and tag, while native side using unsigned int mixing with signed int with that. This commit make necessary changes in JNI part while libnetdbpf unifying the types of fields. Bug: 112226716 Bug: 119193941 Test: 1. manually reconnect vpn 2. update apps from playstore 3. atest libnetdbpf_test 4. runtest frameworks-net 5. cts-tradefed run cts -m CtsUsageStatsTestCases -t \ android.app.usage.cts.NetworkUsageStatsTest Change-Id: I6c27124db8292e2825fba51b8994f013897cb566 Merged-In: I6c27124db8292e2825fba51b8994f013897cb566 (cherry picked from commit bf7803eed8283d5a1caa2efe90aa449590ddb94f) (cherry picked from commit a6c3c7e35d01949bdd56a3941beb9935ed5e46cb) --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index c15b7ee4fe..de3a78a61a 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -175,7 +175,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, } } s.tag = rawTag >> 32; - if (limitTag != -1 && s.tag != limitTag) { + if (limitTag != -1 && s.tag != static_cast(limitTag)) { //ALOGI("skipping due to tag: %s", buffer); continue; } @@ -188,7 +188,7 @@ static int legacyReadNetworkStatsDetail(std::vector* lines, if (sscanf(pos, "%u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, &s.uid, &s.set, &s.rxBytes, &s.rxPackets, &s.txBytes, &s.txPackets) == 6) { - if (limitUid != -1 && limitUid != s.uid) { + if (limitUid != -1 && static_cast(limitUid) != s.uid) { //ALOGI("skipping due to uid: %s", buffer); continue; } From a62125fd557d7e135fcf358cde58878e9b888432 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 29 Oct 2018 22:26:22 +0800 Subject: [PATCH 0584/1150] Refactoring of deleting stats in NetworkStats based on uids. In follow-up commits, current API would create new NetworkStats every time when 464xlatAdjustment wants to filtered out some uids. This commit refactors it to delete stats in-place to get better performance. Bug: 118602783 Test: atest FrameworksNetTests Change-Id: I858f95d1fa7733111786243b4e261ce8a70a068d --- core/java/android/net/NetworkStats.java | 38 ++++++++++++++----- .../server/net/NetworkStatsRecorder.java | 2 +- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 5447f595ca..a00b9a3cae 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -44,6 +44,7 @@ import java.util.Objects; * * @hide */ +// @NotThreadSafe public class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; /** {@link #iface} value when interface details unavailable. */ @@ -443,6 +444,26 @@ public class NetworkStats implements Parcelable { return entry; } + /** + * If @{code dest} is not equal to @{code src}, copy entry from index @{code src} to index + * @{code dest}. + */ + private void maybeCopyEntry(int dest, int src) { + if (dest == src) return; + iface[dest] = iface[src]; + uid[dest] = uid[src]; + set[dest] = set[src]; + tag[dest] = tag[src]; + metered[dest] = metered[src]; + roaming[dest] = roaming[src]; + defaultNetwork[dest] = defaultNetwork[src]; + rxBytes[dest] = rxBytes[src]; + rxPackets[dest] = rxPackets[src]; + txBytes[dest] = txBytes[src]; + txPackets[dest] = txPackets[src]; + operations[dest] = operations[src]; + } + public long getElapsedRealtime() { return elapsedRealtime; } @@ -941,21 +962,18 @@ public class NetworkStats implements Parcelable { } /** - * Return all rows except those attributed to the requested UID; doesn't - * mutate the original structure. + * Remove all rows that match one of specified UIDs. */ - public NetworkStats withoutUids(int[] uids) { - final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); - - Entry entry = new Entry(); + public void removeUids(int[] uids) { + int nextOutputEntry = 0; for (int i = 0; i < size; i++) { - entry = getValues(i, entry); - if (!ArrayUtils.contains(uids, entry.uid)) { - stats.addValues(entry); + if (!ArrayUtils.contains(uids, uid[i])) { + maybeCopyEntry(nextOutputEntry, i); + nextOutputEntry++; } } - return stats; + size = nextOutputEntry; } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a16dcf358d..a2e7e0cae9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -352,7 +352,7 @@ public class NetworkStatsRecorder { // Clear UID from current stats snapshot if (mLastSnapshot != null) { - mLastSnapshot = mLastSnapshot.withoutUids(uids); + mLastSnapshot.removeUids(uids); } final NetworkStatsCollection complete = mComplete != null ? mComplete.get() : null; From 3b51392d2cc6dd05e6582bd2ae03ff0b15e53701 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 30 Oct 2018 21:49:38 +0800 Subject: [PATCH 0585/1150] Ignore ipv6 tx traffic on clat uid. Currently, 464xlat counts its ipv6 tx traffic into root uid. When user is making ipv4 upload over ipv6-only network, ipv4 tx traffic may sometimes be counted faster then ipv6 tx traffic. Thus, NetworkStatsService may detect non-monotonic values due to 464xlat adjustment. So the solution is that: for clatd, make ipv6 tx traffic counts into clat uid, and then ignore it in the framework side. Bug: 118602783 Test: 1. manually verify clatd traffic on clat uid. 2. runtest frameworks-net Change-Id: Ifb478b79e3e281918c70e16d1f90682c78f33db1 --- core/java/android/net/NetworkStats.java | 26 ++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index a00b9a3cae..9cf582bef1 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,6 +16,8 @@ package android.net; +import static android.os.Process.CLAT_UID; + import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -828,13 +830,15 @@ public class NetworkStats implements Parcelable { * *

            For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, every 464xlat - * packet needs to be subtracted from the root UID on the base interface both for tx - * and rx traffic (http://b/12249687, http:/b/33681750). + * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, + * every rx 464xlat packet needs to be subtracted from the root UID on the base interface + * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto + * clat uid should be ignored. * * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is only needed in tx - * direction. + * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the + * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still + * needs to be ignored. * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} @@ -862,17 +866,14 @@ public class NetworkStats implements Parcelable { if (baseIface == null) { continue; } - // Subtract any 464lat traffic seen for the root UID on the current base interface. - // However, for eBPF, the per uid stats is collected by different hook, the rx packets - // on base interface will not be counted. Thus, the adjustment on root uid is only - // needed in tx direction. + // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base + // interface. As for eBPF, the per uid stats is collected by different hook, the rx + // packets on base interface will not be counted. adjust.iface = baseIface; if (!useBpfStats) { adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); adjust.rxPackets = -entry.rxPackets; } - adjust.txBytes = -(entry.txBytes + entry.txPackets * IPV4V6_HEADER_DELTA); - adjust.txPackets = -entry.txPackets; adjustments.combineValues(adjust); // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet @@ -884,6 +885,9 @@ public class NetworkStats implements Parcelable { stackedTraffic.setValues(i, entry); } + // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked + // v4 interface, so it needs to be removed to avoid double-counting. + baseTraffic.removeUids(new int[] {CLAT_UID}); baseTraffic.combineAllValues(adjustments); } From 1b6c2ed876565ae87a5f102d9555b54c943353c1 Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Tue, 11 Dec 2018 19:47:33 +0100 Subject: [PATCH 0586/1150] API: Clean up redundant and ineffective usages of SystemApi and TestApi Everything that is marked SystemApi or TestApi, but not @hide is still part of the public SDK, it is therefore not sound to have that combination. In the future, specifing such a combination will be considered an error to prevent inadvertently exposing SystemApi and TestApi as public API. Bug: 115333477 Change-Id: Ibd5d6a22862fdbc1e20a1cb3925280f5a682edea Test: METALAVA_PREPEND_ARGS="--error UnhiddenSystemApi" m checkapi Exempt-From-Owner-Approval: API cleanup --- core/java/android/net/TrafficStats.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 22dd4fc362..bbf8f97c88 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -274,7 +274,6 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - @SystemApi @SuppressLint("Doclava125") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); @@ -313,7 +312,6 @@ public class TrafficStats { * * @see #setThreadStatsUid(int) */ - @SystemApi @SuppressLint("Doclava125") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); From 770dbc40656c38fee9d7480cdec9c9b1e75dc3df Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Tue, 11 Dec 2018 19:47:33 +0100 Subject: [PATCH 0587/1150] API: Clean up redundant and ineffective usages of SystemApi and TestApi Everything that is marked SystemApi or TestApi, but not @hide is still part of the public SDK, it is therefore not sound to have that combination. In the future, specifing such a combination will be considered an error to prevent inadvertently exposing SystemApi and TestApi as public API. Bug: 115333477 Change-Id: Ibd5d6a22862fdbc1e20a1cb3925280f5a682edea Merged-In: Ibd5d6a22862fdbc1e20a1cb3925280f5a682edea Test: METALAVA_PREPEND_ARGS="--error UnhiddenSystemApi" m checkapi Exempt-From-Owner-Approval: API cleanup --- core/java/android/net/TrafficStats.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 1b22911f0c..bbb809d528 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -274,7 +274,6 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - @SystemApi @SuppressLint("Doclava125") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); @@ -313,7 +312,6 @@ public class TrafficStats { * * @see #setThreadStatsUid(int) */ - @SystemApi @SuppressLint("Doclava125") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); From c14b217455d60f2ecdd8d9c2d49a2440e23412be Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Tue, 11 Dec 2018 14:15:57 -0800 Subject: [PATCH 0588/1150] Delete unused import The hasBpfSupport() check from BpfUtils is not used by the native helper in framework. Remove them. Bug: 111441138 Test: Build without failure. Change-Id: Icdd01bf1a03efd7883e4939d0d730303ec1004e7 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 1 - services/core/jni/com_android_server_net_NetworkStatsService.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index b708735616..24bafca9c3 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -35,7 +35,6 @@ #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" -using android::bpf::hasBpfSupport; using android::bpf::parseBpfNetworkStatsDetail; using android::bpf::stats_line; diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 649f1a56f0..4d4a7b4164 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -34,7 +34,6 @@ #include "netdbpf/BpfNetworkStats.h" using android::bpf::Stats; -using android::bpf::hasBpfSupport; using android::bpf::bpfGetUidStats; using android::bpf::bpfGetIfaceStats; From 6e17032ff625891e8fcb6b228440aeaf4da9c025 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Sat, 22 Dec 2018 13:20:31 -0800 Subject: [PATCH 0589/1150] Adjust map names due to new bpfloader With the new loader support added. The bpf map format is defined by bpf kernel program as well. Change the netd bpf program to the new format. Test: CtsUsageStatsTestCases Bug: 112334572 Change-Id: I34e38e0a8cf0cca54dc52ec897771452f9d90525 --- core/java/com/android/internal/net/NetworkStatsFactory.java | 5 ++--- .../java/com/android/server/net/NetworkStatsService.java | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 0a7cff6856..9bacf9b6c2 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -20,6 +20,7 @@ import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; + import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; @@ -33,10 +34,8 @@ import com.android.internal.util.ProcFileReader; import libcore.io.IoUtils; -import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; -import java.io.FileReader; import java.io.IOException; import java.net.ProtocolException; import java.util.Arrays; @@ -127,7 +126,7 @@ public class NetworkStatsFactory { } public NetworkStatsFactory() { - this(new File("/proc/"), new File("/sys/fs/bpf/traffic_uid_stats_map").exists()); + this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists()); } @VisibleForTesting diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 82371855bd..538326bcae 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -361,7 +361,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); - mUseBpfTrafficStats = new File("/sys/fs/bpf/traffic_uid_stats_map").exists(); + mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); } private void registerLocalService() { From 77f9cd1aa62506f38f9fef8ea99942a193880881 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 9 Jan 2019 10:23:20 +0800 Subject: [PATCH 0590/1150] DO NOT MERGE: Revert: use legacy way to get tcp packet count In Q, legacy way to get tcp packet count is not planned to be supported. Users who use this unsupported API e.g., data stall detection are also planned to be removed. Thus, this change reverts 334a7559650b4 which is the short term solution in P. Bug: 110443385 Test: atest FrameworksNetTests Change-Id: Ia09f908edbf194b9aa873a3bdd5aee7b6fcb16bc --- .../java/com/android/server/net/NetworkStatsService.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 82371855bd..383e1e0288 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -955,13 +955,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getIfaceStats(String iface, int type) { - // eBPF code doesn't provide per-interface TCP counters. Use xt_qtaguid for now. - // TODO: delete getMobileTcp(Rx|Tx)Packets entirely. See b/110443385 . - if (type == TYPE_TCP_TX_PACKETS || type == TYPE_TCP_RX_PACKETS) { - return nativeGetIfaceStat(iface, type, false); - } else { - return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); - } + return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); } @Override From 1915400dd1aed77187c912cc7a1a7897bd7bba4b Mon Sep 17 00:00:00 2001 From: Mike SU Date: Mon, 26 Nov 2018 15:05:13 +0800 Subject: [PATCH 0591/1150] fix getIfaceStats and getTotalStats bug root cause: getIfaceStats and getTotalStats is directly reading iface_stat_fmt or eBPF, not include tether stats. solution: add tether stats to getIfaceStats and getTotalStats. Bug: 120039819 Test case1: 1. tether offload is enabled on phone, enable MHS on phone. 2. Use test app to check getMobileRxBytes->getIfaceStats 3. Download 10M file on MHS client 4. Use test app to check getMobileRxBytes->getIfaceStats again result: getMobileRxBytes increased around 10M Test case2: 1. tether offload is disabled on phone, enable MHS on phone. repeat above step 2~4 result: getMobileRxBytes increased around 10M Following CTS cases passed run cts -m CtsNetTestCases --test android.net.cts.TrafficStatsTest run cts -m CtsUsageStatsTestCases --test android.app.usage.cts.NetworkUsageStatsTest Change-Id: I3d94acb71c142ec38b750e58822881ff383341cc --- .../server/net/NetworkStatsService.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b0adf954ca..2e7cbc684c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -955,12 +955,64 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getIfaceStats(String iface, int type) { - return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + if (nativeIfaceStats == -1) { + return nativeIfaceStats; + } else { + // When tethering offload is in use, nativeIfaceStats does not contain usage from + // offload, add it back here. + // When tethering offload is not in use, nativeIfaceStats contains tethering usage. + // this does not cause double-counting of tethering traffic, because + // NetdTetheringStatsProvider returns zero NetworkStats + // when called with STATS_PER_IFACE. + return nativeIfaceStats + getTetherStats(iface, type); + } } @Override public long getTotalStats(int type) { - return nativeGetTotalStat(type, checkBpfStatsEnable()); + long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable()); + if (nativeTotalStats == -1) { + return nativeTotalStats; + } else { + // Refer to comment in getIfaceStats + return nativeTotalStats + getTetherStats(IFACE_ALL, type); + } + } + + private long getTetherStats(String iface, int type) { + final NetworkStats tetherSnapshot; + final long token = Binder.clearCallingIdentity(); + try { + tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + } catch (RemoteException e) { + Slog.w(TAG, "Error get TetherStats: " + e); + return 0; + } finally { + Binder.restoreCallingIdentity(token); + } + HashSet limitIfaces; + if (iface == IFACE_ALL) { + limitIfaces = null; + } else { + limitIfaces = new HashSet(); + limitIfaces.add(iface); + } + NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces); + if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type + + " entry=" + entry); + switch (type) { + case 0: // TYPE_RX_BYTES + return entry.rxBytes; + case 1: // TYPE_RX_PACKETS + return entry.rxPackets; + case 2: // TYPE_TX_BYTES + return entry.txBytes; + case 3: // TYPE_TX_PACKETS + return entry.txPackets; + default: + return 0; + } } private boolean checkBpfStatsEnable() { From 6d52547595fd60d0284174d6888ae88c35928a30 Mon Sep 17 00:00:00 2001 From: Mike SU Date: Mon, 26 Nov 2018 15:05:13 +0800 Subject: [PATCH 0592/1150] fix getIfaceStats and getTotalStats bug root cause: getIfaceStats and getTotalStats is directly reading iface_stat_fmt or eBPF, not include tether stats. solution: add tether stats to getIfaceStats and getTotalStats. Clean cherry-pick of aosp/848934 Bug: 120039819 Test case1: 1. tether offload is enabled on phone, enable MHS on phone. 2. Use test app to check getMobileRxBytes->getIfaceStats 3. Download 10M file on MHS client 4. Use test app to check getMobileRxBytes->getIfaceStats again result: getMobileRxBytes increased around 10M Test case2: 1. tether offload is disabled on phone, enable MHS on phone. repeat above step 2~4 result: getMobileRxBytes increased around 10M Following CTS cases passed run cts -m CtsNetTestCases --test android.net.cts.TrafficStatsTest run cts -m CtsUsageStatsTestCases --test android.app.usage.cts.NetworkUsageStatsTest Change-Id: I3d94acb71c142ec38b750e58822881ff383341cc --- .../server/net/NetworkStatsService.java | 56 ++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 8c274e42c9..bffd60bcb8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -962,12 +962,64 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getIfaceStats(String iface, int type) { - return nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + if (nativeIfaceStats == -1) { + return nativeIfaceStats; + } else { + // When tethering offload is in use, nativeIfaceStats does not contain usage from + // offload, add it back here. + // When tethering offload is not in use, nativeIfaceStats contains tethering usage. + // this does not cause double-counting of tethering traffic, because + // NetdTetheringStatsProvider returns zero NetworkStats + // when called with STATS_PER_IFACE. + return nativeIfaceStats + getTetherStats(iface, type); + } } @Override public long getTotalStats(int type) { - return nativeGetTotalStat(type, checkBpfStatsEnable()); + long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable()); + if (nativeTotalStats == -1) { + return nativeTotalStats; + } else { + // Refer to comment in getIfaceStats + return nativeTotalStats + getTetherStats(IFACE_ALL, type); + } + } + + private long getTetherStats(String iface, int type) { + final NetworkStats tetherSnapshot; + final long token = Binder.clearCallingIdentity(); + try { + tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); + } catch (RemoteException e) { + Slog.w(TAG, "Error get TetherStats: " + e); + return 0; + } finally { + Binder.restoreCallingIdentity(token); + } + HashSet limitIfaces; + if (iface == IFACE_ALL) { + limitIfaces = null; + } else { + limitIfaces = new HashSet(); + limitIfaces.add(iface); + } + NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces); + if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type + + " entry=" + entry); + switch (type) { + case 0: // TYPE_RX_BYTES + return entry.rxBytes; + case 1: // TYPE_RX_PACKETS + return entry.rxPackets; + case 2: // TYPE_TX_BYTES + return entry.txBytes; + case 3: // TYPE_TX_PACKETS + return entry.txPackets; + default: + return 0; + } } private boolean checkBpfStatsEnable() { From e4e5381e0fe89074ebc807e33635b96acc2ec2df Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 10 Jan 2019 14:48:54 -0800 Subject: [PATCH 0593/1150] Use delta reads for per uid traffic stats For the detailed network stats of each uid and tag, the native implementation provides delta read instead of consistent stats data since boot. Every time the readNetworkStatsDetail function gets called, the data pulled will be cleared. We will keep a persistent data since boot in NetworkStatsService instead. Fixed some checkstyle complains in related files as well. Bug: 79171384 Test: android.app.usage.cts.NetworkUsageStatsTest NetworkStatsServiceTest Change-Id: I50bcf278739135081d522e50b0e88d76fd9ab131 --- .../internal/net/NetworkStatsFactory.java | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index 9bacf9b6c2..f8483461c2 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -64,6 +64,9 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; + // A persistent Snapshot since device start for eBPF stats + private final NetworkStats mPersistSnapshot; + // TODO: only do adjustments in NetworkStatsService and remove this. /** * (Stacked interface) -> (base interface) association for all connected ifaces since boot. @@ -135,6 +138,7 @@ public class NetworkStatsFactory { mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; + mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); } public NetworkStats readBpfNetworkStatsDev() throws IOException { @@ -268,6 +272,7 @@ public class NetworkStatsFactory { return stats; } + // TODO: delete the lastStats parameter private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, int limitTag, NetworkStats lastStats) throws IOException { if (USE_NATIVE_PARSING) { @@ -278,16 +283,28 @@ public class NetworkStatsFactory { } else { stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, - limitIfaces, limitTag, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); + if (mUseBpfStats) { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, + null, TAG_ALL, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); + mPersistSnapshot.combineAllValues(stats); + NetworkStats result = mPersistSnapshot.clone(); + result.filter(limitUid, limitIfaces, limitTag); + return result; + } else { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, + limitIfaces, limitTag, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + if (SANITY_CHECK_NATIVE) { + final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid, + limitIfaces, limitTag); + assertEquals(javaStats, stats); + } + return stats; } - if (SANITY_CHECK_NATIVE) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid, - limitIfaces, limitTag); - assertEquals(javaStats, stats); - } - return stats; } else { return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag); } From 43ac4781a5ea312040e9ac8ba3d52f39e818978d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 10 Jan 2019 19:12:46 +0900 Subject: [PATCH 0594/1150] Move IpClient to NetworkStack Test: atest FrameworksNetTests NetworkStackTests Bug: b/112869080 Change-Id: I7d00848c052382cd1b6ce458868bed6a1e9e8ec5 --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 126bf65565..371276fbd2 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -44,7 +44,7 @@ import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; -import android.net.util.NetdService; +import android.net.shared.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; From a71a38b32943c992e4fe51a090d36d42ab25ac52 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 25 Jan 2019 14:28:26 +0800 Subject: [PATCH 0595/1150] Hide Keepalive offload API in IpSec Since the new keepalive API is exported in ConnectivityManager, hide Keepalive API in IpSec, also make system-current.txt sync for this part. Bug: 114151147 Test: m -j Change-Id: I076030bdbab1cd7d69f6a034577d529970b050dc --- core/java/android/net/IpSecTransform.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 23c8aa368d..e519fdf65e 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -257,7 +257,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi public static class NattKeepaliveCallback { /** The specified {@code Network} is not connected. */ public static final int ERROR_INVALID_NETWORK = 1; @@ -288,7 +287,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD @@ -331,7 +329,6 @@ public final class IpSecTransform implements AutoCloseable { * * @hide */ - @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.MANAGE_IPSEC_TUNNELS, android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD From 38784a056dbeb0c1c0d2eb8d34d77f1fad302181 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 23 Jan 2019 23:11:12 +0900 Subject: [PATCH 0596/1150] Add SocketUtils for NetworkStack These utilities can only be used for privileged apps. The underlying implementation cannot be @SystemApi. Test: m Bug: 112869080 Change-Id: Idfa90561102e5b03ab2b79486d3ad46457128bf8 --- core/java/android/net/TrafficStats.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index bbf8f97c88..49c6f74b1a 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -128,10 +128,14 @@ public class TrafficStats { public static final int TAG_SYSTEM_APP = 0xFFFFFF05; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; /** @hide */ public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; /** @hide */ public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; @@ -140,6 +144,8 @@ public class TrafficStats { /** @hide */ public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; /** @hide */ + @SystemApi + @TestApi public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; From 079fe596922fa71ae286d3538d2c6e04743e3660 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Mon, 28 Jan 2019 10:39:10 -0800 Subject: [PATCH 0597/1150] jni: more O_CLOEXECs Prevent FDs from leaking across an execve() boundary. Test: compiles and boots Change-Id: I5f91046917b55b6abead0a5c6e939f82814e6f18 --- core/jni/com_android_internal_net_NetworkStatsFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp index 24bafca9c3..8259ffcd41 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp @@ -95,7 +95,7 @@ static jlongArray get_long_array(JNIEnv* env, jobject obj, jfieldID field, int s static int legacyReadNetworkStatsDetail(std::vector* lines, const std::vector& limitIfaces, int limitTag, int limitUid, const char* path) { - FILE* fp = fopen(path, "r"); + FILE* fp = fopen(path, "re"); if (fp == NULL) { return -1; } From 731f7bc00b71acc6ebfeecc30aa72f5e2f14239d Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 29 Jan 2019 15:38:52 +0900 Subject: [PATCH 0598/1150] Remove last NetworkStack usage of hidden APIs Includes various small changes to stop using hidden APIs Test: make NetworkStack Test: flashed, booted, WiFi and tethering working Bug: 112869080 Change-Id: Id2830795a444f484b377ed6437435a1cd833697a --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 371276fbd2..126bf65565 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -44,7 +44,7 @@ import android.net.LinkAddress; import android.net.Network; import android.net.NetworkUtils; import android.net.TrafficStats; -import android.net.shared.NetdService; +import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; From 93f2d251d688f425b4499d8c15284d8fdde4b0a3 Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Mon, 25 Feb 2019 13:25:32 +0000 Subject: [PATCH 0599/1150] Add @UnsupportedAppUsage annotations For packages: android.net android.net.wifi android.nfc This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I7489aad1dceeb18ed7ca48a1ed8829a668b3fa04 --- core/java/android/net/INetworkStatsService.aidl | 5 +++++ core/java/android/net/INetworkStatsSession.aidl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388..92b685c4b5 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -29,6 +29,7 @@ import android.os.Messenger; interface INetworkStatsService { /** Start a statistics query session. */ + @UnsupportedAppUsage INetworkStatsSession openSession(); /** Start a statistics query session. If calling package is profile or device owner then it is @@ -37,9 +38,11 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ + @UnsupportedAppUsage INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ + @UnsupportedAppUsage NetworkStats getDataLayerSnapshotForUid(int uid); /** Get a detailed snapshot of stats since boot for all UIDs. @@ -52,6 +55,7 @@ interface INetworkStatsService { NetworkStats getDetailedUidStats(in String[] requiredIfaces); /** Return set of any ifaces associated with mobile networks since boot. */ + @UnsupportedAppUsage String[] getMobileIfaces(); /** Increment data layer count of operations performed for UID and tag. */ @@ -60,6 +64,7 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces(in Network[] defaultNetworks); /** Force update of statistics. */ + @UnsupportedAppUsage void forceUpdate(); /** Registers a callback on data usage. */ diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl index 5229a3b3b9..f13f2cb664 100644 --- a/core/java/android/net/INetworkStatsSession.aidl +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -27,13 +27,17 @@ interface INetworkStatsSession { NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return network layer usage summary for traffic that matches template. */ + @UnsupportedAppUsage NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return historical network layer stats for traffic that matches template. */ + @UnsupportedAppUsage NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); /** Return network layer usage summary per UID for traffic that matches template. */ + @UnsupportedAppUsage NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); /** Return historical network layer stats for specific UID traffic that matches template. */ + @UnsupportedAppUsage NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); /** Return historical network layer stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end); @@ -41,6 +45,7 @@ interface INetworkStatsSession { /** Return array of uids that have stats and are accessible to the calling user */ int[] getRelevantUids(); + @UnsupportedAppUsage void close(); } From 8afc4efd1fed498d996e35a4311ce669311d5cc4 Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Thu, 28 Feb 2019 14:37:50 +0000 Subject: [PATCH 0600/1150] Add @UnsupportedAppUsage annotations For packages: android.net android.net.wifi android.nfc This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Merged-In: I7489aad1dceeb18ed7ca48a1ed8829a668b3fa04 Change-Id: I16570aef456b45a5543bf889dddc7a0d25441928 --- core/java/android/net/INetworkStatsService.aidl | 5 +++++ core/java/android/net/INetworkStatsSession.aidl | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388..92b685c4b5 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -29,6 +29,7 @@ import android.os.Messenger; interface INetworkStatsService { /** Start a statistics query session. */ + @UnsupportedAppUsage INetworkStatsSession openSession(); /** Start a statistics query session. If calling package is profile or device owner then it is @@ -37,9 +38,11 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ + @UnsupportedAppUsage INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ + @UnsupportedAppUsage NetworkStats getDataLayerSnapshotForUid(int uid); /** Get a detailed snapshot of stats since boot for all UIDs. @@ -52,6 +55,7 @@ interface INetworkStatsService { NetworkStats getDetailedUidStats(in String[] requiredIfaces); /** Return set of any ifaces associated with mobile networks since boot. */ + @UnsupportedAppUsage String[] getMobileIfaces(); /** Increment data layer count of operations performed for UID and tag. */ @@ -60,6 +64,7 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces(in Network[] defaultNetworks); /** Force update of statistics. */ + @UnsupportedAppUsage void forceUpdate(); /** Registers a callback on data usage. */ diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl index 5229a3b3b9..f13f2cb664 100644 --- a/core/java/android/net/INetworkStatsSession.aidl +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -27,13 +27,17 @@ interface INetworkStatsSession { NetworkStats getDeviceSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return network layer usage summary for traffic that matches template. */ + @UnsupportedAppUsage NetworkStats getSummaryForNetwork(in NetworkTemplate template, long start, long end); /** Return historical network layer stats for traffic that matches template. */ + @UnsupportedAppUsage NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); /** Return network layer usage summary per UID for traffic that matches template. */ + @UnsupportedAppUsage NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); /** Return historical network layer stats for specific UID traffic that matches template. */ + @UnsupportedAppUsage NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); /** Return historical network layer stats for specific UID traffic that matches template. */ NetworkStatsHistory getHistoryIntervalForUid(in NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end); @@ -41,6 +45,7 @@ interface INetworkStatsSession { /** Return array of uids that have stats and are accessible to the calling user */ int[] getRelevantUids(); + @UnsupportedAppUsage void close(); } From f664be533b4088975ac2781473d90e74ff0f5265 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 0601/1150] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/INetworkStatsService.aidl | 8 +++- .../server/net/NetworkStatsService.java | 46 +++++++++---------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388..148b25dfa8 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,11 +19,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; +import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { @@ -58,7 +60,11 @@ interface INetworkStatsService { void incrementOperationCount(int uid, int tag, int operationCount); /** Force update of ifaces. */ - void forceUpdateIfaces(in Network[] defaultNetworks); + void forceUpdateIfaces( + in Network[] defaultNetworks, + in VpnInfo[] vpnArray, + in NetworkState[] networkStates, + in String activeIface); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index bffd60bcb8..205ddb07ec 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -82,7 +82,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -196,8 +195,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; - private IConnectivityManager mConnManager; - @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -259,6 +256,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ + @GuardedBy("mStatsLock") private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -269,6 +267,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Set containing info about active VPNs and their underlying networks. */ + @GuardedBy("mStatsLock") + private VpnInfo[] mVpnInfos = new VpnInfo[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -382,10 +384,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerCallback = callback; } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - public void systemReady() { mSystemReady = true; @@ -864,13 +862,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces(Network[] defaultNetworks) { + public void forceUpdateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks); + updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1134,11 +1136,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces(Network[] defaultNetworks) { + private void updateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(defaultNetworks); + mVpnInfos = vpnArray; + mActiveIface = activeIface; + updateIfacesLocked(defaultNetworks, networkStates); } finally { mWakeLock.release(); } @@ -1152,7 +1160,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks) { + private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1164,18 +1172,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // will be persisted during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK); - final NetworkState[] states; - final LinkProperties activeLink; - try { - states = mConnManager.getAllNetworkState(); - activeLink = mConnManager.getActiveLinkProperties(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); @@ -1287,7 +1283,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); From e889557e8bcc905e4c0eaca849e823174f2b7d1e Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 0602/1150] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Id1da446b54d95ee68ed14079107b1a10318bcf8b Merged-In: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/INetworkStatsService.aidl | 8 +++- .../server/net/NetworkStatsService.java | 46 +++++++++---------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388..148b25dfa8 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,11 +19,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; +import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { @@ -58,7 +60,11 @@ interface INetworkStatsService { void incrementOperationCount(int uid, int tag, int operationCount); /** Force update of ifaces. */ - void forceUpdateIfaces(in Network[] defaultNetworks); + void forceUpdateIfaces( + in Network[] defaultNetworks, + in VpnInfo[] vpnArray, + in NetworkState[] networkStates, + in String activeIface); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 2e7cbc684c..8fa435cd93 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -82,7 +82,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -195,8 +194,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; - private IConnectivityManager mConnManager; - @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -258,6 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ + @GuardedBy("mStatsLock") private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -268,6 +266,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Set containing info about active VPNs and their underlying networks. */ + @GuardedBy("mStatsLock") + private VpnInfo[] mVpnInfos = new VpnInfo[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -375,10 +377,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerCallback = callback; } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - public void systemReady() { mSystemReady = true; @@ -857,13 +855,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces(Network[] defaultNetworks) { + public void forceUpdateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks); + updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1127,11 +1129,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces(Network[] defaultNetworks) { + private void updateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(defaultNetworks); + mVpnInfos = vpnArray; + mActiveIface = activeIface; + updateIfacesLocked(defaultNetworks, networkStates); } finally { mWakeLock.release(); } @@ -1145,7 +1153,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks) { + private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1157,18 +1165,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // will be persisted during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK); - final NetworkState[] states; - final LinkProperties activeLink; - try { - states = mConnManager.getAllNetworkState(); - activeLink = mConnManager.getActiveLinkProperties(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); @@ -1280,7 +1276,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); From 26b24a58735dfb8fb68cc3ea2c7451c1a26d8c89 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 0603/1150] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. This change also is cherry-picking cleanup made to NSS in http://aosp/628368. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Ia687845888434c8ddd24bdf44b4c70dfe80e03f5 Merged-In: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/INetworkStatsService.aidl | 8 ++- .../server/net/NetworkStatsService.java | 53 ++++++++----------- 2 files changed, 29 insertions(+), 32 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388..148b25dfa8 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,11 +19,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; +import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { @@ -58,7 +60,11 @@ interface INetworkStatsService { void incrementOperationCount(int uid, int tag, int operationCount); /** Force update of ifaces. */ - void forceUpdateIfaces(in Network[] defaultNetworks); + void forceUpdateIfaces( + in Network[] defaultNetworks, + in VpnInfo[] vpnArray, + in NetworkState[] networkStates, + in String activeIface); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 17ab29d747..2fef560afd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -82,7 +82,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -161,9 +160,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_UPDATE_IFACES = 2; // Perform polling, persist network, and register the global alert again. - private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 3; + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -196,8 +194,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; - private IConnectivityManager mConnManager; - @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -259,6 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ + @GuardedBy("mStatsLock") private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -269,6 +266,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Set containing info about active VPNs and their underlying networks. */ + @GuardedBy("mStatsLock") + private VpnInfo[] mVpnInfos = new VpnInfo[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -371,10 +372,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerCallback = callback; } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - public void systemReady() { mSystemReady = true; @@ -853,13 +850,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces(Network[] defaultNetworks) { + public void forceUpdateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks); + updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1077,11 +1078,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces(Network[] defaultNetworks) { + private void updateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(defaultNetworks); + mVpnInfos = vpnArray; + mActiveIface = activeIface; + updateIfacesLocked(defaultNetworks, networkStates); } finally { mWakeLock.release(); } @@ -1095,7 +1102,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks) { + private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1107,18 +1114,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // will be persisted during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK); - final NetworkState[] states; - final LinkProperties activeLink; - try { - states = mConnManager.getAllNetworkState(); - activeLink = mConnManager.getActiveLinkProperties(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); @@ -1230,7 +1225,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); @@ -1689,10 +1684,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mService.performPoll(FLAG_PERSIST_ALL); return true; } - case MSG_UPDATE_IFACES: { - mService.updateIfaces(null); - return true; - } case MSG_PERFORM_POLL_REGISTER_ALERT: { mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); From 43cdbac7d0b3cb3b71bdb021283657b49d4d398c Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 28 Feb 2019 12:06:45 -0700 Subject: [PATCH 0604/1150] All Parcelable CREATOR fields are @NonNull. If they were null, then the Parcelable would fail to work. Bug: 126726802 Test: manual Change-Id: I7929ffa2f20e5de1c8e68e8263cca99496e9d014 Exempt-From-Owner-Approval: Trivial API annotations --- core/java/android/net/DataUsageRequest.java | 2 +- core/java/android/net/IpSecAlgorithm.java | 2 +- core/java/android/net/IpSecConfig.java | 2 +- core/java/android/net/IpSecSpiResponse.java | 2 +- core/java/android/net/IpSecTransformResponse.java | 2 +- core/java/android/net/IpSecTunnelInterfaceResponse.java | 2 +- core/java/android/net/IpSecUdpEncapResponse.java | 2 +- core/java/android/net/NetworkStats.java | 2 +- core/java/android/net/NetworkStatsHistory.java | 2 +- core/java/android/net/NetworkTemplate.java | 2 +- core/java/android/net/nsd/NsdServiceInfo.java | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index ac9a5a3668..0ac8f7e794 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -69,7 +69,7 @@ public final class DataUsageRequest implements Parcelable { dest.writeLong(thresholdInBytes); } - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public DataUsageRequest createFromParcel(Parcel in) { diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 8034bb62c9..38d9883f00 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -191,7 +191,7 @@ public final class IpSecAlgorithm implements Parcelable { } /** Parcelable Creator */ - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecAlgorithm createFromParcel(Parcel in) { final String name = in.readString(); diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 3552655983..a64014fe55 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -322,7 +322,7 @@ public final class IpSecConfig implements Parcelable { return strBuilder.toString(); } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecConfig createFromParcel(Parcel in) { return new IpSecConfig(in); diff --git a/core/java/android/net/IpSecSpiResponse.java b/core/java/android/net/IpSecSpiResponse.java index 71dfa03ac1..f99e570fb7 100644 --- a/core/java/android/net/IpSecSpiResponse.java +++ b/core/java/android/net/IpSecSpiResponse.java @@ -65,7 +65,7 @@ public final class IpSecSpiResponse implements Parcelable { spi = in.readInt(); } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecSpiResponse createFromParcel(Parcel in) { return new IpSecSpiResponse(in); diff --git a/core/java/android/net/IpSecTransformResponse.java b/core/java/android/net/IpSecTransformResponse.java index cfc176227f..a38488954f 100644 --- a/core/java/android/net/IpSecTransformResponse.java +++ b/core/java/android/net/IpSecTransformResponse.java @@ -60,7 +60,7 @@ public final class IpSecTransformResponse implements Parcelable { resourceId = in.readInt(); } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecTransformResponse createFromParcel(Parcel in) { return new IpSecTransformResponse(in); diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.java b/core/java/android/net/IpSecTunnelInterfaceResponse.java index c23d831a44..e3411e003d 100644 --- a/core/java/android/net/IpSecTunnelInterfaceResponse.java +++ b/core/java/android/net/IpSecTunnelInterfaceResponse.java @@ -65,7 +65,7 @@ public final class IpSecTunnelInterfaceResponse implements Parcelable { interfaceName = in.readString(); } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) { return new IpSecTunnelInterfaceResponse(in); diff --git a/core/java/android/net/IpSecUdpEncapResponse.java b/core/java/android/net/IpSecUdpEncapResponse.java index 4679267cf9..4e7ba9b515 100644 --- a/core/java/android/net/IpSecUdpEncapResponse.java +++ b/core/java/android/net/IpSecUdpEncapResponse.java @@ -83,7 +83,7 @@ public final class IpSecUdpEncapResponse implements Parcelable { fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); } - public static final Parcelable.Creator CREATOR = + public static final @android.annotation.NonNull Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecUdpEncapResponse createFromParcel(Parcel in) { return new IpSecUdpEncapResponse(in); diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9cf582bef1..e892b650bf 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1153,7 +1153,7 @@ public class NetworkStats implements Parcelable { } @UnsupportedAppUsage - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index d53e0326ae..f61260ee3e 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -719,7 +719,7 @@ public class NetworkStatsHistory implements Parcelable { } @UnsupportedAppUsage - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkStatsHistory createFromParcel(Parcel in) { return new NetworkStatsHistory(in); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index bb75c63436..d42fce3a4c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -482,7 +482,7 @@ public class NetworkTemplate implements Parcelable { } @UnsupportedAppUsage - public static final Creator CREATOR = new Creator() { + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { @Override public NetworkTemplate createFromParcel(Parcel in) { return new NetworkTemplate(in); diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 9ba17edfb9..459b140980 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -355,7 +355,7 @@ public final class NsdServiceInfo implements Parcelable { } /** Implement the Parcelable interface */ - public static final Creator CREATOR = + public static final @android.annotation.NonNull Creator CREATOR = new Creator() { public NsdServiceInfo createFromParcel(Parcel in) { NsdServiceInfo info = new NsdServiceInfo(); From 54a272dbdf773565a663d9b0a35883b048e8ae8f Mon Sep 17 00:00:00 2001 From: Brett Chabot Date: Tue, 26 Feb 2019 14:52:33 -0800 Subject: [PATCH 0605/1150] Migrate frameworks/base/tests/testables and its users to androidx.test See go/jetpack-test-android-migration Test: atest TestablesTests NetworkStackTests FrameworksServicesTests SystemUITests FrameworksUiServicesTests ExtServicesUnitTests Exempt-From-Owner-Approval: already reviewed Change-Id: I083fcdaa71b503535aa2b3c257740f3ecf055373 Merged-In: Ib04d80954bd8536914d88c66b28e6632e60a6245 --- .../src/com/android/server/net/IpConfigStoreTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java index 9f4b754621..7767a2810a 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -27,9 +27,10 @@ import android.net.LinkAddress; import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; -import android.support.test.runner.AndroidJUnit4; import android.util.ArrayMap; +import androidx.test.runner.AndroidJUnit4; + import org.junit.Test; import org.junit.runner.RunWith; From 85cd5b63535a76da6ba7a425db38671b08f54f8f Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Sun, 17 Feb 2019 23:15:15 -0800 Subject: [PATCH 0606/1150] Add unit tests related to data accounting for VPNs with one underlying network. This is to establish a baseline for the existing behavior, and to ensure that following changes are not causing a regression in existing behavior. This CL is also adding missing cleanup for NetworkStatsCollectionTest which was forcing all network types in NetworkTemplate that was causing NetworkStatsService related tests to fail. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: I285f186cfb16bc9fa704c797996b1e4f8a73dee4 --- core/java/android/net/NetworkTemplate.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index bb75c63436..60ae352d5c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -40,6 +40,7 @@ import android.os.Parcelable; import android.util.BackupUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.io.ByteArrayOutputStream; @@ -89,10 +90,22 @@ public class NetworkTemplate implements Parcelable { private static boolean sForceAllNetworkTypes = false; + /** + * Results in matching against all mobile network types. + * + *

            See {@link #matchesMobile} and {@link matchesMobileWildcard}. + */ + @VisibleForTesting public static void forceAllNetworkTypes() { sForceAllNetworkTypes = true; } + /** Resets the affect of {@link #forceAllNetworkTypes}. */ + @VisibleForTesting + public static void resetForceAllNetworkTypes() { + sForceAllNetworkTypes = false; + } + /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. From d54527084e29e3c0dfe7e5151132b2ac375b3bed Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Thu, 21 Mar 2019 13:57:17 +0000 Subject: [PATCH 0607/1150] Add @UnsupportedAppUsage annotations For packages: android.companion android.filterfw android.hardware.camera2.utils android.inputmethodservice android.net.nsd android.os android.preference android.security.keymaster android.service.dreams android.telecom android.telephony.ims.compat.feature android.telephony android.util android.view.accessibility android.media.effect This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Change-Id: I9c2f8347952f3cc65759472b0e1a2717b285e44e --- core/java/android/net/nsd/INsdManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 3361a7b84b..9484c74bcb 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,6 +25,7 @@ import android.os.Messenger; */ interface INsdManager { + @UnsupportedAppUsage Messenger getMessenger(); void setEnabled(boolean enable); } From c323b81b4beef6a61aabae14ed8bca43b93e70f5 Mon Sep 17 00:00:00 2001 From: Andrei Onea Date: Fri, 22 Mar 2019 11:32:59 +0000 Subject: [PATCH 0608/1150] Add @UnsupportedAppUsage annotations For packages: android.companion android.filterfw android.hardware.camera2.utils android.inputmethodservice android.net.nsd android.os android.preference android.security.keymaster android.service.dreams android.telecom android.telephony.ims.compat.feature android.telephony android.util android.view.accessibility android.media.effect This is an automatically generated CL. See go/UnsupportedAppUsage for more details. Exempted-From-Owner-Approval: Mechanical changes to the codebase which have been approved by Android API council and announced on android-eng@ Bug: 110868826 Test: m Merged-In: I9c2f8347952f3cc65759472b0e1a2717b285e44e Change-Id: I14793863cf815fa3383fec6c6bf5a9365c2e17eb --- core/java/android/net/nsd/INsdManager.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 3361a7b84b..9484c74bcb 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,6 +25,7 @@ import android.os.Messenger; */ interface INsdManager { + @UnsupportedAppUsage Messenger getMessenger(); void setEnabled(boolean enable); } From 2e2662fbcfe1611def7ee2055cf17cb2f39d9511 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Sun, 17 Feb 2019 23:43:25 -0800 Subject: [PATCH 0609/1150] Take all VPN underlying networks into account when migrating traffic for VPN uid. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: Manually verified on device that stats from VPN UID are moved appropriately based on its declared underlying network set. Test: vogar --mode app_process --benchmark NetworkStatsBenchmark.java Change-Id: I9d8d0cc58d18002c1c96f8ddff780ef8dc452d21 --- core/java/android/net/NetworkStats.java | 330 +++++++++++------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 214 insertions(+), 122 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9cf582bef1..9e79606a24 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,6 +18,7 @@ package android.net; import static android.os.Process.CLAT_UID; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1175,133 +1176,217 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - * This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may - * change over time. + *

            This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change + * over time. * - * This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * It is possible for the VPN software to use multiple underlying networks. This method - * only migrates traffic for the primary underlying network. + *

            This method performs adjustments for one active VPN package and one VPN iface at a time. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIface the primary underlying network iface used by the VPN application - * @return true if it successfully adjusts the accounting for VPN, false otherwise + * @param underlyingIfaces underlying network ifaces used by the VPN application */ - public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { - Entry tunIfaceTotal = new Entry(); - Entry underlyingIfaceTotal = new Entry(); + public void migrateTun(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces) { + // Combined usage by all apps using VPN. + final Entry tunIfaceTotal = new Entry(); + // Usage by VPN, grouped by its {@code underlyingIfaces}. + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + // Usage by VPN, summed across all its {@code underlyingIfaces}. + final Entry underlyingIfacesTotal = new Entry(); - tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); + for (int i = 0; i < perInterfaceTotal.length; i++) { + perInterfaceTotal[i] = new Entry(); + } - // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. + tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, + underlyingIfacesTotal); + + // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); - if (pool.isEmpty()) { - return true; - } - Entry moved = - addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); - deductTrafficFromVpnApp(tunUid, underlyingIface, moved); - - if (!moved.isEmpty()) { - Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" - + moved); - return false; - } - return true; + final Entry[] moved = + addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, + perInterfaceTotal, underlyingIfacesTotal); + deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); } /** * Initializes the data used by the migrateTun() method. * - * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through the tunUid's underlyingIface - * (both foreground and background). - * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *

            This is the first pass iteration which does the following work: + * + *

              + *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and + * background). + *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *
            + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN + * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code + * underlyingIfaces} + * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its + * {@code underlyingIfaces} */ - private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } + if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - - if (recycle.uid == tunUid && recycle.tag == TAG_NONE - && Objects.equals(underlyingIface, recycle.iface)) { - underlyingIfaceTotal.add(recycle); + if (recycle.tag != TAG_NONE) { + // TODO(b/123666283): Take all tags for tunUid into account. + continue; } - if (recycle.uid != tunUid && recycle.tag == TAG_NONE - && Objects.equals(tunIface, recycle.iface)) { + if (recycle.uid == tunUid) { + // Add up traffic through tunUid's underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + perInterfaceTotal[j].add(recycle); + underlyingIfacesTotal.add(recycle); + break; + } + } + } else if (tunIface.equals(recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry pool = new Entry(); - pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); - pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); - pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); - pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); - pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); - return pool; - } + /** + * Distributes traffic across apps that are using given {@code tunIface}, and returns the total + * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} + * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} + * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code + * underlyingIfaces} + */ + private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + // Traffic that should be moved off of each underlying interface for tunUid (see + // deductTrafficFromVpnApp below). + final Entry[] moved = new Entry[underlyingIfaces.length]; + for (int i = 0; i < underlyingIfaces.length; i++) { + moved[i] = new Entry(); + } - private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry pool) { - Entry moved = new Entry(); - Entry tmpEntry = new Entry(); - tmpEntry.iface = underlyingIface; + final Entry tmpEntry = new Entry(); for (int i = 0; i < size; i++) { - // the vpn app is excluded from the redistribution but all moved traffic will be - // deducted from the vpn app (see deductTrafficFromVpnApp below). - if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { - if (tunIfaceTotal.rxBytes > 0) { - tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - } else { - tmpEntry.rxBytes = 0; - } - if (tunIfaceTotal.rxPackets > 0) { - tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - } else { - tmpEntry.rxPackets = 0; - } - if (tunIfaceTotal.txBytes > 0) { - tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - } else { - tmpEntry.txBytes = 0; - } - if (tunIfaceTotal.txPackets > 0) { - tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - } else { - tmpEntry.txPackets = 0; - } - if (tunIfaceTotal.operations > 0) { - tmpEntry.operations = - pool.operations * operations[i] / tunIfaceTotal.operations; - } else { - tmpEntry.operations = 0; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; + if (!Objects.equals(iface[i], tunIface)) { + // Consider only entries that go onto the VPN interface. + continue; + } + if (uid[i] == tunUid) { + // Exclude VPN app from the redistribution, as it can choose to create packet + // streams by writing to itself. + continue; + } + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; + + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. + // TODO: Consider refactoring first pass into a separate helper method. + long totalRxBytes = 0; + if (tunIfaceTotal.rxBytes > 0) { + // Note - The multiplication below should not overflow since NetworkStatsService + // processes this every time device has transmitted/received amount equivalent to + // global threshold alert (~ 2MB) across all interfaces. + final long rxBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + // app must not be blamed for more than it consumed on tunIface + totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); + } + long totalRxPackets = 0; + if (tunIfaceTotal.rxPackets > 0) { + final long rxPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); + } + long totalTxBytes = 0; + if (tunIfaceTotal.txBytes > 0) { + final long txBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); + } + long totalTxPackets = 0; + if (tunIfaceTotal.txPackets > 0) { + final long txPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); + } + long totalOperations = 0; + if (tunIfaceTotal.operations > 0) { + final long operationsAcrossUnderlyingIfaces = + underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; + totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); + } + // In a second pass, distribute these values across interfaces in the proportion that + // each interface represents of the total traffic of the underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + tmpEntry.iface = underlyingIfaces[j]; + tmpEntry.rxBytes = 0; + // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; + if (underlyingIfacesTotal.rxBytes > 0) { + tmpEntry.rxBytes = + totalRxBytes + * perInterfaceTotal[j].rxBytes + / underlyingIfacesTotal.rxBytes; + } + tmpEntry.rxPackets = 0; + if (underlyingIfacesTotal.rxPackets > 0) { + tmpEntry.rxPackets = + totalRxPackets + * perInterfaceTotal[j].rxPackets + / underlyingIfacesTotal.rxPackets; + } + tmpEntry.txBytes = 0; + if (underlyingIfacesTotal.txBytes > 0) { + tmpEntry.txBytes = + totalTxBytes + * perInterfaceTotal[j].txBytes + / underlyingIfacesTotal.txBytes; + } + tmpEntry.txPackets = 0; + if (underlyingIfacesTotal.txPackets > 0) { + tmpEntry.txPackets = + totalTxPackets + * perInterfaceTotal[j].txPackets + / underlyingIfacesTotal.txPackets; + } + tmpEntry.operations = 0; + if (underlyingIfacesTotal.operations > 0) { + tmpEntry.operations = + totalOperations + * perInterfaceTotal[j].operations + / underlyingIfacesTotal.operations; + } + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved.add(tmpEntry); + moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1311,38 +1396,45 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { - // Add debug info - moved.uid = tunUid; - moved.set = SET_DBG_VPN_OUT; - moved.tag = TAG_NONE; - moved.iface = underlyingIface; - moved.metered = METERED_ALL; - moved.roaming = ROAMING_ALL; - moved.defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved); + private void deductTrafficFromVpnApp( + int tunUid, + @NonNull String[] underlyingIfaces, + @NonNull Entry[] moved) { + for (int i = 0; i < underlyingIfaces.length; i++) { + // Add debug info + moved[i].uid = tunUid; + moved[i].set = SET_DBG_VPN_OUT; + moved[i].tag = TAG_NONE; + moved[i].iface = underlyingIfaces[i]; + moved[i].metered = METERED_ALL; + moved[i].roaming = ROAMING_ALL; + moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved[i]); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, - // which should be the case as it comes directly from the /proc file. We only blend in the - // roaming data after applying these adjustments, by checking the NetworkIdentity of the - // underlying iface. - int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - tunSubtract(idxVpnBackground, this, moved); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and + // METERED_NO, which should be the case as it comes directly from the /proc file. + // We only blend in the roaming data after applying these adjustments, by checking the + // NetworkIdentity of the underlying iface. + final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed + // from foreground usage. + tunSubtract(idxVpnBackground, this, moved[i]); + } - int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved); + final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved[i]); + } } } - private static void tunSubtract(int i, NetworkStats left, Entry right) { + private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a2e7e0cae9..bdff50053f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoUtils; - import com.google.android.collect.Sets; +import libcore.io.IoUtils; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); } } From 48f57628283d7cdacd831af3b5b6de8fb44c20ac Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 18 Jan 2019 19:22:48 -0800 Subject: [PATCH 0610/1150] NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. This API is similar to one provided by NetworkStatsFactory with the difference that NSS also migrates traffic from VPN UID to other apps. Since traffic can only be migrated over NetworkStats delta, NSS therefore maintains NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSS records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or getDetailedUidStats API is invoked by one of its callers. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: manually verified that battery stats are migrating traffic off of TUN (after patching above CL where we point BatteryStats to use this API). Change-Id: Ib0f0c2d4d41ee1d7a027ea9da457baaf198d649e --- core/java/android/net/NetworkStats.java | 29 +++++--- .../internal/net/NetworkStatsFactory.java | 5 ++ .../server/net/NetworkStatsService.java | 70 ++++++++++++++++++- 3 files changed, 94 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9e79606a24..27e0414961 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -34,6 +34,7 @@ import libcore.util.EmptyArray; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; +import java.util.function.Predicate; import java.util.HashSet; import java.util.Map; import java.util.Objects; @@ -994,23 +995,33 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } + filter(e -> (limitUid == UID_ALL || limitUid == e.uid) + && (limitTag == TAG_ALL || limitTag == e.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, e.iface))); + } + /** + * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. + * + *

            This mutates the original structure in place. + */ + public void filterDebugEntries() { + filter(e -> e.set < SET_DEBUG_START); + } + + private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - final boolean matches = - (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, entry.iface)); - - if (matches) { - setValues(nextOutputEntry, entry); + if (predicate.test(entry)) { + if (nextOutputEntry != i) { + setValues(nextOutputEntry, entry); + } nextOutputEntry++; } } - size = nextOutputEntry; } diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/core/java/com/android/internal/net/NetworkStatsFactory.java index f8483461c2..1f3b4c4121 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/core/java/com/android/internal/net/NetworkStatsFactory.java @@ -256,6 +256,11 @@ public class NetworkStatsFactory { return stats; } + /** + * @deprecated Use NetworkStatsService#getDetailedUidStats which also accounts for + * VPN traffic + */ + @Deprecated public NetworkStats readNetworkStatsDetail() throws IOException { return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 8fa435cd93..4c07678173 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -292,6 +292,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); + /** + * Snapshot containing most recent network stats for all UIDs across all interfaces and tags + * since boot. + * + *

            Maintains migrated VPN stats which are result of performing TUN migration on {@link + * #mLastUidDetailSnapshot}. + */ + @GuardedBy("mStatsLock") + private NetworkStats mTunAdjustedStats; + /** + * Used by {@link #mTunAdjustedStats} to migrate VPN traffic over delta between this snapshot + * and latest snapshot. + */ + @GuardedBy("mStatsLock") + private NetworkStats mLastUidDetailSnapshot; + /** Must be set in factory by calling #setHandler. */ private Handler mHandler; private Handler.Callback mHandlerCallback; @@ -805,15 +821,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { + // Get the latest snapshot from NetworkStatsFactory. + // TODO: Querying for INTERFACES_ALL may incur performance penalty. Consider restricting + // this to limited set of ifaces. + NetworkStats uidDetailStats = getNetworkStatsUidDetail(INTERFACES_ALL); + + // Migrate traffic from VPN UID over delta and update mTunAdjustedStats. + NetworkStats result; + synchronized (mStatsLock) { + migrateTunTraffic(uidDetailStats, mVpnInfos); + result = mTunAdjustedStats.clone(); + } + + // Apply filter based on ifacesToQuery. final String[] ifacesToQuery = NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); - return getNetworkStatsUidDetail(ifacesToQuery); + result.filter(UID_ALL, ifacesToQuery, TAG_ALL); + return result; } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); return new NetworkStats(0L, 0); } } + @VisibleForTesting + NetworkStats getTunAdjustedStats() { + synchronized (mStatsLock) { + if (mTunAdjustedStats == null) { + return null; + } + return mTunAdjustedStats.clone(); + } + } + @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1288,6 +1328,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); + + migrateTunTraffic(uidSnapshot, vpnArray); + } + + /** + * Updates {@link #mTunAdjustedStats} with the delta containing traffic migrated off of VPNs. + */ + @GuardedBy("mStatsLock") + private void migrateTunTraffic(NetworkStats uidDetailStats, VpnInfo[] vpnInfoArray) { + if (mTunAdjustedStats == null) { + // Either device booted or system server restarted, hence traffic cannot be migrated + // correctly without knowing the past state of VPN's underlying networks. + mTunAdjustedStats = uidDetailStats; + mLastUidDetailSnapshot = uidDetailStats; + return; + } + // Migrate delta traffic from VPN to other apps. + NetworkStats delta = uidDetailStats.subtract(mLastUidDetailSnapshot); + for (VpnInfo info : vpnInfoArray) { + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + } + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); + // Update #mTunAdjustedStats with migrated delta. + mTunAdjustedStats.combineAllValues(delta); + mTunAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); + // Update last snapshot. + mLastUidDetailSnapshot = uidDetailStats; } /** From eb5e7d58e648d32bb18e31825329aeb2b5c78a4b Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 1 Mar 2019 15:07:24 -0800 Subject: [PATCH 0611/1150] Move NetworkStatsFactory into service directory In order to notify netd to swap eBPF maps before pulling the networkStats from eBPF maps, NetworkStatsFactory need to use the NetdServices to issue binder calls. So it need to be moved from framework/base/core to framework/base/service since object in framework/base/core cannot get any system services. This change is also necessary for setting up a lock inside NetworkStatsFactory to prevent racing between two netstats caller since the lock need to be hold before netd trigger the map swap. Also fix the compile problem caused by moving the NetworkStatsFactory and the related tests. Rename the packages and the jni functions to a more proper name. Bug: 124764595 Bug: 128900919 Test: NetworkStatsFactoryTest android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Merged-In: Ifcfe4df81caf8ede2e4e66a76552cb3200378fa8 Change-Id: Ifcfe4df81caf8ede2e4e66a76552cb3200378fa8 --- .../server}/net/NetworkStatsFactory.java | 2 +- .../server/net/NetworkStatsService.java | 1 - ...android_server_net_NetworkStatsFactory.cpp | 42 +++++++++---------- 3 files changed, 21 insertions(+), 24 deletions(-) rename {core/java/com/android/internal => services/core/java/com/android/server}/net/NetworkStatsFactory.java (99%) rename core/jni/com_android_internal_net_NetworkStatsFactory.cpp => services/core/jni/com_android_server_net_NetworkStatsFactory.cpp (88%) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java similarity index 99% rename from core/java/com/android/internal/net/NetworkStatsFactory.java rename to services/core/java/com/android/server/net/NetworkStatsFactory.java index 1f3b4c4121..bf34d8fa6b 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4c07678173..f237c4bca5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -129,7 +129,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp similarity index 88% rename from core/jni/com_android_internal_net_NetworkStatsFactory.cpp rename to services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 8259ffcd41..9cd743b346 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -21,9 +21,9 @@ #include #include -#include #include +#include #include #include #include @@ -333,29 +333,27 @@ static const JNINativeMethod gMethods[] = { (void*) readNetworkStatsDev }, }; -int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { - int err = RegisterMethodsOrDie(env, - "com/android/internal/net/NetworkStatsFactory", gMethods, +int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { + int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, NELEM(gMethods)); + gStringClass = env->FindClass("java/lang/String"); + gStringClass = static_cast(env->NewGlobalRef(gStringClass)); - gStringClass = FindClassOrDie(env, "java/lang/String"); - gStringClass = MakeGlobalRefOrDie(env, gStringClass); - - jclass clazz = FindClassOrDie(env, "android/net/NetworkStats"); - gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); - gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); - gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); - gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I"); - gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J"); + jclass clazz = env->FindClass("android/net/NetworkStats"); + gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); + gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); + gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); + gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); + gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); + gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I"); + gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I"); + gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I"); + gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); + gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); + gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); + gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); + gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); return err; } From 36ba2a62c4f4efba0d57eec250a6cfc18dae0bd7 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Fri, 1 Mar 2019 15:07:24 -0800 Subject: [PATCH 0612/1150] Move NetworkStatsFactory into service directory In order to notify netd to swap eBPF maps before pulling the networkStats from eBPF maps, NetworkStatsFactory need to use the NetdServices to issue binder calls. So it need to be moved from framework/base/core to framework/base/service since object in framework/base/core cannot get any system services. This change is also necessary for setting up a lock inside NetworkStatsFactory to prevent racing between two netstats caller since the lock need to be hold before netd trigger the map swap. Also fix the compile problem caused by moving the NetworkStatsFactory and the related tests. Rename the packages and the jni functions to a more proper name. Bug: 124764595 Bug: 128900919 Test: NetworkStatsFactoryTest android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: Ifcfe4df81caf8ede2e4e66a76552cb3200378fa8 --- .../server}/net/NetworkStatsFactory.java | 2 +- .../server/net/NetworkStatsService.java | 1 - ...android_server_net_NetworkStatsFactory.cpp | 42 +++++++++---------- 3 files changed, 21 insertions(+), 24 deletions(-) rename {core/java/com/android/internal => services/core/java/com/android/server}/net/NetworkStatsFactory.java (99%) rename core/jni/com_android_internal_net_NetworkStatsFactory.cpp => services/core/jni/com_android_server_net_NetworkStatsFactory.cpp (88%) diff --git a/core/java/com/android/internal/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java similarity index 99% rename from core/java/com/android/internal/net/NetworkStatsFactory.java rename to services/core/java/com/android/server/net/NetworkStatsFactory.java index f8483461c2..af299cf66d 100644 --- a/core/java/com/android/internal/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.internal.net; +package com.android.server.net; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 205ddb07ec..15599111f6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -130,7 +130,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp similarity index 88% rename from core/jni/com_android_internal_net_NetworkStatsFactory.cpp rename to services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 8259ffcd41..9cd743b346 100644 --- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -21,9 +21,9 @@ #include #include -#include #include +#include #include #include #include @@ -333,29 +333,27 @@ static const JNINativeMethod gMethods[] = { (void*) readNetworkStatsDev }, }; -int register_com_android_internal_net_NetworkStatsFactory(JNIEnv* env) { - int err = RegisterMethodsOrDie(env, - "com/android/internal/net/NetworkStatsFactory", gMethods, +int register_android_server_net_NetworkStatsFactory(JNIEnv* env) { + int err = jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsFactory", gMethods, NELEM(gMethods)); + gStringClass = env->FindClass("java/lang/String"); + gStringClass = static_cast(env->NewGlobalRef(gStringClass)); - gStringClass = FindClassOrDie(env, "java/lang/String"); - gStringClass = MakeGlobalRefOrDie(env, gStringClass); - - jclass clazz = FindClassOrDie(env, "android/net/NetworkStats"); - gNetworkStatsClassInfo.size = GetFieldIDOrDie(env, clazz, "size", "I"); - gNetworkStatsClassInfo.capacity = GetFieldIDOrDie(env, clazz, "capacity", "I"); - gNetworkStatsClassInfo.iface = GetFieldIDOrDie(env, clazz, "iface", "[Ljava/lang/String;"); - gNetworkStatsClassInfo.uid = GetFieldIDOrDie(env, clazz, "uid", "[I"); - gNetworkStatsClassInfo.set = GetFieldIDOrDie(env, clazz, "set", "[I"); - gNetworkStatsClassInfo.tag = GetFieldIDOrDie(env, clazz, "tag", "[I"); - gNetworkStatsClassInfo.metered = GetFieldIDOrDie(env, clazz, "metered", "[I"); - gNetworkStatsClassInfo.roaming = GetFieldIDOrDie(env, clazz, "roaming", "[I"); - gNetworkStatsClassInfo.defaultNetwork = GetFieldIDOrDie(env, clazz, "defaultNetwork", "[I"); - gNetworkStatsClassInfo.rxBytes = GetFieldIDOrDie(env, clazz, "rxBytes", "[J"); - gNetworkStatsClassInfo.rxPackets = GetFieldIDOrDie(env, clazz, "rxPackets", "[J"); - gNetworkStatsClassInfo.txBytes = GetFieldIDOrDie(env, clazz, "txBytes", "[J"); - gNetworkStatsClassInfo.txPackets = GetFieldIDOrDie(env, clazz, "txPackets", "[J"); - gNetworkStatsClassInfo.operations = GetFieldIDOrDie(env, clazz, "operations", "[J"); + jclass clazz = env->FindClass("android/net/NetworkStats"); + gNetworkStatsClassInfo.size = env->GetFieldID(clazz, "size", "I"); + gNetworkStatsClassInfo.capacity = env->GetFieldID(clazz, "capacity", "I"); + gNetworkStatsClassInfo.iface = env->GetFieldID(clazz, "iface", "[Ljava/lang/String;"); + gNetworkStatsClassInfo.uid = env->GetFieldID(clazz, "uid", "[I"); + gNetworkStatsClassInfo.set = env->GetFieldID(clazz, "set", "[I"); + gNetworkStatsClassInfo.tag = env->GetFieldID(clazz, "tag", "[I"); + gNetworkStatsClassInfo.metered = env->GetFieldID(clazz, "metered", "[I"); + gNetworkStatsClassInfo.roaming = env->GetFieldID(clazz, "roaming", "[I"); + gNetworkStatsClassInfo.defaultNetwork = env->GetFieldID(clazz, "defaultNetwork", "[I"); + gNetworkStatsClassInfo.rxBytes = env->GetFieldID(clazz, "rxBytes", "[J"); + gNetworkStatsClassInfo.rxPackets = env->GetFieldID(clazz, "rxPackets", "[J"); + gNetworkStatsClassInfo.txBytes = env->GetFieldID(clazz, "txBytes", "[J"); + gNetworkStatsClassInfo.txPackets = env->GetFieldID(clazz, "txPackets", "[J"); + gNetworkStatsClassInfo.operations = env->GetFieldID(clazz, "operations", "[J"); return err; } From bf388d54a4bfea5aa32440f2e0ef4b898f370bde Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 20 Mar 2019 09:44:09 -0700 Subject: [PATCH 0613/1150] Fix flaky UdpEncapsulationSocket test This commit reduces the flakiness of the testOpenAndCloseUdpEncapsulationSocket by retrying up to three times. Unfortunately, testing port-selected socket creation is racy against other applications. This helps to handle the same race condition as done in IpSecService#bindToRandomPort Bug: 128024100 Test: 200x runs of testOpenAndCloseUdpEncapsulationSocket Change-Id: I7e036ce821019dbac6c50899bd0894e89d2fe82a --- services/core/java/com/android/server/IpSecService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 126bf65565..2cfcecca5f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -96,9 +96,10 @@ public class IpSecService extends IIpSecService.Stub { new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms - private static final int MAX_PORT_BIND_ATTEMPTS = 10; private static final InetAddress INADDR_ANY; + @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); From d184120d8d515eb1fa452e1aeff88906192fee07 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 28 Feb 2019 20:28:48 -0800 Subject: [PATCH 0614/1150] Fix remove-before-add for IpSecService RefcountedResource This patch fixes a bug where if a binder dies before the linkToDeath call, the cleanup will be performed before the entry is added to the array. While it is safe in that quotas and tracking performs as per normal, the RefcountedRecord may not be cleaned up. Rethrowing this exception is safe, since the only paths that would hit this are all on binder threads coming from applications. Further, it seems there is only one real way of this getting hit - if the app that called the creation died during the binder call. Bug: 126802451 Test: Compiled, CTS tests passing Change-Id: I6db75853da9f29e1573512e26351623f22770c5d --- services/core/java/com/android/server/IpSecService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 126bf65565..fc7fe5ea56 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -207,6 +207,7 @@ public class IpSecService extends IIpSecService.Stub { mBinder.linkToDeath(this, 0); } catch (RemoteException e) { binderDied(); + e.rethrowFromSystemServer(); } } } From 587caa5aa8299114cf31df9ebbd2632dee33ee68 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 4 Apr 2019 09:18:29 -0700 Subject: [PATCH 0615/1150] Fix flaky UdpEncapsulationSocket test This commit reduces the flakiness of the testOpenAndCloseUdpEncapsulationSocket by retrying up to three times. Unfortunately, testing port-selected socket creation is racy against other applications. This helps to handle the same race condition as done in IpSecService#bindToRandomPort Bug: 128024100 Test: 200x runs of testOpenAndCloseUdpEncapsulationSocket Change-Id: I7e036ce821019dbac6c50899bd0894e89d2fe82a Merged-In: Idf040a67e53d9b9ec6e6c647ce24f8ada501d355 Merged-In: Iad9aea4b42cd8b31a5a2659bb9cb54dd1c64e8b7 (cherry picked from commit 13fda9e39bdaf5f0503c8db68b4560a2c0034c49) --- services/core/java/com/android/server/IpSecService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 126bf65565..2cfcecca5f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -96,9 +96,10 @@ public class IpSecService extends IIpSecService.Stub { new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms - private static final int MAX_PORT_BIND_ATTEMPTS = 10; private static final InetAddress INADDR_ANY; + @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); From 4722cf1e44c8bd091fbeacd0f2a5e77968ddad56 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 15:46:21 +0900 Subject: [PATCH 0616/1150] Restrict access to dangerous methods to <= P Test: make Fixes: 130143562 Change-Id: I1a6a472f83cf00a1ab174a9c5e67d3e9357a0c45 --- core/java/android/net/TrafficStats.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a..5a22747cb4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -25,6 +25,7 @@ import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.media.MediaPlayer; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.util.DataUnit; @@ -150,7 +151,7 @@ public class TrafficStats { private static INetworkStatsService sStatsService; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { sStatsService = INetworkStatsService.Stub.asInterface( @@ -960,7 +961,7 @@ public class TrafficStats { * Interfaces are never removed from this list, so counters should always be * monotonic. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private static String[] getMobileIfaces() { try { return getStatsService().getMobileIfaces(); From d2fa72a3e1c600f1436d8bee6aa5cc431ba4fd2a Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 9 Apr 2019 19:42:52 +0800 Subject: [PATCH 0617/1150] Enforce NETWORK_STACK permission for calling NSS#forceUpdateIfaces ConnectivityManager and its usages are removed from NetworkStatsService. After that, forceUpdateIfaces requires information that only ConnectivityService has, hence restricting the calling permission to NETWORK_STACK or MAINLINE_NETWORK_STACK permission. The required permission will be changed from READ_NETWORK_USAGE_HISTORY to NETWORK_STACK or MAINLINE_NETWORK_STACK. This change would make it impossible to call outside the system. Bug: 126830974 Test: atest FrameworksNetTests Change-Id: I776484921b2dbb6735d7940c558fb5e4baed6d1e --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f237c4bca5..484efd6bfd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.INTERFACES_ALL; @@ -899,7 +900,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + checkNetworkStackPermission(mContext); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); From f786f8914a07e3e0519018429bb88f4e604cf20a Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 9 Apr 2019 11:31:46 -0700 Subject: [PATCH 0618/1150] Fix remove-before-add for IpSecService RefcountedResource This patch fixes a bug where if a binder dies before the linkToDeath call, the cleanup will be performed before the entry is added to the array. While it is safe in that quotas and tracking performs as per normal, the RefcountedRecord may not be cleaned up. Rethrowing this exception is safe, since the only paths that would hit this are all on binder threads coming from applications. Further, it seems there is only one real way of this getting hit - if the app that called the creation died during the binder call. Bug: 126802451 Test: Compiled, CTS tests passing Change-Id: Ib955acaa5e498c0e977cb5f2e48cffbc9fea8c7c Merged-In: I6db75853da9f29e1573512e26351623f22770c5d Merged-In: I416c2e43961ec0e1cc6b2fbcef970fbce858603b Merged-In: Ib955acaa5e498c0e977cb5f2e48cffbc9fea8c7c (cherry picked from commit c206dde1bdfadb09939f415cf8c0689f24918e03) --- services/core/java/com/android/server/IpSecService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2cfcecca5f..2055b64483 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -208,6 +208,7 @@ public class IpSecService extends IIpSecService.Stub { mBinder.linkToDeath(this, 0); } catch (RemoteException e) { binderDied(); + e.rethrowFromSystemServer(); } } } From 9ca2f8c911080f80284737edb754c13a490d2133 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 9 Apr 2019 23:24:41 -0700 Subject: [PATCH 0619/1150] Enforce NETWORK_STACK permission for calling NSS#forceUpdateIfaces ConnectivityManager and its usages are removed from NetworkStatsService. After that, forceUpdateIfaces requires information that only ConnectivityService has, hence restricting the calling permission to NETWORK_STACK or MAINLINE_NETWORK_STACK permission. The required permission will be changed from READ_NETWORK_USAGE_HISTORY to NETWORK_STACK or MAINLINE_NETWORK_STACK. This change would make it impossible to call outside the system. Bug: 126830974 Test: atest FrameworksNetTests Merged-In: I1b26dc64eaab2151e6885fd01cc5e8d4e18c4e60 Change-Id: I4ea421e4126a45f65d25fe0bec74243a3b20aeab (cherry picked from commit e5245130bd3c9196a9854b14ec0866cee137ed33) --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 15599111f6..f34ace55a7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -25,6 +25,7 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.INTERFACES_ALL; @@ -866,7 +867,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + checkNetworkStackPermission(mContext); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); From a61c36281278e282ac53f5ba91b73748374e192f Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 10 Apr 2019 12:55:07 -0700 Subject: [PATCH 0620/1150] Add a lock to protect persistent stats snapshot Since the network stats could be polled from multiple services at runtime, it is not thread safe for networkStatsFactory to hold a persistent stats snapshot without any protection. Use a internal lock to prevent concurrent modification on mPersistentSnapshot to fix the problem. Bug: 124764595 Test: android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: I22afb46f17697e8b6359d4f593802e0f4b95db8b --- .../server/net/NetworkStatsFactory.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index bf34d8fa6b..bd11d46a97 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -28,6 +28,7 @@ import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; @@ -65,6 +66,7 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; // A persistent Snapshot since device start for eBPF stats + @GuardedBy("mPersistSnapshot") private final NetworkStats mPersistSnapshot; // TODO: only do adjustments in NetworkStatsService and remove this. @@ -289,15 +291,17 @@ public class NetworkStatsFactory { stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } if (mUseBpfStats) { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - null, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); + synchronized (mPersistSnapshot) { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, + null, TAG_ALL, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); + mPersistSnapshot.combineAllValues(stats); + NetworkStats result = mPersistSnapshot.clone(); + result.filter(limitUid, limitIfaces, limitTag); + return result; } - mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); - mPersistSnapshot.combineAllValues(stats); - NetworkStats result = mPersistSnapshot.clone(); - result.filter(limitUid, limitIfaces, limitTag); - return result; } else { if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, limitIfaces, limitTag, mUseBpfStats) != 0) { From b7a5ed712570811045cd286da72defd95628fe30 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 27 Feb 2019 19:07:39 -0800 Subject: [PATCH 0621/1150] Ask netd to swap stats map before reading To avoid protentail race problem between netd and system_server when reading the network stats map. Always inform netd before reading the stats and let netd to do a swap between active stats map and inactive stats map. So the system_server can safely remove the stats after reading. Bug: 126620214 Test: android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: I8fa37c26bec23ffca0b29b679e72ba1189f557f1 --- .../server/net/NetworkStatsFactory.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index bd11d46a97..2e64965a61 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -24,7 +24,10 @@ import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; +import android.net.INetd; import android.net.NetworkStats; +import android.net.util.NetdService; +import android.os.RemoteException; import android.os.StrictMode; import android.os.SystemClock; @@ -65,6 +68,8 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; + private INetd mNetdService; + // A persistent Snapshot since device start for eBPF stats @GuardedBy("mPersistSnapshot") private final NetworkStats mPersistSnapshot; @@ -279,6 +284,19 @@ public class NetworkStatsFactory { return stats; } + @GuardedBy("mPersistSnapshot") + private void requestSwapActiveStatsMapLocked() throws RemoteException { + // Ask netd to do a active map stats swap. When the binder call successfully returns, + // the system server should be able to safely read and clean the inactive map + // without race problem. + if (mUseBpfStats) { + if (mNetdService == null) { + mNetdService = NetdService.getInstance(); + } + mNetdService.trafficSwapActiveStatsMap(); + } + } + // TODO: delete the lastStats parameter private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, int limitTag, NetworkStats lastStats) throws IOException { @@ -292,6 +310,13 @@ public class NetworkStatsFactory { } if (mUseBpfStats) { synchronized (mPersistSnapshot) { + try { + requestSwapActiveStatsMapLocked(); + } catch (RemoteException e) { + throw new IOException(e); + } + // Stats are always read from the inactive map, so they must be read after the + // swap if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, null, TAG_ALL, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); From c25767ac57208f7563cb32b9f1ba3c51ac24bafc Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 11:16:56 +0900 Subject: [PATCH 0622/1150] Move TrafficStats tags for the network stack constants As per API council feedback, these constants should live in a place that is private to the network stack, only with a range defined in system API. Bug: 129433383 Test: m Change-Id: I84a90f84a9af6fef4667ee4d512ebd0413222086 (cherry picked from commit 79a6330650ca04bd7a08afbd63f8016a3b30bc72) --- core/java/android/net/TrafficStats.java | 55 +++++++++++++++++-------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a..4332d8abbc 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -89,6 +89,42 @@ public class TrafficStats { */ public static final int UID_TETHERING = -5; + /** + * Tag values in this range are reserved for the network stack. The network stack is + * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline + * module separate process, and as the system UID otherwise. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF; + + /** + * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services + * like DownloadManager when performing traffic on behalf of an application. + */ + // Please note there is no enforcement of these constants, so do not rely on them to + // determine that the caller is a system caller. + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00; + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F; + + /** + * Tag values between these ranges are reserved for the network stack to do traffic + * on behalf of applications. It is a subrange of the range above. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F; + /** * Default tag value for {@link DownloadManager} traffic. * @@ -127,26 +163,9 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_APP = 0xFFFFFF05; + // TODO : remove this constant when Wifi code is updated /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; - /** @hide */ - public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; - /** @hide */ - @SystemApi - @TestApi public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; - /** @hide */ - public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; - /** @hide */ - public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; - /** @hide */ - public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; - /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; From ed723aee02844541b723d8dcd99ec85c6bcf0f0a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 15:46:21 +0900 Subject: [PATCH 0623/1150] Restrict access to dangerous methods to <= P Test: make Fixes: 130143562 Change-Id: I1a6a472f83cf00a1ab174a9c5e67d3e9357a0c45 Merged-In: I95107f7b628eecb54e9f4411785186b668e9f3d8 Merged-In: I890030580fdad45c3f8589bf6adbe5798d578cfe (cherry picked from commit 4722cf1e44c8bd091fbeacd0f2a5e77968ddad56) --- core/java/android/net/TrafficStats.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a..5a22747cb4 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -25,6 +25,7 @@ import android.app.backup.BackupManager; import android.app.usage.NetworkStatsManager; import android.content.Context; import android.media.MediaPlayer; +import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; import android.util.DataUnit; @@ -150,7 +151,7 @@ public class TrafficStats { private static INetworkStatsService sStatsService; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { sStatsService = INetworkStatsService.Stub.asInterface( @@ -960,7 +961,7 @@ public class TrafficStats { * Interfaces are never removed from this list, so counters should always be * monotonic. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private static String[] getMobileIfaces() { try { return getStatsService().getMobileIfaces(); From 65c3968e29e7af4e26e0a0505f75ffcf934d6310 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Tue, 9 Apr 2019 11:16:56 +0900 Subject: [PATCH 0624/1150] Move TrafficStats tags for the network stack constants As per API council feedback, these constants should live in a place that is private to the network stack, only with a range defined in system API. Bug: 129433383 Test: m Change-Id: I84a90f84a9af6fef4667ee4d512ebd0413222086 Merged-In: I4882686a86e7c6d42f4b0619b921d02619ed6d4c Merged-In: I9b648ed6c687d56db61a54570c7880c51c1bae51 --- core/java/android/net/TrafficStats.java | 55 +++++++++++++++++-------- 1 file changed, 37 insertions(+), 18 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 49c6f74b1a..4332d8abbc 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -89,6 +89,42 @@ public class TrafficStats { */ public static final int UID_TETHERING = -5; + /** + * Tag values in this range are reserved for the network stack. The network stack is + * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline + * module separate process, and as the system UID otherwise. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF; + + /** + * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services + * like DownloadManager when performing traffic on behalf of an application. + */ + // Please note there is no enforcement of these constants, so do not rely on them to + // determine that the caller is a system caller. + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00; + /** @hide */ + @SystemApi + public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F; + + /** + * Tag values between these ranges are reserved for the network stack to do traffic + * on behalf of applications. It is a subrange of the range above. + */ + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80; + /** @hide */ + @SystemApi + public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F; + /** * Default tag value for {@link DownloadManager} traffic. * @@ -127,26 +163,9 @@ public class TrafficStats { */ public static final int TAG_SYSTEM_APP = 0xFFFFFF05; + // TODO : remove this constant when Wifi code is updated /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40; - /** @hide */ - public static final int TAG_SYSTEM_NTP = 0xFFFFFF41; - /** @hide */ - @SystemApi - @TestApi public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42; - /** @hide */ - public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43; - /** @hide */ - public static final int TAG_SYSTEM_GPS = 0xFFFFFF44; - /** @hide */ - public static final int TAG_SYSTEM_PAC = 0xFFFFFF45; - /** @hide */ - @SystemApi - @TestApi - public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46; private static INetworkStatsService sStatsService; From e5b426fba66157edd159c21bad8ca8189f9e47e5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 25 Feb 2019 12:33:22 -0800 Subject: [PATCH 0625/1150] Add NATT keepalive resources and methods into IpSecService This change adds a new NATTKeepalive resource type, along with the associated allocation/deallocation. Additionally, this change allows ReferenceCountedResource(s) to not be binder-linked, to allow the ConnectivityService to verify ownership and allocate a NattKeepalive without double-registering for binder-death notifications. Bug: 125517194 Test: IpSecService frameworks tests ran Change-Id: I8293f79940ad57dabb6f2b9de5e334d06b869443 --- core/java/android/net/IIpSecService.aidl | 4 + .../java/com/android/server/IpSecService.java | 166 ++++++++++++++++-- 2 files changed, 159 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index d6774d47b4..b5a2a16c7f 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -72,4 +72,8 @@ interface IIpSecService int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); void removeTransportModeTransforms(in ParcelFileDescriptor socket); + + int lockEncapSocketForNattKeepalive(int encapSocketResourceId, int requesterUid); + + void releaseNattKeepalive(int nattKeepaliveResourceId, int ownerUid); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2055b64483..c1f52552ea 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -28,8 +28,10 @@ import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.IIpSecService; import android.net.INetd; import android.net.IpSecAlgorithm; @@ -42,6 +44,7 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; import android.net.LinkAddress; import android.net.Network; +import android.net.NetworkStack; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; @@ -74,6 +77,8 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; /** @@ -174,6 +179,14 @@ public class IpSecService extends IIpSecService.Stub { void freeUnderlyingResources() throws RemoteException; } + /** + * Sentinel value placeholder for a real binder in RefcountedResources. + * + *

            Used for cases where there the allocating party is a system service, and thus is expected + * to track the resource lifecycles instead of IpSecService. + */ + private static final Binder DUMMY_BINDER = new Binder(); + /** * RefcountedResource manages references and dependencies in an exclusively acyclic graph. * @@ -188,24 +201,42 @@ public class IpSecService extends IIpSecService.Stub { */ @VisibleForTesting public class RefcountedResource implements IBinder.DeathRecipient { - private final T mResource; - private final List mChildren; - int mRefCount = 1; // starts at 1 for user's reference. - IBinder mBinder; - RefcountedResource(T resource, IBinder binder, RefcountedResource... children) { + @NonNull private final T mResource; + @NonNull private final List mChildren; + int mRefCount = 1; // starts at 1 for user's reference. + + /* + * This field can take one of three states: + * 1. null, when the object has been released by the user (or the user's binder dies) + * 2. DUMMY_BINDER, when the refcounted resource is allocated from another system service + * and the other system service manages the lifecycle of the resource instead of + * IpSecService. + * 3. an actual binder, to ensure IpSecService can cleanup after users that forget to close + * their resources. + */ + @Nullable IBinder mBinder; + + RefcountedResource(@NonNull T resource, @NonNull RefcountedResource... children) { + this(resource, DUMMY_BINDER, children); + } + + RefcountedResource( + @NonNull T resource, + @NonNull IBinder binder, + @NonNull RefcountedResource... children) { synchronized (IpSecService.this) { this.mResource = resource; - this.mChildren = new ArrayList<>(children.length); this.mBinder = binder; - + this.mChildren = Collections.unmodifiableList(Arrays.asList(children)); for (RefcountedResource child : children) { - mChildren.add(child); child.mRefCount++; } try { - mBinder.linkToDeath(this, 0); + if (mBinder != DUMMY_BINDER) { + mBinder.linkToDeath(this, 0); + } } catch (RemoteException e) { binderDied(); e.rethrowFromSystemServer(); @@ -252,11 +283,12 @@ public class IpSecService extends IIpSecService.Stub { return; } - mBinder.unlinkToDeath(this, 0); + if (mBinder != DUMMY_BINDER) { + mBinder.unlinkToDeath(this, 0); + } mBinder = null; mResource.invalidate(); - releaseReference(); } @@ -381,6 +413,8 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); final RefcountedResourceArray mTunnelInterfaceRecords = new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName()); + final RefcountedResourceArray mNattKeepaliveRecords = + new RefcountedResourceArray<>(NattKeepaliveRecord.class.getSimpleName()); /** * Trackers for quotas for each of the OwnedResource types. @@ -394,6 +428,8 @@ public class IpSecService extends IIpSecService.Stub { final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); + final ResourceTracker mNattKeepaliveQuotaTracker = + new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); // Max 1 NATT keepalive per encap socket final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES); void removeSpiRecord(int resourceId) { @@ -412,6 +448,10 @@ public class IpSecService extends IIpSecService.Stub { mEncapSocketRecords.remove(resourceId); } + void removeNattKeepaliveRecord(int resourceId) { + mNattKeepaliveRecords.remove(resourceId); + } + @Override public String toString() { return new StringBuilder() @@ -421,6 +461,8 @@ public class IpSecService extends IIpSecService.Stub { .append(mTransformQuotaTracker) .append(", mSocketQuotaTracker=") .append(mSocketQuotaTracker) + .append(", mNattKeepaliveQuotaTracker=") + .append(mNattKeepaliveQuotaTracker) .append(", mTunnelQuotaTracker=") .append(mTunnelQuotaTracker) .append(", mSpiRecords=") @@ -429,6 +471,8 @@ public class IpSecService extends IIpSecService.Stub { .append(mTransformRecords) .append(", mEncapSocketRecords=") .append(mEncapSocketRecords) + .append(", mNattKeepaliveRecords=") + .append(mNattKeepaliveRecords) .append(", mTunnelInterfaceRecords=") .append(mTunnelInterfaceRecords) .append("}") @@ -573,6 +617,11 @@ public class IpSecService extends IIpSecService.Stub { mArray.remove(key); } + @VisibleForTesting + int size() { + return mArray.size(); + } + @Override public String toString() { return mArray.toString(); @@ -983,6 +1032,50 @@ public class IpSecService extends IIpSecService.Stub { } } + /** + * Tracks a NATT-keepalive instance + * + *

            This class ensures that while a NATT-keepalive is active, the UDP encap socket that it is + * supporting will stay open until the NATT-keepalive is finished. NATT-keepalive offload + * lifecycles will be managed by ConnectivityService, which will validate that the UDP Encap + * socket is owned by the requester, and take a reference to it via this NattKeepaliveRecord + * + *

            It shall be the responsibility of the caller to ensure that instances of an EncapSocket do + * not spawn multiple instances of NATT keepalives (and thereby register duplicate records) + */ + private final class NattKeepaliveRecord extends OwnedResourceRecord { + NattKeepaliveRecord(int resourceId) { + super(resourceId); + } + + @Override + @GuardedBy("IpSecService.this") + public void freeUnderlyingResources() { + Log.d(TAG, "Natt Keepalive released: " + mResourceId); + + getResourceTracker().give(); + } + + @Override + protected ResourceTracker getResourceTracker() { + return getUserRecord().mNattKeepaliveQuotaTracker; + } + + @Override + public void invalidate() { + getUserRecord().removeNattKeepaliveRecord(mResourceId); + } + + @Override + public String toString() { + return new StringBuilder() + .append("{super=") + .append(super.toString()) + .append("}") + .toString(); + } + } + /** * Constructs a new IpSecService instance * @@ -1818,6 +1911,57 @@ public class IpSecService extends IIpSecService.Stub { } } + private void verifyNetworkStackCaller() { + if (mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + != PackageManager.PERMISSION_GRANTED + && mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException( + "Requires permission NETWORK_STACK or MAINLINE_NETWORK_STACK"); + } + } + + /** + * Validates that a provided UID owns the encapSocket, and creates a NATT keepalive record + * + *

            For system server use only. Caller must have NETWORK_STACK permission + * + * @param encapSocketResourceId resource identifier of the encap socket record + * @param ownerUid the UID of the caller. Used to verify ownership. + * @return + */ + public synchronized int lockEncapSocketForNattKeepalive( + int encapSocketResourceId, int ownerUid) { + verifyNetworkStackCaller(); + + // Verify ownership. Will throw IllegalArgumentException if the UID specified does not + // own the specified UDP encapsulation socket + UserRecord userRecord = mUserResourceTracker.getUserRecord(ownerUid); + RefcountedResource refcountedSocketRecord = + userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(encapSocketResourceId); + + // Build NattKeepaliveRecord + final int resourceId = mNextResourceId++; + userRecord.mNattKeepaliveRecords.put( + resourceId, + new RefcountedResource( + new NattKeepaliveRecord(resourceId), refcountedSocketRecord)); + + return resourceId; + } + + /** + * Release a previously allocated NattKeepalive that has been registered with the system server + */ + @Override + public synchronized void releaseNattKeepalive(int nattKeepaliveResourceId, int ownerUid) + throws RemoteException { + verifyNetworkStackCaller(); + + UserRecord userRecord = mUserResourceTracker.getUserRecord(ownerUid); + releaseResource(userRecord.mNattKeepaliveRecords, nattKeepaliveResourceId); + } + @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); From e98964d7d287296aeb5619c6f0e2d1f0b868dd3b Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Thu, 11 Apr 2019 18:44:45 -0700 Subject: [PATCH 0626/1150] Add a lock to protect persistent stats snapshot Since the network stats could be polled from multiple services at runtime, it is not thread safe for networkStatsFactory to hold a persistent stats snapshot without any protection. Use a internal lock to prevent concurrent modification on mPersistentSnapshot to fix the problem. Bug: 124764595 Test: android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: I73851336452110afb74d6dd1ca5e50047d5b3d4a Merged-In: I73851336452110afb74d6dd1ca5e50047d5b3d4a Merged-In: I22afb46f17697e8b6359d4f593802e0f4b95db8b (cherry picked from commit 180c020966422bcd127de0adb7b1042534ac5baf) --- .../server/net/NetworkStatsFactory.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index af299cf66d..174f60091d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -28,6 +28,7 @@ import android.net.NetworkStats; import android.os.StrictMode; import android.os.SystemClock; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; @@ -65,6 +66,7 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; // A persistent Snapshot since device start for eBPF stats + @GuardedBy("mPersistSnapshot") private final NetworkStats mPersistSnapshot; // TODO: only do adjustments in NetworkStatsService and remove this. @@ -284,15 +286,17 @@ public class NetworkStatsFactory { stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } if (mUseBpfStats) { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - null, TAG_ALL, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); + synchronized (mPersistSnapshot) { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, + null, TAG_ALL, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); + mPersistSnapshot.combineAllValues(stats); + NetworkStats result = mPersistSnapshot.clone(); + result.filter(limitUid, limitIfaces, limitTag); + return result; } - mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); - mPersistSnapshot.combineAllValues(stats); - NetworkStats result = mPersistSnapshot.clone(); - result.filter(limitUid, limitIfaces, limitTag); - return result; } else { if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, limitIfaces, limitTag, mUseBpfStats) != 0) { From 04a2c86ba594cb02c330acfa85163d85da44c8fe Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Wed, 27 Feb 2019 19:07:39 -0800 Subject: [PATCH 0627/1150] Ask netd to swap stats map before reading To avoid protentail race problem between netd and system_server when reading the network stats map. Always inform netd before reading the stats and let netd to do a swap between active stats map and inactive stats map. So the system_server can safely remove the stats after reading. Bug: 126620214 Test: android.app.usage.cts.NetworkUsageStatsTest android.net.cts.TrafficStatsTest Change-Id: I8fa37c26bec23ffca0b29b679e72ba1189f557f1 Merged-In: I8fa37c26bec23ffca0b29b679e72ba1189f557f1 (cherry picked from commit b7a5ed712570811045cd286da72defd95628fe30) --- .../server/net/NetworkStatsFactory.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 174f60091d..69efd02dea 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -24,7 +24,10 @@ import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; +import android.net.INetd; import android.net.NetworkStats; +import android.net.util.NetdService; +import android.os.RemoteException; import android.os.StrictMode; import android.os.SystemClock; @@ -65,6 +68,8 @@ public class NetworkStatsFactory { private boolean mUseBpfStats; + private INetd mNetdService; + // A persistent Snapshot since device start for eBPF stats @GuardedBy("mPersistSnapshot") private final NetworkStats mPersistSnapshot; @@ -274,6 +279,19 @@ public class NetworkStatsFactory { return stats; } + @GuardedBy("mPersistSnapshot") + private void requestSwapActiveStatsMapLocked() throws RemoteException { + // Ask netd to do a active map stats swap. When the binder call successfully returns, + // the system server should be able to safely read and clean the inactive map + // without race problem. + if (mUseBpfStats) { + if (mNetdService == null) { + mNetdService = NetdService.getInstance(); + } + mNetdService.trafficSwapActiveStatsMap(); + } + } + // TODO: delete the lastStats parameter private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, int limitTag, NetworkStats lastStats) throws IOException { @@ -287,6 +305,13 @@ public class NetworkStatsFactory { } if (mUseBpfStats) { synchronized (mPersistSnapshot) { + try { + requestSwapActiveStatsMapLocked(); + } catch (RemoteException e) { + throw new IOException(e); + } + // Stats are always read from the inactive map, so they must be read after the + // swap if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, null, TAG_ALL, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); From c32795470c56ba7517b12d09519239ab3c13e0ab Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 16 Jul 2018 14:56:20 -0700 Subject: [PATCH 0628/1150] Add EPROTONOSUPPORT to IpSecManager SSE map This change maps EPROTONOSUPPORT to the list of error codes that map to UnsupportedOperationException in IpSecManager. Bug: 80103456 Test: Compiles, CTS tests ran Change-Id: Iec3d5fc4a9bcad7c104414afefae775232d46558 --- core/java/android/net/IpSecManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d4c3edca43..889e9bc787 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -941,7 +941,8 @@ public final class IpSecManager { throw new IllegalArgumentException(sse); } else if (sse.errorCode == OsConstants.EAGAIN) { throw new IllegalStateException(sse); - } else if (sse.errorCode == OsConstants.EOPNOTSUPP) { + } else if (sse.errorCode == OsConstants.EOPNOTSUPP + || sse.errorCode == OsConstants.EPROTONOSUPPORT) { throw new UnsupportedOperationException(sse); } } From 540ea7d69ab4a640a9a1a4593bc024c3b1f78b94 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 16 Jul 2018 14:56:20 -0700 Subject: [PATCH 0629/1150] Add EPROTONOSUPPORT to IpSecManager SSE map This change maps EPROTONOSUPPORT to the list of error codes that map to UnsupportedOperationException in IpSecManager. Bug: 80103456 Test: Compiles, CTS tests ran Change-Id: Iec3d5fc4a9bcad7c104414afefae775232d46558 Merged-In: Iec3d5fc4a9bcad7c104414afefae775232d46558 (cherry picked from commit dcbc670688d815ce89954765fac46aa2ad6d8adb) --- core/java/android/net/IpSecManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 1145d5bd4d..7d34381f73 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -947,7 +947,8 @@ public final class IpSecManager { throw new IllegalArgumentException(sse); } else if (sse.errorCode == OsConstants.EAGAIN) { throw new IllegalStateException(sse); - } else if (sse.errorCode == OsConstants.EOPNOTSUPP) { + } else if (sse.errorCode == OsConstants.EOPNOTSUPP + || sse.errorCode == OsConstants.EPROTONOSUPPORT) { throw new UnsupportedOperationException(sse); } } From 01e9de82dc41c7c698d9cd07419644c2f9b119b5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 8 Nov 2018 19:45:34 -0800 Subject: [PATCH 0630/1150] Add IPsec checks for IPSEC_TUNNEL feature This patch adds checks to ensure that the IPSEC_TUNNEL feature flag is enabled. Bug: 117183273 Test: Compiles & tests passing Change-Id: I2699dda29e1eed139bc6fd1b70071e5ab33cad88 --- core/java/android/net/IpSecManager.java | 6 ++++++ core/java/android/net/IpSecTransform.java | 3 +++ .../java/com/android/server/IpSecService.java | 20 ++++++++++++------- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 1145d5bd4d..61fa04aed0 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -19,11 +19,13 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -749,6 +751,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { @@ -771,6 +774,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { try { @@ -886,6 +890,7 @@ public final class IpSecManager { */ @SystemApi @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) @@ -916,6 +921,7 @@ public final class IpSecManager { * @hide */ @SystemApi + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, @PolicyDirection int direction, @NonNull IpSecTransform transform) throws IOException { diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index e519fdf65e..36111f2a37 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -21,9 +21,11 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Handler; import android.os.IBinder; @@ -483,6 +485,7 @@ public final class IpSecTransform implements AutoCloseable { */ @SystemApi @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public IpSecTransform buildTunnelModeTransform( @NonNull InetAddress sourceAddress, diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 2055b64483..fe22dcda96 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -30,6 +30,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; +import android.content.pm.PackageManager; import android.net.IIpSecService; import android.net.INetd; import android.net.IpSecAlgorithm; @@ -1276,7 +1277,7 @@ public class IpSecService extends IIpSecService.Stub { public synchronized IpSecTunnelInterfaceResponse createTunnelInterface( String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, String callingPackage) { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); checkNotNull(binder, "Null Binder passed to createTunnelInterface"); checkNotNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); @@ -1362,7 +1363,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void addAddressToTunnelInterface( int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1391,7 +1392,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeAddressFromTunnelInterface( int tunnelResourceId, LinkAddress localAddr, String callingPackage) { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); // Get tunnelInterface record; if no such interface is found, will throw @@ -1420,7 +1421,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void deleteTunnelInterface( int resourceId, String callingPackage) throws RemoteException { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); releaseResource(userRecord.mTunnelInterfaceRecords, resourceId); } @@ -1549,7 +1550,12 @@ public class IpSecService extends IIpSecService.Stub { private static final String TUNNEL_OP = AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS; - private void enforceTunnelPermissions(String callingPackage) { + private void enforceTunnelFeatureAndPermissions(String callingPackage) { + if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS)) { + throw new UnsupportedOperationException( + "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS"); + } + checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { case AppOpsManager.MODE_DEFAULT: @@ -1621,7 +1627,7 @@ public class IpSecService extends IIpSecService.Stub { IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { checkNotNull(c); if (c.getMode() == IpSecTransform.MODE_TUNNEL) { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); } checkIpSecConfig(c); checkNotNull(binder, "Null Binder passed to createTransform"); @@ -1729,7 +1735,7 @@ public class IpSecService extends IIpSecService.Stub { public synchronized void applyTunnelModeTransform( int tunnelResourceId, int direction, int transformResourceId, String callingPackage) throws RemoteException { - enforceTunnelPermissions(callingPackage); + enforceTunnelFeatureAndPermissions(callingPackage); checkDirection(direction); int callingUid = Binder.getCallingUid(); From b8c6549326a2089fb62de8a105940f8584f29e44 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 26 Apr 2019 01:38:04 +0000 Subject: [PATCH 0631/1150] Revert "Add NATT keepalive resources and methods into IpSecService" This reverts commit e5b426fba66157edd159c21bad8ca8189f9e47e5. Reason for revert: Adds dependency between IpSecService and ConnectivityService may lead to future deadlock problems. Uses a simpler approach instead, hence the solution is not needed. See aosp/954040. Change-Id: Ibff278a6eee666cd85dba81c2bed94d568679b02 --- core/java/android/net/IIpSecService.aidl | 4 - .../java/com/android/server/IpSecService.java | 163 ++---------------- 2 files changed, 10 insertions(+), 157 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index b5a2a16c7f..d6774d47b4 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -72,8 +72,4 @@ interface IIpSecService int tunnelResourceId, int direction, int transformResourceId, in String callingPackage); void removeTransportModeTransforms(in ParcelFileDescriptor socket); - - int lockEncapSocketForNattKeepalive(int encapSocketResourceId, int requesterUid); - - void releaseNattKeepalive(int nattKeepaliveResourceId, int ownerUid); } diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index c1f52552ea..b4e1c32f25 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -28,7 +28,6 @@ import static android.system.OsConstants.SOCK_DGRAM; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; -import android.annotation.Nullable; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; @@ -44,7 +43,6 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; import android.net.LinkAddress; import android.net.Network; -import android.net.NetworkStack; import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; @@ -77,8 +75,6 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.List; /** @@ -179,14 +175,6 @@ public class IpSecService extends IIpSecService.Stub { void freeUnderlyingResources() throws RemoteException; } - /** - * Sentinel value placeholder for a real binder in RefcountedResources. - * - *

            Used for cases where there the allocating party is a system service, and thus is expected - * to track the resource lifecycles instead of IpSecService. - */ - private static final Binder DUMMY_BINDER = new Binder(); - /** * RefcountedResource manages references and dependencies in an exclusively acyclic graph. * @@ -201,42 +189,24 @@ public class IpSecService extends IIpSecService.Stub { */ @VisibleForTesting public class RefcountedResource implements IBinder.DeathRecipient { - - @NonNull private final T mResource; - @NonNull private final List mChildren; + private final T mResource; + private final List mChildren; int mRefCount = 1; // starts at 1 for user's reference. + IBinder mBinder; - /* - * This field can take one of three states: - * 1. null, when the object has been released by the user (or the user's binder dies) - * 2. DUMMY_BINDER, when the refcounted resource is allocated from another system service - * and the other system service manages the lifecycle of the resource instead of - * IpSecService. - * 3. an actual binder, to ensure IpSecService can cleanup after users that forget to close - * their resources. - */ - @Nullable IBinder mBinder; - - RefcountedResource(@NonNull T resource, @NonNull RefcountedResource... children) { - this(resource, DUMMY_BINDER, children); - } - - RefcountedResource( - @NonNull T resource, - @NonNull IBinder binder, - @NonNull RefcountedResource... children) { + RefcountedResource(T resource, IBinder binder, RefcountedResource... children) { synchronized (IpSecService.this) { this.mResource = resource; + this.mChildren = new ArrayList<>(children.length); this.mBinder = binder; - this.mChildren = Collections.unmodifiableList(Arrays.asList(children)); + for (RefcountedResource child : children) { + mChildren.add(child); child.mRefCount++; } try { - if (mBinder != DUMMY_BINDER) { - mBinder.linkToDeath(this, 0); - } + mBinder.linkToDeath(this, 0); } catch (RemoteException e) { binderDied(); e.rethrowFromSystemServer(); @@ -283,12 +253,11 @@ public class IpSecService extends IIpSecService.Stub { return; } - if (mBinder != DUMMY_BINDER) { - mBinder.unlinkToDeath(this, 0); - } + mBinder.unlinkToDeath(this, 0); mBinder = null; mResource.invalidate(); + releaseReference(); } @@ -413,8 +382,6 @@ public class IpSecService extends IIpSecService.Stub { new RefcountedResourceArray<>(EncapSocketRecord.class.getSimpleName()); final RefcountedResourceArray mTunnelInterfaceRecords = new RefcountedResourceArray<>(TunnelInterfaceRecord.class.getSimpleName()); - final RefcountedResourceArray mNattKeepaliveRecords = - new RefcountedResourceArray<>(NattKeepaliveRecord.class.getSimpleName()); /** * Trackers for quotas for each of the OwnedResource types. @@ -428,8 +395,6 @@ public class IpSecService extends IIpSecService.Stub { final ResourceTracker mSpiQuotaTracker = new ResourceTracker(MAX_NUM_SPIS); final ResourceTracker mTransformQuotaTracker = new ResourceTracker(MAX_NUM_TRANSFORMS); final ResourceTracker mSocketQuotaTracker = new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); - final ResourceTracker mNattKeepaliveQuotaTracker = - new ResourceTracker(MAX_NUM_ENCAP_SOCKETS); // Max 1 NATT keepalive per encap socket final ResourceTracker mTunnelQuotaTracker = new ResourceTracker(MAX_NUM_TUNNEL_INTERFACES); void removeSpiRecord(int resourceId) { @@ -448,10 +413,6 @@ public class IpSecService extends IIpSecService.Stub { mEncapSocketRecords.remove(resourceId); } - void removeNattKeepaliveRecord(int resourceId) { - mNattKeepaliveRecords.remove(resourceId); - } - @Override public String toString() { return new StringBuilder() @@ -461,8 +422,6 @@ public class IpSecService extends IIpSecService.Stub { .append(mTransformQuotaTracker) .append(", mSocketQuotaTracker=") .append(mSocketQuotaTracker) - .append(", mNattKeepaliveQuotaTracker=") - .append(mNattKeepaliveQuotaTracker) .append(", mTunnelQuotaTracker=") .append(mTunnelQuotaTracker) .append(", mSpiRecords=") @@ -471,8 +430,6 @@ public class IpSecService extends IIpSecService.Stub { .append(mTransformRecords) .append(", mEncapSocketRecords=") .append(mEncapSocketRecords) - .append(", mNattKeepaliveRecords=") - .append(mNattKeepaliveRecords) .append(", mTunnelInterfaceRecords=") .append(mTunnelInterfaceRecords) .append("}") @@ -617,11 +574,6 @@ public class IpSecService extends IIpSecService.Stub { mArray.remove(key); } - @VisibleForTesting - int size() { - return mArray.size(); - } - @Override public String toString() { return mArray.toString(); @@ -1032,50 +984,6 @@ public class IpSecService extends IIpSecService.Stub { } } - /** - * Tracks a NATT-keepalive instance - * - *

            This class ensures that while a NATT-keepalive is active, the UDP encap socket that it is - * supporting will stay open until the NATT-keepalive is finished. NATT-keepalive offload - * lifecycles will be managed by ConnectivityService, which will validate that the UDP Encap - * socket is owned by the requester, and take a reference to it via this NattKeepaliveRecord - * - *

            It shall be the responsibility of the caller to ensure that instances of an EncapSocket do - * not spawn multiple instances of NATT keepalives (and thereby register duplicate records) - */ - private final class NattKeepaliveRecord extends OwnedResourceRecord { - NattKeepaliveRecord(int resourceId) { - super(resourceId); - } - - @Override - @GuardedBy("IpSecService.this") - public void freeUnderlyingResources() { - Log.d(TAG, "Natt Keepalive released: " + mResourceId); - - getResourceTracker().give(); - } - - @Override - protected ResourceTracker getResourceTracker() { - return getUserRecord().mNattKeepaliveQuotaTracker; - } - - @Override - public void invalidate() { - getUserRecord().removeNattKeepaliveRecord(mResourceId); - } - - @Override - public String toString() { - return new StringBuilder() - .append("{super=") - .append(super.toString()) - .append("}") - .toString(); - } - } - /** * Constructs a new IpSecService instance * @@ -1911,57 +1819,6 @@ public class IpSecService extends IIpSecService.Stub { } } - private void verifyNetworkStackCaller() { - if (mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - != PackageManager.PERMISSION_GRANTED - && mContext.checkCallingOrSelfPermission(android.Manifest.permission.NETWORK_STACK) - != PackageManager.PERMISSION_GRANTED) { - throw new SecurityException( - "Requires permission NETWORK_STACK or MAINLINE_NETWORK_STACK"); - } - } - - /** - * Validates that a provided UID owns the encapSocket, and creates a NATT keepalive record - * - *

            For system server use only. Caller must have NETWORK_STACK permission - * - * @param encapSocketResourceId resource identifier of the encap socket record - * @param ownerUid the UID of the caller. Used to verify ownership. - * @return - */ - public synchronized int lockEncapSocketForNattKeepalive( - int encapSocketResourceId, int ownerUid) { - verifyNetworkStackCaller(); - - // Verify ownership. Will throw IllegalArgumentException if the UID specified does not - // own the specified UDP encapsulation socket - UserRecord userRecord = mUserResourceTracker.getUserRecord(ownerUid); - RefcountedResource refcountedSocketRecord = - userRecord.mEncapSocketRecords.getRefcountedResourceOrThrow(encapSocketResourceId); - - // Build NattKeepaliveRecord - final int resourceId = mNextResourceId++; - userRecord.mNattKeepaliveRecords.put( - resourceId, - new RefcountedResource( - new NattKeepaliveRecord(resourceId), refcountedSocketRecord)); - - return resourceId; - } - - /** - * Release a previously allocated NattKeepalive that has been registered with the system server - */ - @Override - public synchronized void releaseNattKeepalive(int nattKeepaliveResourceId, int ownerUid) - throws RemoteException { - verifyNetworkStackCaller(); - - UserRecord userRecord = mUserResourceTracker.getUserRecord(ownerUid); - releaseResource(userRecord.mNattKeepaliveRecords, nattKeepaliveResourceId); - } - @Override protected synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mContext.enforceCallingOrSelfPermission(DUMP, TAG); From 624100d0432e654d6832081ff410dc28e9304a10 Mon Sep 17 00:00:00 2001 From: Lei Yu Date: Thu, 9 May 2019 11:53:57 -0700 Subject: [PATCH 0632/1150] Use merged NetworkTemplate to query data usage This CL uses merged NetworkTemplate so that it shows correct data for carrier which is a virtual that has multiple subscriberId under the hood. By doing this, this CL also adds several hidden API so settings can query by NetworkTemplate directly. Fixes: 120566366 Test: RunSettingsLibRoboTests Change-Id: I8b747697933c75b48b14387adafb5ac9ca165926 --- .../app/usage/NetworkStatsManager.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 59ae3347f4..8e40449fa5 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -278,6 +278,12 @@ public class NetworkStatsManager { return null; } + return querySummary(template, startTime, endTime); + } + + /** @hide */ + public NetworkStats querySummary(NetworkTemplate template, long startTime, + long endTime) throws SecurityException, RemoteException { NetworkStats result; result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); result.startSummaryEnumeration(); @@ -296,6 +302,13 @@ public class NetworkStatsManager { NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); } + /** @hide */ + public NetworkStats queryDetailsForUid(NetworkTemplate template, + long startTime, long endTime, int uid) throws SecurityException { + return queryDetailsForUidTagState(template, startTime, endTime, uid, + NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); + } + /** * Query network usage statistics details for a given uid and tag. * @@ -340,6 +353,13 @@ public class NetworkStatsManager { NetworkTemplate template; template = createTemplate(networkType, subscriberId); + return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); + } + + /** @hide */ + public NetworkStats queryDetailsForUidTagState(NetworkTemplate template, + long startTime, long endTime, int uid, int tag, int state) throws SecurityException { + NetworkStats result; try { result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); From bbf19a273d552799b23bf1a7371a426adc5a6bfb Mon Sep 17 00:00:00 2001 From: chen xu Date: Wed, 22 May 2019 14:10:29 -0700 Subject: [PATCH 0633/1150] NetworkStatAccess Should checkCarrierPrivileges cross all subscriptions Bug: 133236378 Test: Manual Change-Id: I49fbde1fe73b33aadcf8fd23ad224f363b137bf3 --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index cebc472178..7c1c1c7ce4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -109,7 +109,7 @@ public final class NetworkStatsAccess { final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); boolean hasCarrierPrivileges = tm != null && - tm.checkCarrierPrivilegesForPackage(callingPackage) == + tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); From 08c6a361a5e9a289fe89d98f5fc4105e6c9c405e Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Sun, 17 Feb 2019 23:43:25 -0800 Subject: [PATCH 0634/1150] Take all VPN underlying networks into account when migrating traffic for VPN uid. (cherry picked from commit 2e2662fbcfe1611def7ee2055cf17cb2f39d9511) Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: Manually verified on device that stats from VPN UID are moved appropriately based on its declared underlying network set. Test: vogar --mode app_process --benchmark NetworkStatsBenchmark.java Change-Id: I7f368c5970b2dcb969fe0daf5ef44edb1f51d09d --- core/java/android/net/NetworkStats.java | 330 +++++++++++------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 214 insertions(+), 122 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e892b650bf..f09f2ee223 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,6 +18,7 @@ package android.net; import static android.os.Process.CLAT_UID; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1175,133 +1176,217 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - * This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may - * change over time. + *

            This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change + * over time. * - * This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * It is possible for the VPN software to use multiple underlying networks. This method - * only migrates traffic for the primary underlying network. + *

            This method performs adjustments for one active VPN package and one VPN iface at a time. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIface the primary underlying network iface used by the VPN application - * @return true if it successfully adjusts the accounting for VPN, false otherwise + * @param underlyingIfaces underlying network ifaces used by the VPN application */ - public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { - Entry tunIfaceTotal = new Entry(); - Entry underlyingIfaceTotal = new Entry(); + public void migrateTun(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces) { + // Combined usage by all apps using VPN. + final Entry tunIfaceTotal = new Entry(); + // Usage by VPN, grouped by its {@code underlyingIfaces}. + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + // Usage by VPN, summed across all its {@code underlyingIfaces}. + final Entry underlyingIfacesTotal = new Entry(); - tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); + for (int i = 0; i < perInterfaceTotal.length; i++) { + perInterfaceTotal[i] = new Entry(); + } - // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. + tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, + underlyingIfacesTotal); + + // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); - if (pool.isEmpty()) { - return true; - } - Entry moved = - addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); - deductTrafficFromVpnApp(tunUid, underlyingIface, moved); - - if (!moved.isEmpty()) { - Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" - + moved); - return false; - } - return true; + final Entry[] moved = + addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, + perInterfaceTotal, underlyingIfacesTotal); + deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); } /** * Initializes the data used by the migrateTun() method. * - * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through the tunUid's underlyingIface - * (both foreground and background). - * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *

            This is the first pass iteration which does the following work: + * + *

              + *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and + * background). + *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *
            + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN + * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code + * underlyingIfaces} + * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its + * {@code underlyingIfaces} */ - private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } + if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - - if (recycle.uid == tunUid && recycle.tag == TAG_NONE - && Objects.equals(underlyingIface, recycle.iface)) { - underlyingIfaceTotal.add(recycle); + if (recycle.tag != TAG_NONE) { + // TODO(b/123666283): Take all tags for tunUid into account. + continue; } - if (recycle.uid != tunUid && recycle.tag == TAG_NONE - && Objects.equals(tunIface, recycle.iface)) { + if (recycle.uid == tunUid) { + // Add up traffic through tunUid's underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + perInterfaceTotal[j].add(recycle); + underlyingIfacesTotal.add(recycle); + break; + } + } + } else if (tunIface.equals(recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry pool = new Entry(); - pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); - pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); - pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); - pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); - pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); - return pool; - } + /** + * Distributes traffic across apps that are using given {@code tunIface}, and returns the total + * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} + * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} + * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code + * underlyingIfaces} + */ + private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + // Traffic that should be moved off of each underlying interface for tunUid (see + // deductTrafficFromVpnApp below). + final Entry[] moved = new Entry[underlyingIfaces.length]; + for (int i = 0; i < underlyingIfaces.length; i++) { + moved[i] = new Entry(); + } - private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry pool) { - Entry moved = new Entry(); - Entry tmpEntry = new Entry(); - tmpEntry.iface = underlyingIface; + final Entry tmpEntry = new Entry(); for (int i = 0; i < size; i++) { - // the vpn app is excluded from the redistribution but all moved traffic will be - // deducted from the vpn app (see deductTrafficFromVpnApp below). - if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { - if (tunIfaceTotal.rxBytes > 0) { - tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - } else { - tmpEntry.rxBytes = 0; - } - if (tunIfaceTotal.rxPackets > 0) { - tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - } else { - tmpEntry.rxPackets = 0; - } - if (tunIfaceTotal.txBytes > 0) { - tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - } else { - tmpEntry.txBytes = 0; - } - if (tunIfaceTotal.txPackets > 0) { - tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - } else { - tmpEntry.txPackets = 0; - } - if (tunIfaceTotal.operations > 0) { - tmpEntry.operations = - pool.operations * operations[i] / tunIfaceTotal.operations; - } else { - tmpEntry.operations = 0; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; + if (!Objects.equals(iface[i], tunIface)) { + // Consider only entries that go onto the VPN interface. + continue; + } + if (uid[i] == tunUid) { + // Exclude VPN app from the redistribution, as it can choose to create packet + // streams by writing to itself. + continue; + } + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; + + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. + // TODO: Consider refactoring first pass into a separate helper method. + long totalRxBytes = 0; + if (tunIfaceTotal.rxBytes > 0) { + // Note - The multiplication below should not overflow since NetworkStatsService + // processes this every time device has transmitted/received amount equivalent to + // global threshold alert (~ 2MB) across all interfaces. + final long rxBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + // app must not be blamed for more than it consumed on tunIface + totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); + } + long totalRxPackets = 0; + if (tunIfaceTotal.rxPackets > 0) { + final long rxPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); + } + long totalTxBytes = 0; + if (tunIfaceTotal.txBytes > 0) { + final long txBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); + } + long totalTxPackets = 0; + if (tunIfaceTotal.txPackets > 0) { + final long txPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); + } + long totalOperations = 0; + if (tunIfaceTotal.operations > 0) { + final long operationsAcrossUnderlyingIfaces = + underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; + totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); + } + // In a second pass, distribute these values across interfaces in the proportion that + // each interface represents of the total traffic of the underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + tmpEntry.iface = underlyingIfaces[j]; + tmpEntry.rxBytes = 0; + // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; + if (underlyingIfacesTotal.rxBytes > 0) { + tmpEntry.rxBytes = + totalRxBytes + * perInterfaceTotal[j].rxBytes + / underlyingIfacesTotal.rxBytes; + } + tmpEntry.rxPackets = 0; + if (underlyingIfacesTotal.rxPackets > 0) { + tmpEntry.rxPackets = + totalRxPackets + * perInterfaceTotal[j].rxPackets + / underlyingIfacesTotal.rxPackets; + } + tmpEntry.txBytes = 0; + if (underlyingIfacesTotal.txBytes > 0) { + tmpEntry.txBytes = + totalTxBytes + * perInterfaceTotal[j].txBytes + / underlyingIfacesTotal.txBytes; + } + tmpEntry.txPackets = 0; + if (underlyingIfacesTotal.txPackets > 0) { + tmpEntry.txPackets = + totalTxPackets + * perInterfaceTotal[j].txPackets + / underlyingIfacesTotal.txPackets; + } + tmpEntry.operations = 0; + if (underlyingIfacesTotal.operations > 0) { + tmpEntry.operations = + totalOperations + * perInterfaceTotal[j].operations + / underlyingIfacesTotal.operations; + } + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved.add(tmpEntry); + moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1311,38 +1396,45 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { - // Add debug info - moved.uid = tunUid; - moved.set = SET_DBG_VPN_OUT; - moved.tag = TAG_NONE; - moved.iface = underlyingIface; - moved.metered = METERED_ALL; - moved.roaming = ROAMING_ALL; - moved.defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved); + private void deductTrafficFromVpnApp( + int tunUid, + @NonNull String[] underlyingIfaces, + @NonNull Entry[] moved) { + for (int i = 0; i < underlyingIfaces.length; i++) { + // Add debug info + moved[i].uid = tunUid; + moved[i].set = SET_DBG_VPN_OUT; + moved[i].tag = TAG_NONE; + moved[i].iface = underlyingIfaces[i]; + moved[i].metered = METERED_ALL; + moved[i].roaming = ROAMING_ALL; + moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved[i]); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, - // which should be the case as it comes directly from the /proc file. We only blend in the - // roaming data after applying these adjustments, by checking the NetworkIdentity of the - // underlying iface. - int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - tunSubtract(idxVpnBackground, this, moved); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and + // METERED_NO, which should be the case as it comes directly from the /proc file. + // We only blend in the roaming data after applying these adjustments, by checking the + // NetworkIdentity of the underlying iface. + final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed + // from foreground usage. + tunSubtract(idxVpnBackground, this, moved[i]); + } - int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved); + final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved[i]); + } } } - private static void tunSubtract(int i, NetworkStats left, Entry right) { + private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a2e7e0cae9..bdff50053f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoUtils; - import com.google.android.collect.Sets; +import libcore.io.IoUtils; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); } } From e1c0117fcfa06e4acaa354a3d60a9b48ee67484b Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 18 Jan 2019 19:22:48 -0800 Subject: [PATCH 0635/1150] NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. (cherry picked from commit 48f57628283d7cdacd831af3b5b6de8fb44c20ac) This API is similar to one provided by NetworkStatsFactory with the difference that NSS also migrates traffic from VPN UID to other apps. Since traffic can only be migrated over NetworkStats delta, NSS therefore maintains NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSS records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or getDetailedUidStats API is invoked by one of its callers. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Test: manually verified that battery stats are migrating traffic off of TUN (after patching above CL where we point BatteryStats to use this API). Change-Id: I4b8d7c5b6905a4a12c1806dfd35c2c4c63610404 --- core/java/android/net/NetworkStats.java | 29 +++++--- .../server/net/NetworkStatsFactory.java | 4 ++ .../server/net/NetworkStatsService.java | 70 ++++++++++++++++++- 3 files changed, 93 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f09f2ee223..e8625f34f0 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -34,6 +34,7 @@ import libcore.util.EmptyArray; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; +import java.util.function.Predicate; import java.util.HashSet; import java.util.Map; import java.util.Objects; @@ -994,23 +995,33 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } + filter(e -> (limitUid == UID_ALL || limitUid == e.uid) + && (limitTag == TAG_ALL || limitTag == e.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, e.iface))); + } + /** + * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. + * + *

            This mutates the original structure in place. + */ + public void filterDebugEntries() { + filter(e -> e.set < SET_DEBUG_START); + } + + private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - final boolean matches = - (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, entry.iface)); - - if (matches) { - setValues(nextOutputEntry, entry); + if (predicate.test(entry)) { + if (nextOutputEntry != i) { + setValues(nextOutputEntry, entry); + } nextOutputEntry++; } } - size = nextOutputEntry; } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 69efd02dea..473cc97b7e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -263,6 +263,10 @@ public class NetworkStatsFactory { return stats; } + /** + * @deprecated Use NetworkStatsService#getDetailedUidStats which also accounts for + * VPN traffic + */ public NetworkStats readNetworkStatsDetail() throws IOException { return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f34ace55a7..a13368ff9d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -293,6 +293,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); + /** + * Snapshot containing most recent network stats for all UIDs across all interfaces and tags + * since boot. + * + *

            Maintains migrated VPN stats which are result of performing TUN migration on {@link + * #mLastUidDetailSnapshot}. + */ + @GuardedBy("mStatsLock") + private NetworkStats mTunAdjustedStats; + /** + * Used by {@link #mTunAdjustedStats} to migrate VPN traffic over delta between this snapshot + * and latest snapshot. + */ + @GuardedBy("mStatsLock") + private NetworkStats mLastUidDetailSnapshot; + /** Must be set in factory by calling #setHandler. */ private Handler mHandler; private Handler.Callback mHandlerCallback; @@ -812,15 +828,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { + // Get the latest snapshot from NetworkStatsFactory. + // TODO: Querying for INTERFACES_ALL may incur performance penalty. Consider restricting + // this to limited set of ifaces. + NetworkStats uidDetailStats = getNetworkStatsUidDetail(INTERFACES_ALL); + + // Migrate traffic from VPN UID over delta and update mTunAdjustedStats. + NetworkStats result; + synchronized (mStatsLock) { + migrateTunTraffic(uidDetailStats, mVpnInfos); + result = mTunAdjustedStats.clone(); + } + + // Apply filter based on ifacesToQuery. final String[] ifacesToQuery = NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); - return getNetworkStatsUidDetail(ifacesToQuery); + result.filter(UID_ALL, ifacesToQuery, TAG_ALL); + return result; } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); return new NetworkStats(0L, 0); } } + @VisibleForTesting + NetworkStats getTunAdjustedStats() { + synchronized (mStatsLock) { + if (mTunAdjustedStats == null) { + return null; + } + return mTunAdjustedStats.clone(); + } + } + @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1295,6 +1335,34 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); + + migrateTunTraffic(uidSnapshot, vpnArray); + } + + /** + * Updates {@link #mTunAdjustedStats} with the delta containing traffic migrated off of VPNs. + */ + @GuardedBy("mStatsLock") + private void migrateTunTraffic(NetworkStats uidDetailStats, VpnInfo[] vpnInfoArray) { + if (mTunAdjustedStats == null) { + // Either device booted or system server restarted, hence traffic cannot be migrated + // correctly without knowing the past state of VPN's underlying networks. + mTunAdjustedStats = uidDetailStats; + mLastUidDetailSnapshot = uidDetailStats; + return; + } + // Migrate delta traffic from VPN to other apps. + NetworkStats delta = uidDetailStats.subtract(mLastUidDetailSnapshot); + for (VpnInfo info : vpnInfoArray) { + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + } + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); + // Update #mTunAdjustedStats with migrated delta. + mTunAdjustedStats.combineAllValues(delta); + mTunAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); + // Update last snapshot. + mLastUidDetailSnapshot = uidDetailStats; } /** From 3c3e4846d1fe3fec51756281acbd4715d2837de4 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 24 May 2019 16:29:22 -0700 Subject: [PATCH 0636/1150] Addressing comments for http://ag/7700679. Note, that its in a separate CL so we could cherry-pick this CL to aosp. http://ag/7700679 is already in aosp. Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: I7cfda226b4ed11b67002b83b38fba0f5caf96718 --- core/java/android/net/NetworkStats.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e8625f34f0..bb344e2896 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1300,7 +1300,8 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - for (int i = 0; i < size; i++) { + final int origSize = size; + for (int i = 0; i < origSize; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1316,8 +1317,9 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. + // In a first pass, compute this entry's total share of data across all + // underlyingIfaces. This is computed on the basis of the share of this entry's usage + // over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1394,9 +1396,11 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - + // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying + // interface. Add that data usage to this object. combineValues(tmpEntry); if (tag[i] == TAG_NONE) { + // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1412,8 +1416,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info moved[i].uid = tunUid; + // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; From 146b95b1231c74fc7cf533dd5365a605a9ce8b07 Mon Sep 17 00:00:00 2001 From: chen xu Date: Wed, 22 May 2019 14:10:29 -0700 Subject: [PATCH 0637/1150] NetworkStatAccess Should checkCarrierPrivileges cross all subscriptions Bug: 133236378 Test: Manual Change-Id: I49fbde1fe73b33aadcf8fd23ad224f363b137bf3 Merged-in: I49fbde1fe73b33aadcf8fd23ad224f363b137bf3 --- .../core/java/com/android/server/net/NetworkStatsAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index cebc472178..7c1c1c7ce4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -109,7 +109,7 @@ public final class NetworkStatsAccess { final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); boolean hasCarrierPrivileges = tm != null && - tm.checkCarrierPrivilegesForPackage(callingPackage) == + tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); From 290d5733ae066b79104da41a405596d042bcfef9 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Fri, 24 May 2019 16:29:22 -0700 Subject: [PATCH 0638/1150] Addressing comments for http://ag/7700679. (cherry picked from commit 3c3e4846d1fe3fec51756281acbd4715d2837de4) Note, that its in a separate CL so we could cherry-pick this CL to aosp. http://ag/7700679 is already in aosp (http://aosp/865073). Bug: 113122541 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Ic1767bc8bf1460e4223f86465fc72344428e6055 Merged-In: I7cfda226b4ed11b67002b83b38fba0f5caf96718 --- core/java/android/net/NetworkStats.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 27e0414961..b27b1c0578 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1300,7 +1300,8 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - for (int i = 0; i < size; i++) { + final int origSize = size; + for (int i = 0; i < origSize; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1316,8 +1317,9 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. + // In a first pass, compute this entry's total share of data across all + // underlyingIfaces. This is computed on the basis of the share of this entry's usage + // over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1394,9 +1396,11 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - + // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying + // interface. Add that data usage to this object. combineValues(tmpEntry); if (tag[i] == TAG_NONE) { + // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1412,8 +1416,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info moved[i].uid = tunUid; + // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; From 7123ebdd2f674a88129f1f6eded5e30bbce35d67 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:06:39 -0700 Subject: [PATCH 0639/1150] Revert "Addressing comments for http://ag/7700679." This reverts commit 3c3e4846d1fe3fec51756281acbd4715d2837de4. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I5fbb3443a39a21fc9d96442726cd10d20e8d61cd --- core/java/android/net/NetworkStats.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index bb344e2896..e8625f34f0 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1300,8 +1300,7 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - final int origSize = size; - for (int i = 0; i < origSize; i++) { + for (int i = 0; i < size; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1317,9 +1316,8 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute this entry's total share of data across all - // underlyingIfaces. This is computed on the basis of the share of this entry's usage - // over tunIface. + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1396,11 +1394,9 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying - // interface. Add that data usage to this object. + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1416,8 +1412,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - moved[i].uid = tunUid; // Add debug info + moved[i].uid = tunUid; moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; From ed2eba3a1a94e97cbdc890034e2fd2799b192fe1 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:06:48 -0700 Subject: [PATCH 0640/1150] Revert "NetworkStatsService: Fix getDetailedUidStats to take VPNs into account." This reverts commit e1c0117fcfa06e4acaa354a3d60a9b48ee67484b. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I0c00e8f0e30cee987b71b561079a97bf09d4dae4 --- core/java/android/net/NetworkStats.java | 29 +++----- .../server/net/NetworkStatsFactory.java | 4 -- .../server/net/NetworkStatsService.java | 70 +------------------ 3 files changed, 10 insertions(+), 93 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e8625f34f0..f09f2ee223 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -34,7 +34,6 @@ import libcore.util.EmptyArray; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; -import java.util.function.Predicate; import java.util.HashSet; import java.util.Map; import java.util.Objects; @@ -995,33 +994,23 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } - filter(e -> (limitUid == UID_ALL || limitUid == e.uid) - && (limitTag == TAG_ALL || limitTag == e.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, e.iface))); - } - /** - * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. - * - *

            This mutates the original structure in place. - */ - public void filterDebugEntries() { - filter(e -> e.set < SET_DEBUG_START); - } - - private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - if (predicate.test(entry)) { - if (nextOutputEntry != i) { - setValues(nextOutputEntry, entry); - } + final boolean matches = + (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, entry.iface)); + + if (matches) { + setValues(nextOutputEntry, entry); nextOutputEntry++; } } + size = nextOutputEntry; } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 473cc97b7e..69efd02dea 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -263,10 +263,6 @@ public class NetworkStatsFactory { return stats; } - /** - * @deprecated Use NetworkStatsService#getDetailedUidStats which also accounts for - * VPN traffic - */ public NetworkStats readNetworkStatsDetail() throws IOException { return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a13368ff9d..f34ace55a7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -293,22 +293,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - /** - * Snapshot containing most recent network stats for all UIDs across all interfaces and tags - * since boot. - * - *

            Maintains migrated VPN stats which are result of performing TUN migration on {@link - * #mLastUidDetailSnapshot}. - */ - @GuardedBy("mStatsLock") - private NetworkStats mTunAdjustedStats; - /** - * Used by {@link #mTunAdjustedStats} to migrate VPN traffic over delta between this snapshot - * and latest snapshot. - */ - @GuardedBy("mStatsLock") - private NetworkStats mLastUidDetailSnapshot; - /** Must be set in factory by calling #setHandler. */ private Handler mHandler; private Handler.Callback mHandlerCallback; @@ -828,39 +812,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { - // Get the latest snapshot from NetworkStatsFactory. - // TODO: Querying for INTERFACES_ALL may incur performance penalty. Consider restricting - // this to limited set of ifaces. - NetworkStats uidDetailStats = getNetworkStatsUidDetail(INTERFACES_ALL); - - // Migrate traffic from VPN UID over delta and update mTunAdjustedStats. - NetworkStats result; - synchronized (mStatsLock) { - migrateTunTraffic(uidDetailStats, mVpnInfos); - result = mTunAdjustedStats.clone(); - } - - // Apply filter based on ifacesToQuery. final String[] ifacesToQuery = NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); - result.filter(UID_ALL, ifacesToQuery, TAG_ALL); - return result; + return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); return new NetworkStats(0L, 0); } } - @VisibleForTesting - NetworkStats getTunAdjustedStats() { - synchronized (mStatsLock) { - if (mTunAdjustedStats == null) { - return null; - } - return mTunAdjustedStats.clone(); - } - } - @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1335,34 +1295,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); - - migrateTunTraffic(uidSnapshot, vpnArray); - } - - /** - * Updates {@link #mTunAdjustedStats} with the delta containing traffic migrated off of VPNs. - */ - @GuardedBy("mStatsLock") - private void migrateTunTraffic(NetworkStats uidDetailStats, VpnInfo[] vpnInfoArray) { - if (mTunAdjustedStats == null) { - // Either device booted or system server restarted, hence traffic cannot be migrated - // correctly without knowing the past state of VPN's underlying networks. - mTunAdjustedStats = uidDetailStats; - mLastUidDetailSnapshot = uidDetailStats; - return; - } - // Migrate delta traffic from VPN to other apps. - NetworkStats delta = uidDetailStats.subtract(mLastUidDetailSnapshot); - for (VpnInfo info : vpnInfoArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); - } - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - // Update #mTunAdjustedStats with migrated delta. - mTunAdjustedStats.combineAllValues(delta); - mTunAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); - // Update last snapshot. - mLastUidDetailSnapshot = uidDetailStats; } /** From 4892220eb7f0f7b0bc6ad14dfaf05accd9cf5028 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 6 Jun 2019 17:08:02 -0700 Subject: [PATCH 0641/1150] Revert "Take all VPN underlying networks into account when migrating traffic for" This reverts commit 08c6a361a5e9a289fe89d98f5fc4105e6c9c405e. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: Ibdaad3a4cbf0d8ef1ed53cfab1e454b9b878bae9 --- core/java/android/net/NetworkStats.java | 320 +++++++----------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 117 insertions(+), 209 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f09f2ee223..e892b650bf 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,7 +18,6 @@ package android.net; import static android.os.Process.CLAT_UID; -import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1176,217 +1175,133 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - *

            This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change - * over time. + * This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may + * change over time. * - *

            This method performs adjustments for one active VPN package and one VPN iface at a time. + * This method performs adjustments for one active VPN package and one VPN iface at a time. + * + * It is possible for the VPN software to use multiple underlying networks. This method + * only migrates traffic for the primary underlying network. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param underlyingIface the primary underlying network iface used by the VPN application + * @return true if it successfully adjusts the accounting for VPN, false otherwise */ - public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces) { - // Combined usage by all apps using VPN. - final Entry tunIfaceTotal = new Entry(); - // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; - // Usage by VPN, summed across all its {@code underlyingIfaces}. - final Entry underlyingIfacesTotal = new Entry(); + public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { + Entry tunIfaceTotal = new Entry(); + Entry underlyingIfaceTotal = new Entry(); - for (int i = 0; i < perInterfaceTotal.length; i++) { - perInterfaceTotal[i] = new Entry(); - } + tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); - tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, - underlyingIfacesTotal); - - // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. + // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - final Entry[] moved = - addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, - perInterfaceTotal, underlyingIfacesTotal); - deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); + Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); + if (pool.isEmpty()) { + return true; + } + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); + deductTrafficFromVpnApp(tunUid, underlyingIface, moved); + + if (!moved.isEmpty()) { + Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" + + moved); + return false; + } + return true; } /** * Initializes the data used by the migrateTun() method. * - *

            This is the first pass iteration which does the following work: - * - *

              - *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and - * background). - *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. - *
            - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN - * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code - * underlyingIfaces} - * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its - * {@code underlyingIfaces} + * This is the first pass iteration which does the following work: + * (1) Adds up all the traffic through the tunUid's underlyingIface + * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ - private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - final Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } - if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - if (recycle.tag != TAG_NONE) { - // TODO(b/123666283): Take all tags for tunUid into account. - continue; + + if (recycle.uid == tunUid && recycle.tag == TAG_NONE + && Objects.equals(underlyingIface, recycle.iface)) { + underlyingIfaceTotal.add(recycle); } - if (recycle.uid == tunUid) { - // Add up traffic through tunUid's underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - if (Objects.equals(underlyingIfaces[j], recycle.iface)) { - perInterfaceTotal[j].add(recycle); - underlyingIfacesTotal.add(recycle); - break; - } - } - } else if (tunIface.equals(recycle.iface)) { + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - /** - * Distributes traffic across apps that are using given {@code tunIface}, and returns the total - * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} - * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} - * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code - * underlyingIfaces} - */ - private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - // Traffic that should be moved off of each underlying interface for tunUid (see - // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.length]; - for (int i = 0; i < underlyingIfaces.length; i++) { - moved[i] = new Entry(); - } + private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry pool = new Entry(); + pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); + pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); + pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); + pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); + pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); + return pool; + } - final Entry tmpEntry = new Entry(); + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry pool) { + Entry moved = new Entry(); + Entry tmpEntry = new Entry(); + tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (!Objects.equals(iface[i], tunIface)) { - // Consider only entries that go onto the VPN interface. - continue; - } - if (uid[i] == tunUid) { - // Exclude VPN app from the redistribution, as it can choose to create packet - // streams by writing to itself. - continue; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; - - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. - // TODO: Consider refactoring first pass into a separate helper method. - long totalRxBytes = 0; - if (tunIfaceTotal.rxBytes > 0) { - // Note - The multiplication below should not overflow since NetworkStatsService - // processes this every time device has transmitted/received amount equivalent to - // global threshold alert (~ 2MB) across all interfaces. - final long rxBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - // app must not be blamed for more than it consumed on tunIface - totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); - } - long totalRxPackets = 0; - if (tunIfaceTotal.rxPackets > 0) { - final long rxPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); - } - long totalTxBytes = 0; - if (tunIfaceTotal.txBytes > 0) { - final long txBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); - } - long totalTxPackets = 0; - if (tunIfaceTotal.txPackets > 0) { - final long txPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); - } - long totalOperations = 0; - if (tunIfaceTotal.operations > 0) { - final long operationsAcrossUnderlyingIfaces = - underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; - totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); - } - // In a second pass, distribute these values across interfaces in the proportion that - // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - tmpEntry.iface = underlyingIfaces[j]; - tmpEntry.rxBytes = 0; - // Reset 'set' to correct value since it gets updated when adding debug info below. - tmpEntry.set = set[i]; - if (underlyingIfacesTotal.rxBytes > 0) { - tmpEntry.rxBytes = - totalRxBytes - * perInterfaceTotal[j].rxBytes - / underlyingIfacesTotal.rxBytes; + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { + if (tunIfaceTotal.rxBytes > 0) { + tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + } else { + tmpEntry.rxBytes = 0; } - tmpEntry.rxPackets = 0; - if (underlyingIfacesTotal.rxPackets > 0) { - tmpEntry.rxPackets = - totalRxPackets - * perInterfaceTotal[j].rxPackets - / underlyingIfacesTotal.rxPackets; + if (tunIfaceTotal.rxPackets > 0) { + tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + } else { + tmpEntry.rxPackets = 0; } - tmpEntry.txBytes = 0; - if (underlyingIfacesTotal.txBytes > 0) { - tmpEntry.txBytes = - totalTxBytes - * perInterfaceTotal[j].txBytes - / underlyingIfacesTotal.txBytes; + if (tunIfaceTotal.txBytes > 0) { + tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + } else { + tmpEntry.txBytes = 0; } - tmpEntry.txPackets = 0; - if (underlyingIfacesTotal.txPackets > 0) { - tmpEntry.txPackets = - totalTxPackets - * perInterfaceTotal[j].txPackets - / underlyingIfacesTotal.txPackets; + if (tunIfaceTotal.txPackets > 0) { + tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + } else { + tmpEntry.txPackets = 0; } - tmpEntry.operations = 0; - if (underlyingIfacesTotal.operations > 0) { + if (tunIfaceTotal.operations > 0) { tmpEntry.operations = - totalOperations - * perInterfaceTotal[j].operations - / underlyingIfacesTotal.operations; + pool.operations * operations[i] / tunIfaceTotal.operations; + } else { + tmpEntry.operations = 0; } - + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved[j].add(tmpEntry); + moved.add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1396,45 +1311,38 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp( - int tunUid, - @NonNull String[] underlyingIfaces, - @NonNull Entry[] moved) { - for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info - moved[i].uid = tunUid; - moved[i].set = SET_DBG_VPN_OUT; - moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces[i]; - moved[i].metered = METERED_ALL; - moved[i].roaming = ROAMING_ALL; - moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved[i]); + private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { + // Add debug info + moved.uid = tunUid; + moved.set = SET_DBG_VPN_OUT; + moved.tag = TAG_NONE; + moved.iface = underlyingIface; + moved.metered = METERED_ALL; + moved.roaming = ROAMING_ALL; + moved.defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and - // METERED_NO, which should be the case as it comes directly from the /proc file. - // We only blend in the roaming data after applying these adjustments, by checking the - // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed - // from foreground usage. - tunSubtract(idxVpnBackground, this, moved[i]); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the + // roaming data after applying these adjustments, by checking the NetworkIdentity of the + // underlying iface. + int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + tunSubtract(idxVpnBackground, this, moved); + } - final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved[i]); - } + int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved); } } - private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { + private static void tunSubtract(int i, NetworkStats left, Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index bdff50053f..a2e7e0cae9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import com.google.android.collect.Sets; - import libcore.io.IoUtils; +import com.google.android.collect.Sets; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); } } From 656c5eb953cfa40ff998f3f7fa392060ac492e03 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Mon, 10 Jun 2019 22:42:53 +0000 Subject: [PATCH 0642/1150] Revert "Addressing comments for http://ag/7700679." This reverts commit 290d5733ae066b79104da41a405596d042bcfef9. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I12ab724e2ef8a5c1b42078330ba74713ff86fdd1 Merged-In: I5fbb3443a39a21fc9d96442726cd10d20e8d61cd --- core/java/android/net/NetworkStats.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b27b1c0578..27e0414961 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1300,8 +1300,7 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - final int origSize = size; - for (int i = 0; i < origSize; i++) { + for (int i = 0; i < size; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1317,9 +1316,8 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute this entry's total share of data across all - // underlyingIfaces. This is computed on the basis of the share of this entry's usage - // over tunIface. + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1396,11 +1394,9 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying - // interface. Add that data usage to this object. + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1416,8 +1412,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - moved[i].uid = tunUid; // Add debug info + moved[i].uid = tunUid; moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; From 765cb4beee817a09889c02b55f528456f50fa932 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Mon, 10 Jun 2019 22:43:52 +0000 Subject: [PATCH 0643/1150] Revert "NetworkStatsService: Fix getDetailedUidStats to take VPNs into account." This reverts commit 48f57628283d7cdacd831af3b5b6de8fb44c20ac. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I37f75c2b243ea548a88ef1dae88287405c6ef55f Merged-In: I0c00e8f0e30cee987b71b561079a97bf09d4dae4 --- core/java/android/net/NetworkStats.java | 29 +++----- .../server/net/NetworkStatsFactory.java | 5 -- .../server/net/NetworkStatsService.java | 70 +------------------ 3 files changed, 10 insertions(+), 94 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 27e0414961..9e79606a24 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -34,7 +34,6 @@ import libcore.util.EmptyArray; import java.io.CharArrayWriter; import java.io.PrintWriter; import java.util.Arrays; -import java.util.function.Predicate; import java.util.HashSet; import java.util.Map; import java.util.Objects; @@ -995,33 +994,23 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } - filter(e -> (limitUid == UID_ALL || limitUid == e.uid) - && (limitTag == TAG_ALL || limitTag == e.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, e.iface))); - } - /** - * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. - * - *

            This mutates the original structure in place. - */ - public void filterDebugEntries() { - filter(e -> e.set < SET_DEBUG_START); - } - - private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - if (predicate.test(entry)) { - if (nextOutputEntry != i) { - setValues(nextOutputEntry, entry); - } + final boolean matches = + (limitUid == UID_ALL || limitUid == entry.uid) + && (limitTag == TAG_ALL || limitTag == entry.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, entry.iface)); + + if (matches) { + setValues(nextOutputEntry, entry); nextOutputEntry++; } } + size = nextOutputEntry; } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 2e64965a61..69efd02dea 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -263,11 +263,6 @@ public class NetworkStatsFactory { return stats; } - /** - * @deprecated Use NetworkStatsService#getDetailedUidStats which also accounts for - * VPN traffic - */ - @Deprecated public NetworkStats readNetworkStatsDetail() throws IOException { return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 484efd6bfd..f9972dd873 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -292,22 +292,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - /** - * Snapshot containing most recent network stats for all UIDs across all interfaces and tags - * since boot. - * - *

            Maintains migrated VPN stats which are result of performing TUN migration on {@link - * #mLastUidDetailSnapshot}. - */ - @GuardedBy("mStatsLock") - private NetworkStats mTunAdjustedStats; - /** - * Used by {@link #mTunAdjustedStats} to migrate VPN traffic over delta between this snapshot - * and latest snapshot. - */ - @GuardedBy("mStatsLock") - private NetworkStats mLastUidDetailSnapshot; - /** Must be set in factory by calling #setHandler. */ private Handler mHandler; private Handler.Callback mHandlerCallback; @@ -821,39 +805,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { - // Get the latest snapshot from NetworkStatsFactory. - // TODO: Querying for INTERFACES_ALL may incur performance penalty. Consider restricting - // this to limited set of ifaces. - NetworkStats uidDetailStats = getNetworkStatsUidDetail(INTERFACES_ALL); - - // Migrate traffic from VPN UID over delta and update mTunAdjustedStats. - NetworkStats result; - synchronized (mStatsLock) { - migrateTunTraffic(uidDetailStats, mVpnInfos); - result = mTunAdjustedStats.clone(); - } - - // Apply filter based on ifacesToQuery. final String[] ifacesToQuery = NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); - result.filter(UID_ALL, ifacesToQuery, TAG_ALL); - return result; + return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); return new NetworkStats(0L, 0); } } - @VisibleForTesting - NetworkStats getTunAdjustedStats() { - synchronized (mStatsLock) { - if (mTunAdjustedStats == null) { - return null; - } - return mTunAdjustedStats.clone(); - } - } - @Override public String[] getMobileIfaces() { return mMobileIfaces; @@ -1328,34 +1288,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); - - migrateTunTraffic(uidSnapshot, vpnArray); - } - - /** - * Updates {@link #mTunAdjustedStats} with the delta containing traffic migrated off of VPNs. - */ - @GuardedBy("mStatsLock") - private void migrateTunTraffic(NetworkStats uidDetailStats, VpnInfo[] vpnInfoArray) { - if (mTunAdjustedStats == null) { - // Either device booted or system server restarted, hence traffic cannot be migrated - // correctly without knowing the past state of VPN's underlying networks. - mTunAdjustedStats = uidDetailStats; - mLastUidDetailSnapshot = uidDetailStats; - return; - } - // Migrate delta traffic from VPN to other apps. - NetworkStats delta = uidDetailStats.subtract(mLastUidDetailSnapshot); - for (VpnInfo info : vpnInfoArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); - } - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - // Update #mTunAdjustedStats with migrated delta. - mTunAdjustedStats.combineAllValues(delta); - mTunAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); - // Update last snapshot. - mLastUidDetailSnapshot = uidDetailStats; } /** From 48608ad513c64a1f7d5436b5e013d16f5319e583 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Mon, 10 Jun 2019 22:44:57 +0000 Subject: [PATCH 0644/1150] Revert "Take all VPN underlying networks into account when migrating traffic for" This reverts commit 2e2662fbcfe1611def7ee2055cf17cb2f39d9511. Reason for revert: This change has been implicated in 4-way deadlocks as seen in b/134244752. Bug: 134244752 Change-Id: I2f1839d7776a613ca571af8a542755ddc5fc8760 Merged-In: Ibdaad3a4cbf0d8ef1ed53cfab1e454b9b878bae9 --- core/java/android/net/NetworkStats.java | 320 +++++++----------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 117 insertions(+), 209 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9e79606a24..9cf582bef1 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,7 +18,6 @@ package android.net; import static android.os.Process.CLAT_UID; -import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1176,217 +1175,133 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - *

            This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change - * over time. + * This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may + * change over time. * - *

            This method performs adjustments for one active VPN package and one VPN iface at a time. + * This method performs adjustments for one active VPN package and one VPN iface at a time. + * + * It is possible for the VPN software to use multiple underlying networks. This method + * only migrates traffic for the primary underlying network. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param underlyingIface the primary underlying network iface used by the VPN application + * @return true if it successfully adjusts the accounting for VPN, false otherwise */ - public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces) { - // Combined usage by all apps using VPN. - final Entry tunIfaceTotal = new Entry(); - // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; - // Usage by VPN, summed across all its {@code underlyingIfaces}. - final Entry underlyingIfacesTotal = new Entry(); + public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { + Entry tunIfaceTotal = new Entry(); + Entry underlyingIfaceTotal = new Entry(); - for (int i = 0; i < perInterfaceTotal.length; i++) { - perInterfaceTotal[i] = new Entry(); - } + tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); - tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, - underlyingIfacesTotal); - - // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. + // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - final Entry[] moved = - addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, - perInterfaceTotal, underlyingIfacesTotal); - deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); + Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); + if (pool.isEmpty()) { + return true; + } + Entry moved = + addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); + deductTrafficFromVpnApp(tunUid, underlyingIface, moved); + + if (!moved.isEmpty()) { + Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" + + moved); + return false; + } + return true; } /** * Initializes the data used by the migrateTun() method. * - *

            This is the first pass iteration which does the following work: - * - *

              - *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and - * background). - *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. - *
            - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN - * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code - * underlyingIfaces} - * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its - * {@code underlyingIfaces} + * This is the first pass iteration which does the following work: + * (1) Adds up all the traffic through the tunUid's underlyingIface + * (both foreground and background). + * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. */ - private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - final Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } - if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - if (recycle.tag != TAG_NONE) { - // TODO(b/123666283): Take all tags for tunUid into account. - continue; + + if (recycle.uid == tunUid && recycle.tag == TAG_NONE + && Objects.equals(underlyingIface, recycle.iface)) { + underlyingIfaceTotal.add(recycle); } - if (recycle.uid == tunUid) { - // Add up traffic through tunUid's underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - if (Objects.equals(underlyingIfaces[j], recycle.iface)) { - perInterfaceTotal[j].add(recycle); - underlyingIfacesTotal.add(recycle); - break; - } - } - } else if (tunIface.equals(recycle.iface)) { + if (recycle.uid != tunUid && recycle.tag == TAG_NONE + && Objects.equals(tunIface, recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - /** - * Distributes traffic across apps that are using given {@code tunIface}, and returns the total - * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. - * - * @param tunUid uid of the VPN application - * @param tunIface iface of the vpn tunnel - * @param underlyingIfaces underlying network ifaces used by the VPN application - * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} - * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} - * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code - * underlyingIfaces} - */ - private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, - @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { - // Traffic that should be moved off of each underlying interface for tunUid (see - // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.length]; - for (int i = 0; i < underlyingIfaces.length; i++) { - moved[i] = new Entry(); - } + private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { + Entry pool = new Entry(); + pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); + pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); + pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); + pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); + pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); + return pool; + } - final Entry tmpEntry = new Entry(); + private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, + Entry tunIfaceTotal, Entry pool) { + Entry moved = new Entry(); + Entry tmpEntry = new Entry(); + tmpEntry.iface = underlyingIface; for (int i = 0; i < size; i++) { - if (!Objects.equals(iface[i], tunIface)) { - // Consider only entries that go onto the VPN interface. - continue; - } - if (uid[i] == tunUid) { - // Exclude VPN app from the redistribution, as it can choose to create packet - // streams by writing to itself. - continue; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; - - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. - // TODO: Consider refactoring first pass into a separate helper method. - long totalRxBytes = 0; - if (tunIfaceTotal.rxBytes > 0) { - // Note - The multiplication below should not overflow since NetworkStatsService - // processes this every time device has transmitted/received amount equivalent to - // global threshold alert (~ 2MB) across all interfaces. - final long rxBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - // app must not be blamed for more than it consumed on tunIface - totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); - } - long totalRxPackets = 0; - if (tunIfaceTotal.rxPackets > 0) { - final long rxPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); - } - long totalTxBytes = 0; - if (tunIfaceTotal.txBytes > 0) { - final long txBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); - } - long totalTxPackets = 0; - if (tunIfaceTotal.txPackets > 0) { - final long txPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); - } - long totalOperations = 0; - if (tunIfaceTotal.operations > 0) { - final long operationsAcrossUnderlyingIfaces = - underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; - totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); - } - // In a second pass, distribute these values across interfaces in the proportion that - // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - tmpEntry.iface = underlyingIfaces[j]; - tmpEntry.rxBytes = 0; - // Reset 'set' to correct value since it gets updated when adding debug info below. - tmpEntry.set = set[i]; - if (underlyingIfacesTotal.rxBytes > 0) { - tmpEntry.rxBytes = - totalRxBytes - * perInterfaceTotal[j].rxBytes - / underlyingIfacesTotal.rxBytes; + // the vpn app is excluded from the redistribution but all moved traffic will be + // deducted from the vpn app (see deductTrafficFromVpnApp below). + if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { + if (tunIfaceTotal.rxBytes > 0) { + tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + } else { + tmpEntry.rxBytes = 0; } - tmpEntry.rxPackets = 0; - if (underlyingIfacesTotal.rxPackets > 0) { - tmpEntry.rxPackets = - totalRxPackets - * perInterfaceTotal[j].rxPackets - / underlyingIfacesTotal.rxPackets; + if (tunIfaceTotal.rxPackets > 0) { + tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + } else { + tmpEntry.rxPackets = 0; } - tmpEntry.txBytes = 0; - if (underlyingIfacesTotal.txBytes > 0) { - tmpEntry.txBytes = - totalTxBytes - * perInterfaceTotal[j].txBytes - / underlyingIfacesTotal.txBytes; + if (tunIfaceTotal.txBytes > 0) { + tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + } else { + tmpEntry.txBytes = 0; } - tmpEntry.txPackets = 0; - if (underlyingIfacesTotal.txPackets > 0) { - tmpEntry.txPackets = - totalTxPackets - * perInterfaceTotal[j].txPackets - / underlyingIfacesTotal.txPackets; + if (tunIfaceTotal.txPackets > 0) { + tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + } else { + tmpEntry.txPackets = 0; } - tmpEntry.operations = 0; - if (underlyingIfacesTotal.operations > 0) { + if (tunIfaceTotal.operations > 0) { tmpEntry.operations = - totalOperations - * perInterfaceTotal[j].operations - / underlyingIfacesTotal.operations; + pool.operations * operations[i] / tunIfaceTotal.operations; + } else { + tmpEntry.operations = 0; } - + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.set = set[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved[j].add(tmpEntry); + moved.add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1396,45 +1311,38 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp( - int tunUid, - @NonNull String[] underlyingIfaces, - @NonNull Entry[] moved) { - for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info - moved[i].uid = tunUid; - moved[i].set = SET_DBG_VPN_OUT; - moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces[i]; - moved[i].metered = METERED_ALL; - moved[i].roaming = ROAMING_ALL; - moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved[i]); + private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { + // Add debug info + moved.uid = tunUid; + moved.set = SET_DBG_VPN_OUT; + moved.tag = TAG_NONE; + moved.iface = underlyingIface; + moved.metered = METERED_ALL; + moved.roaming = ROAMING_ALL; + moved.defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and - // METERED_NO, which should be the case as it comes directly from the /proc file. - // We only blend in the roaming data after applying these adjustments, by checking the - // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed - // from foreground usage. - tunSubtract(idxVpnBackground, this, moved[i]); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, + // which should be the case as it comes directly from the /proc file. We only blend in the + // roaming data after applying these adjustments, by checking the NetworkIdentity of the + // underlying iface. + int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + tunSubtract(idxVpnBackground, this, moved); + } - final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, - TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved[i]); - } + int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, + METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved); } } - private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { + private static void tunSubtract(int i, NetworkStats left, Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index bdff50053f..a2e7e0cae9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import com.google.android.collect.Sets; - import libcore.io.IoUtils; +import com.google.android.collect.Sets; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); } } From 2cc14c8bed81164b2c7747f715ed57aa40dc84bc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 Jun 2019 17:46:15 +0000 Subject: [PATCH 0645/1150] Revert "Revert "Take all VPN underlying networks into account when migrating traffic for"" This reverts commit 48608ad513c64a1f7d5436b5e013d16f5319e583. Reason for revert: Fix available for deadlocks. Bug: 134244752 Change-Id: Ib65214598837289bd39dbf040b56ab7835f893ba --- core/java/android/net/NetworkStats.java | 330 +++++++++++------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 214 insertions(+), 122 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9cf582bef1..9e79606a24 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,6 +18,7 @@ package android.net; import static android.os.Process.CLAT_UID; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1175,133 +1176,217 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - * This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may - * change over time. + *

            This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change + * over time. * - * This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * It is possible for the VPN software to use multiple underlying networks. This method - * only migrates traffic for the primary underlying network. + *

            This method performs adjustments for one active VPN package and one VPN iface at a time. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIface the primary underlying network iface used by the VPN application - * @return true if it successfully adjusts the accounting for VPN, false otherwise + * @param underlyingIfaces underlying network ifaces used by the VPN application */ - public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { - Entry tunIfaceTotal = new Entry(); - Entry underlyingIfaceTotal = new Entry(); + public void migrateTun(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces) { + // Combined usage by all apps using VPN. + final Entry tunIfaceTotal = new Entry(); + // Usage by VPN, grouped by its {@code underlyingIfaces}. + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + // Usage by VPN, summed across all its {@code underlyingIfaces}. + final Entry underlyingIfacesTotal = new Entry(); - tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); + for (int i = 0; i < perInterfaceTotal.length; i++) { + perInterfaceTotal[i] = new Entry(); + } - // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. + tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, + underlyingIfacesTotal); + + // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); - if (pool.isEmpty()) { - return true; - } - Entry moved = - addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); - deductTrafficFromVpnApp(tunUid, underlyingIface, moved); - - if (!moved.isEmpty()) { - Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" - + moved); - return false; - } - return true; + final Entry[] moved = + addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, + perInterfaceTotal, underlyingIfacesTotal); + deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); } /** * Initializes the data used by the migrateTun() method. * - * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through the tunUid's underlyingIface - * (both foreground and background). - * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *

            This is the first pass iteration which does the following work: + * + *

              + *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and + * background). + *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *
            + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN + * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code + * underlyingIfaces} + * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its + * {@code underlyingIfaces} */ - private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } + if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - - if (recycle.uid == tunUid && recycle.tag == TAG_NONE - && Objects.equals(underlyingIface, recycle.iface)) { - underlyingIfaceTotal.add(recycle); + if (recycle.tag != TAG_NONE) { + // TODO(b/123666283): Take all tags for tunUid into account. + continue; } - if (recycle.uid != tunUid && recycle.tag == TAG_NONE - && Objects.equals(tunIface, recycle.iface)) { + if (recycle.uid == tunUid) { + // Add up traffic through tunUid's underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + perInterfaceTotal[j].add(recycle); + underlyingIfacesTotal.add(recycle); + break; + } + } + } else if (tunIface.equals(recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry pool = new Entry(); - pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); - pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); - pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); - pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); - pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); - return pool; - } + /** + * Distributes traffic across apps that are using given {@code tunIface}, and returns the total + * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} + * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} + * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code + * underlyingIfaces} + */ + private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + // Traffic that should be moved off of each underlying interface for tunUid (see + // deductTrafficFromVpnApp below). + final Entry[] moved = new Entry[underlyingIfaces.length]; + for (int i = 0; i < underlyingIfaces.length; i++) { + moved[i] = new Entry(); + } - private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry pool) { - Entry moved = new Entry(); - Entry tmpEntry = new Entry(); - tmpEntry.iface = underlyingIface; + final Entry tmpEntry = new Entry(); for (int i = 0; i < size; i++) { - // the vpn app is excluded from the redistribution but all moved traffic will be - // deducted from the vpn app (see deductTrafficFromVpnApp below). - if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { - if (tunIfaceTotal.rxBytes > 0) { - tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - } else { - tmpEntry.rxBytes = 0; - } - if (tunIfaceTotal.rxPackets > 0) { - tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - } else { - tmpEntry.rxPackets = 0; - } - if (tunIfaceTotal.txBytes > 0) { - tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - } else { - tmpEntry.txBytes = 0; - } - if (tunIfaceTotal.txPackets > 0) { - tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - } else { - tmpEntry.txPackets = 0; - } - if (tunIfaceTotal.operations > 0) { - tmpEntry.operations = - pool.operations * operations[i] / tunIfaceTotal.operations; - } else { - tmpEntry.operations = 0; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; + if (!Objects.equals(iface[i], tunIface)) { + // Consider only entries that go onto the VPN interface. + continue; + } + if (uid[i] == tunUid) { + // Exclude VPN app from the redistribution, as it can choose to create packet + // streams by writing to itself. + continue; + } + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; + + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. + // TODO: Consider refactoring first pass into a separate helper method. + long totalRxBytes = 0; + if (tunIfaceTotal.rxBytes > 0) { + // Note - The multiplication below should not overflow since NetworkStatsService + // processes this every time device has transmitted/received amount equivalent to + // global threshold alert (~ 2MB) across all interfaces. + final long rxBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + // app must not be blamed for more than it consumed on tunIface + totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); + } + long totalRxPackets = 0; + if (tunIfaceTotal.rxPackets > 0) { + final long rxPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); + } + long totalTxBytes = 0; + if (tunIfaceTotal.txBytes > 0) { + final long txBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); + } + long totalTxPackets = 0; + if (tunIfaceTotal.txPackets > 0) { + final long txPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); + } + long totalOperations = 0; + if (tunIfaceTotal.operations > 0) { + final long operationsAcrossUnderlyingIfaces = + underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; + totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); + } + // In a second pass, distribute these values across interfaces in the proportion that + // each interface represents of the total traffic of the underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + tmpEntry.iface = underlyingIfaces[j]; + tmpEntry.rxBytes = 0; + // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; + if (underlyingIfacesTotal.rxBytes > 0) { + tmpEntry.rxBytes = + totalRxBytes + * perInterfaceTotal[j].rxBytes + / underlyingIfacesTotal.rxBytes; + } + tmpEntry.rxPackets = 0; + if (underlyingIfacesTotal.rxPackets > 0) { + tmpEntry.rxPackets = + totalRxPackets + * perInterfaceTotal[j].rxPackets + / underlyingIfacesTotal.rxPackets; + } + tmpEntry.txBytes = 0; + if (underlyingIfacesTotal.txBytes > 0) { + tmpEntry.txBytes = + totalTxBytes + * perInterfaceTotal[j].txBytes + / underlyingIfacesTotal.txBytes; + } + tmpEntry.txPackets = 0; + if (underlyingIfacesTotal.txPackets > 0) { + tmpEntry.txPackets = + totalTxPackets + * perInterfaceTotal[j].txPackets + / underlyingIfacesTotal.txPackets; + } + tmpEntry.operations = 0; + if (underlyingIfacesTotal.operations > 0) { + tmpEntry.operations = + totalOperations + * perInterfaceTotal[j].operations + / underlyingIfacesTotal.operations; + } + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved.add(tmpEntry); + moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1311,38 +1396,45 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { - // Add debug info - moved.uid = tunUid; - moved.set = SET_DBG_VPN_OUT; - moved.tag = TAG_NONE; - moved.iface = underlyingIface; - moved.metered = METERED_ALL; - moved.roaming = ROAMING_ALL; - moved.defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved); + private void deductTrafficFromVpnApp( + int tunUid, + @NonNull String[] underlyingIfaces, + @NonNull Entry[] moved) { + for (int i = 0; i < underlyingIfaces.length; i++) { + // Add debug info + moved[i].uid = tunUid; + moved[i].set = SET_DBG_VPN_OUT; + moved[i].tag = TAG_NONE; + moved[i].iface = underlyingIfaces[i]; + moved[i].metered = METERED_ALL; + moved[i].roaming = ROAMING_ALL; + moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved[i]); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, - // which should be the case as it comes directly from the /proc file. We only blend in the - // roaming data after applying these adjustments, by checking the NetworkIdentity of the - // underlying iface. - int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - tunSubtract(idxVpnBackground, this, moved); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and + // METERED_NO, which should be the case as it comes directly from the /proc file. + // We only blend in the roaming data after applying these adjustments, by checking the + // NetworkIdentity of the underlying iface. + final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed + // from foreground usage. + tunSubtract(idxVpnBackground, this, moved[i]); + } - int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved); + final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved[i]); + } } } - private static void tunSubtract(int i, NetworkStats left, Entry right) { + private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a2e7e0cae9..bdff50053f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoUtils; - import com.google.android.collect.Sets; +import libcore.io.IoUtils; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); } } From d9d6958e06b75b295e8a6e5fd21d181783c7ec9d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 11 Jun 2019 18:21:30 -0700 Subject: [PATCH 0646/1150] Remove unused lastStats parameter This change removes an unused parameter that is always null in getNetworkStatsUidDetail Bug: 134244752 Test: FrameworksNetTest passing Change-Id: I995b108ef30e1fbd6190131ed4db40a3d9327eb5 --- .../server/net/NetworkStatsFactory.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 69efd02dea..c118bda88c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -16,6 +16,7 @@ package com.android.server.net; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; @@ -264,13 +265,21 @@ public class NetworkStatsFactory { } public NetworkStats readNetworkStatsDetail() throws IOException { - return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); + return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); } - public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, - NetworkStats lastStats) throws IOException { - final NetworkStats stats = - readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); + /** + * Reads the detailed UID stats based on the provided parameters + * + * @param limitUid the UID to limit this query to + * @param limitIfaces the interfaces to limit this query to. Use {@link + * NetworkStats.INTERFACES_ALL} to select all interfaces + * @param limitTag the tags to limit this query to + * @return the NetworkStats instance containing network statistics at the present time. + */ + public NetworkStats readNetworkStatsDetail( + int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { + final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. // TODO: remove this and only apply adjustments in NetworkStatsService. @@ -292,17 +301,11 @@ public class NetworkStatsFactory { } } - // TODO: delete the lastStats parameter - private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, - int limitTag, NetworkStats lastStats) throws IOException { + private NetworkStats readNetworkStatsDetailInternal( + int limitUid, String[] limitIfaces, int limitTag) throws IOException { if (USE_NATIVE_PARSING) { - final NetworkStats stats; - if (lastStats != null) { - stats = lastStats; - stats.setElapsedRealtime(SystemClock.elapsedRealtime()); - } else { - stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); - } + final NetworkStats stats = + new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); if (mUseBpfStats) { synchronized (mPersistSnapshot) { try { From 7d5e62485b2025231a206d1833f14019a38f1bbf Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 Jun 2019 17:46:31 +0000 Subject: [PATCH 0647/1150] NetworkStatsFactory: Take VPNs into account for network/battery stats This change fixes detailed UID stats to ensure network and battery stats both take VPNs into account. NetworkStatsFactory is being made aware of VPNs enabled, and the full set of underlying networks present. Since traffic can only be migrated over a NetworkStats delta, NSF maintains a NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSF records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or NetworkStatsService's getDetailedUidStats() method being called. This change widens the scope of the existing mPersistentSnapshot lock, renaming it to mPersistentDataLock, and ensures that TUN migrations are not done in parallel. Additionally, mVpnInfos is updated via pointer-swapping, to reduce the scope of the mPersistentDataLock. The safety of this change is predicated on: 1. NetworkStatsFactory lock not held, so services cannot deadlock through the cyclical lock. 2. The broadening of the scope of the lock in NetworkStatsFactory has no threading implications, as it is always the last (leaf node) lock held, and therefore is impossible to have lock inversion. Additionally, to ensure VPNs work with 464xlat, the VPN info passed to the NetworkStatsFactory includes all underlying interfaces, instead of only passing the first one. This (partially) re-applies changes from: aosp/972848: Add one more test for VPN usage stats. aosp/972847: Addressing comments for http://ag/7700679. aosp/885338: NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. Co-developed with: Varun Anand Bug: 113122541 Bug: 120145746 Bug: 129264869 Bug: 134244752 Test: FrameworksNetTest passing Test: Manual tests show data usage fixes maintained. Change-Id: I6466ec1411fc5ed6954125d27d353b6cd1be719e --- .../android/net/INetworkStatsService.aidl | 1 - core/java/android/net/NetworkStats.java | 44 ++++-- .../server/net/NetworkStatsFactory.java | 135 +++++++++++++----- .../server/net/NetworkStatsService.java | 28 ++-- 4 files changed, 140 insertions(+), 68 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 41efc50408..e5f3d26667 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -66,7 +66,6 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces( in Network[] defaultNetworks, - in VpnInfo[] vpnArray, in NetworkState[] networkStates, in String activeIface); /** Force update of statistics. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9e79606a24..14a0cbf611 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -23,7 +23,6 @@ import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; @@ -37,6 +36,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.function.Predicate; /** * Collection of active network statistics. Can contain summary details across @@ -994,23 +994,33 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } + filter(e -> (limitUid == UID_ALL || limitUid == e.uid) + && (limitTag == TAG_ALL || limitTag == e.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, e.iface))); + } + /** + * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. + * + *

            This mutates the original structure in place. + */ + public void filterDebugEntries() { + filter(e -> e.set < SET_DEBUG_START); + } + + private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - final boolean matches = - (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, entry.iface)); - - if (matches) { - setValues(nextOutputEntry, entry); + if (predicate.test(entry)) { + if (nextOutputEntry != i) { + setValues(nextOutputEntry, entry); + } nextOutputEntry++; } } - size = nextOutputEntry; } @@ -1289,7 +1299,8 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - for (int i = 0; i < size; i++) { + final int origSize = size; + for (int i = 0; i < origSize; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1305,8 +1316,9 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. + // In a first pass, compute this entry's total share of data across all + // underlyingIfaces. This is computed on the basis of the share of this entry's usage + // over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1383,9 +1395,11 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - + // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying + // interface. Add that data usage to this object. combineValues(tmpEntry); if (tag[i] == TAG_NONE) { + // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1401,8 +1415,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info moved[i].uid = tunUid; + // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index c118bda88c..2d3c66d68f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -34,6 +34,7 @@ import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; @@ -71,11 +72,25 @@ public class NetworkStatsFactory { private INetd mNetdService; - // A persistent Snapshot since device start for eBPF stats - @GuardedBy("mPersistSnapshot") - private final NetworkStats mPersistSnapshot; + /** + * Guards persistent data access in this class + * + *

            In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out + * to other code that will acquire other locks within the system server. See b/134244752. + */ + private static final Object sPersistentDataLock = new Object(); + + /** Set containing info about active VPNs and their underlying networks. */ + private static volatile VpnInfo[] sVpnInfos = new VpnInfo[0]; + + // A persistent snapshot of cumulative stats since device start + @GuardedBy("sPersistentDataLock") + private NetworkStats mPersistSnapshot; + + // The persistent snapshot of tun and 464xlat adjusted stats since device start + @GuardedBy("sPersistentDataLock") + private NetworkStats mTunAnd464xlatAdjustedStats; - // TODO: only do adjustments in NetworkStatsService and remove this. /** * (Stacked interface) -> (base interface) association for all connected ifaces since boot. * @@ -91,6 +106,24 @@ public class NetworkStatsFactory { } } + /** + * Set active VPN information for data usage migration purposes + * + *

            Traffic on TUN-based VPNs inherently all appear to be originated from the VPN providing + * app's UID. This method is used to support migration of VPN data usage, ensuring data is + * accurately billed to the real owner of the traffic. + * + * @param vpnArray The snapshot of the currently-running VPNs. + */ + public static void updateVpnInfos(VpnInfo[] vpnArray) { + sVpnInfos = vpnArray.clone(); + } + + @VisibleForTesting + public static VpnInfo[] getVpnInfos() { + return sVpnInfos.clone(); + } + /** * Get a set of interfaces containing specified ifaces and stacked interfaces. * @@ -147,6 +180,7 @@ public class NetworkStatsFactory { mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); + mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } public NetworkStats readBpfNetworkStatsDev() throws IOException { @@ -279,16 +313,10 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsDetail( int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { - final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); - - // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. - // TODO: remove this and only apply adjustments in NetworkStatsService. - stats.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); - - return stats; + return readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); } - @GuardedBy("mPersistSnapshot") + @GuardedBy("sPersistentDataLock") private void requestSwapActiveStatsMapLocked() throws RemoteException { // Ask netd to do a active map stats swap. When the binder call successfully returns, // the system server should be able to safely read and clean the inactive map @@ -303,11 +331,18 @@ public class NetworkStatsFactory { private NetworkStats readNetworkStatsDetailInternal( int limitUid, String[] limitIfaces, int limitTag) throws IOException { - if (USE_NATIVE_PARSING) { - final NetworkStats stats = - new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); - if (mUseBpfStats) { - synchronized (mPersistSnapshot) { + // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other + // code that will acquire other locks within the system server. See b/134244752. + synchronized (sPersistentDataLock) { + // Take a reference. If this gets swapped out, we still have the old reference. + final VpnInfo[] vpnArray = sVpnInfos; + // Take a defensive copy. mPersistSnapshot is mutated in some cases below + final NetworkStats prev = mPersistSnapshot.clone(); + + if (USE_NATIVE_PARSING) { + final NetworkStats stats = + new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); + if (mUseBpfStats) { try { requestSwapActiveStatsMapLocked(); } catch (RemoteException e) { @@ -316,32 +351,66 @@ public class NetworkStatsFactory { // Stats are always read from the inactive map, so they must be read after the // swap if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - null, TAG_ALL, mUseBpfStats) != 0) { + INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); } + + // BPF stats are incremental; fold into mPersistSnapshot. mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); mPersistSnapshot.combineAllValues(stats); - NetworkStats result = mPersistSnapshot.clone(); - result.filter(limitUid, limitIfaces, limitTag); - return result; + } else { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, + INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + if (SANITY_CHECK_NATIVE) { + final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, + UID_ALL, INTERFACES_ALL, TAG_ALL); + assertEquals(javaStats, stats); + } + + mPersistSnapshot = stats; } } else { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, - limitIfaces, limitTag, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - if (SANITY_CHECK_NATIVE) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid, - limitIfaces, limitTag); - assertEquals(javaStats, stats); - } - return stats; + mPersistSnapshot = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL, + TAG_ALL); } - } else { - return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag); + + NetworkStats adjustedStats = adjustForTunAnd464Xlat(mPersistSnapshot, prev, vpnArray); + + // Filter return values + adjustedStats.filter(limitUid, limitIfaces, limitTag); + return adjustedStats; } } + @GuardedBy("sPersistentDataLock") + private NetworkStats adjustForTunAnd464Xlat( + NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) { + // Calculate delta from last snapshot + final NetworkStats delta = uidDetailStats.subtract(previousStats); + + // Apply 464xlat adjustments before VPN adjustments. If VPNs are using v4 on a v6 only + // network, the overhead is their fault. + // No locking here: apply464xlatAdjustments behaves fine with an add-only + // ConcurrentHashMap. + delta.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); + + // Migrate data usage over a VPN to the TUN network. + for (VpnInfo info : vpnArray) { + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + } + + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); + + // Update mTunAnd464xlatAdjustedStats with migrated delta. + mTunAnd464xlatAdjustedStats.combineAllValues(delta); + mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); + + return mTunAnd464xlatAdjustedStats.clone(); + } + /** * Parse and return {@link NetworkStats} with UID-level details. Values are * expected to monotonically increase since device boot. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f9972dd873..6ca3e38d69 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -130,7 +130,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; @@ -266,10 +265,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; - /** Set containing info about active VPNs and their underlying networks. */ - @GuardedBy("mStatsLock") - private VpnInfo[] mVpnInfos = new VpnInfo[0]; - private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -857,7 +852,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdateIfaces( Network[] defaultNetworks, - VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { checkNetworkStackPermission(mContext); @@ -865,7 +859,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); + updateIfaces(defaultNetworks, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1131,13 +1125,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void updateIfaces( Network[] defaultNetworks, - VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - mVpnInfos = vpnArray; mActiveIface = activeIface; updateIfacesLocked(defaultNetworks, networkStates); } finally { @@ -1147,10 +1139,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Inspect all current {@link NetworkState} to derive mapping from {@code - * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} - * are active on a single {@code iface}, they are combined under a single - * {@link NetworkIdentitySet}. + * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link + * NetworkStatsHistory}. When multiple {@link NetworkInfo} are active on a single {@code iface}, + * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { @@ -1276,18 +1267,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + mUidRecorder.recordSnapshotLocked( + uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + mUidTagRecorder.recordSnapshotLocked( + uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // We need to make copies of member fields that are sent to the observer to avoid // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); + new ArrayMap<>(mActiveUidIfaces), null /* vpnArray */, currentTime); } /** @@ -1660,8 +1652,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private NetworkStats getNetworkStatsUidDetail(String[] ifaces) throws RemoteException { - - // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here. final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, ifaces); From f2465f87c20c7618b2727a9e8eab2a4d4559c2ff Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Jun 2019 10:54:38 -0700 Subject: [PATCH 0648/1150] Remove VPN info arrays from NetworkStats(Observer|Recorder) This change removes the now-unused VPN arrays in the network stats observer and recorder classes. These are always null values in every call site. Bug: 113122541 Bug: 120145746 Bug: 129264869 Bug: 134244752 Test: FrameworksNetTest passing Test: Manual tests show data usage fixes maintained. Change-Id: Ieb8645acc400fdaeb0df7092c5369b96f9f35af9 --- .../server/net/NetworkStatsObservers.java | 13 +++++------ .../server/net/NetworkStatsRecorder.java | 22 ++++--------------- .../server/net/NetworkStatsService.java | 14 +++++------- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index d8408730dd..2564daeaa1 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -39,7 +39,6 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import java.util.concurrent.atomic.AtomicInteger; @@ -104,9 +103,9 @@ class NetworkStatsObservers { public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot, ArrayMap activeIfaces, ArrayMap activeUidIfaces, - VpnInfo[] vpnArray, long currentTime) { + long currentTime) { StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces, - activeUidIfaces, vpnArray, currentTime); + activeUidIfaces, currentTime); getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext)); } @@ -354,7 +353,7 @@ class NetworkStatsObservers { // thread will update it. We pass a null VPN array because usage is aggregated by uid // for this snapshot, so VPN traffic can't be reattributed to responsible apps. mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, - null /* vpnArray */, statsContext.mCurrentTime); + statsContext.mCurrentTime); } /** @@ -396,7 +395,7 @@ class NetworkStatsObservers { // thread will update it. We pass the VPN info so VPN traffic is reattributed to // responsible apps. mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, - statsContext.mVpnArray, statsContext.mCurrentTime); + statsContext.mCurrentTime); } /** @@ -427,18 +426,16 @@ class NetworkStatsObservers { NetworkStats mUidSnapshot; ArrayMap mActiveIfaces; ArrayMap mActiveUidIfaces; - VpnInfo[] mVpnArray; long mCurrentTime; StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot, ArrayMap activeIfaces, ArrayMap activeUidIfaces, - VpnInfo[] vpnArray, long currentTime) { + long currentTime) { mXtSnapshot = xtSnapshot; mUidSnapshot = uidSnapshot; mActiveIfaces = activeIfaces; mActiveUidIfaces = activeUidIfaces; - mVpnArray = vpnArray; mCurrentTime = currentTime; } } diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index bdff50053f..06ec341d9e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -23,7 +23,6 @@ import static android.text.format.DateUtils.YEAR_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; -import android.annotation.Nullable; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; @@ -37,7 +36,6 @@ import android.util.MathUtils; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -202,18 +200,12 @@ public class NetworkStatsRecorder { } /** - * Record any delta that occurred since last {@link NetworkStats} snapshot, - * using the given {@link Map} to identify network interfaces. First - * snapshot is considered bootstrap, and is not counted as delta. - * - * @param vpnArray Optional info about the currently active VPN, if any. This is used to - * redistribute traffic from the VPN app to the underlying responsible apps. - * This should always be set to null if the provided snapshot is aggregated - * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state. + * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given + * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is + * not counted as delta. */ public void recordSnapshotLocked(NetworkStats snapshot, - Map ifaceIdent, @Nullable VpnInfo[] vpnArray, - long currentTimeMillis) { + Map ifaceIdent, long currentTimeMillis) { final HashSet unknownIfaces = Sets.newHashSet(); // skip recording when snapshot missing @@ -232,12 +224,6 @@ public class NetworkStatsRecorder { final long end = currentTimeMillis; final long start = end - delta.getElapsedRealtime(); - if (vpnArray != null) { - for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); - } - } - NetworkStats.Entry entry = null; for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 6ca3e38d69..2fc78d6f47 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1258,28 +1258,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); - mDevRecorder.recordSnapshotLocked( - devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); - mXtRecorder.recordSnapshotLocked( - xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked( - uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked( - uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // We need to make copies of member fields that are sent to the observer to avoid // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), null /* vpnArray */, currentTime); + new ArrayMap<>(mActiveUidIfaces), currentTime); } /** From 82a1e493b112ea64588a1ce5bca349f3386348b1 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Thu, 30 May 2019 17:11:14 +0900 Subject: [PATCH 0649/1150] Factorize custom asserts. Also a few utilities that were in the way, and some opportunistic cleanups. Test: FrameworksNetTest NetworkStackTest Change-Id: I385070e2044fd967cb18f1ffea9a86a4627b742e --- core/java/android/net/IpSecConfig.java | 41 ++++++++++++----------- core/java/android/net/IpSecTransform.java | 14 ++++---- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java index 3552655983..43c8ff2335 100644 --- a/core/java/android/net/IpSecConfig.java +++ b/core/java/android/net/IpSecConfig.java @@ -15,6 +15,7 @@ */ package android.net; +import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -333,25 +334,25 @@ public final class IpSecConfig implements Parcelable { } }; - @VisibleForTesting - /** Equals method used for testing */ - public static boolean equals(IpSecConfig lhs, IpSecConfig rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return (lhs.mMode == rhs.mMode - && lhs.mSourceAddress.equals(rhs.mSourceAddress) - && lhs.mDestinationAddress.equals(rhs.mDestinationAddress) - && ((lhs.mNetwork != null && lhs.mNetwork.equals(rhs.mNetwork)) - || (lhs.mNetwork == rhs.mNetwork)) - && lhs.mEncapType == rhs.mEncapType - && lhs.mEncapSocketResourceId == rhs.mEncapSocketResourceId - && lhs.mEncapRemotePort == rhs.mEncapRemotePort - && lhs.mNattKeepaliveInterval == rhs.mNattKeepaliveInterval - && lhs.mSpiResourceId == rhs.mSpiResourceId - && IpSecAlgorithm.equals(lhs.mEncryption, rhs.mEncryption) - && IpSecAlgorithm.equals(lhs.mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) - && IpSecAlgorithm.equals(lhs.mAuthentication, rhs.mAuthentication) - && lhs.mMarkValue == rhs.mMarkValue - && lhs.mMarkMask == rhs.mMarkMask - && lhs.mXfrmInterfaceId == rhs.mXfrmInterfaceId); + @Override + public boolean equals(@Nullable Object other) { + if (!(other instanceof IpSecConfig)) return false; + final IpSecConfig rhs = (IpSecConfig) other; + return (mMode == rhs.mMode + && mSourceAddress.equals(rhs.mSourceAddress) + && mDestinationAddress.equals(rhs.mDestinationAddress) + && ((mNetwork != null && mNetwork.equals(rhs.mNetwork)) + || (mNetwork == rhs.mNetwork)) + && mEncapType == rhs.mEncapType + && mEncapSocketResourceId == rhs.mEncapSocketResourceId + && mEncapRemotePort == rhs.mEncapRemotePort + && mNattKeepaliveInterval == rhs.mNattKeepaliveInterval + && mSpiResourceId == rhs.mSpiResourceId + && IpSecAlgorithm.equals(mEncryption, rhs.mEncryption) + && IpSecAlgorithm.equals(mAuthenticatedEncryption, rhs.mAuthenticatedEncryption) + && IpSecAlgorithm.equals(mAuthentication, rhs.mAuthentication) + && mMarkValue == rhs.mMarkValue + && mMarkMask == rhs.mMarkMask + && mXfrmInterfaceId == rhs.mXfrmInterfaceId); } } diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index a12df28eac..93ae4f1188 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -148,15 +148,13 @@ public final class IpSecTransform implements AutoCloseable { } /** - * Equals method used for testing - * - * @hide + * Standard equals. */ - @VisibleForTesting - public static boolean equals(IpSecTransform lhs, IpSecTransform rhs) { - if (lhs == null || rhs == null) return (lhs == rhs); - return IpSecConfig.equals(lhs.getConfig(), rhs.getConfig()) - && lhs.mResourceId == rhs.mResourceId; + public boolean equals(Object other) { + if (this == other) return true; + if (!(other instanceof IpSecTransform)) return false; + final IpSecTransform rhs = (IpSecTransform) other; + return getConfig().equals(rhs.getConfig()) && mResourceId == rhs.mResourceId; } /** From 2cb570ff3651d721d7e8d50504759f04923d5767 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 14 Jun 2019 11:54:49 -0700 Subject: [PATCH 0650/1150] Inline readNetworkStatsDetailInternal, make mUseBpfStats final This change inlines the logic from readNetworkStatsDetailInternal, and reduces reundant checks in mUseBpfStats Bug: 113122541 Test: atest FrameworksNetTests run, passing Change-Id: If2ef8d8f038f32c8cf974aa02cfc1dc7e44dbad3 --- .../server/net/NetworkStatsFactory.java | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 2d3c66d68f..7687718b06 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -68,7 +68,7 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; - private boolean mUseBpfStats; + private final boolean mUseBpfStats; private INetd mNetdService; @@ -302,6 +302,17 @@ public class NetworkStatsFactory { return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); } + @GuardedBy("sPersistentDataLock") + private void requestSwapActiveStatsMapLocked() throws RemoteException { + // Ask netd to do a active map stats swap. When the binder call successfully returns, + // the system server should be able to safely read and clean the inactive map + // without race problem. + if (mNetdService == null) { + mNetdService = NetdService.getInstance(); + } + mNetdService.trafficSwapActiveStatsMap(); + } + /** * Reads the detailed UID stats based on the provided parameters * @@ -312,24 +323,6 @@ public class NetworkStatsFactory { * @return the NetworkStats instance containing network statistics at the present time. */ public NetworkStats readNetworkStatsDetail( - int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { - return readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); - } - - @GuardedBy("sPersistentDataLock") - private void requestSwapActiveStatsMapLocked() throws RemoteException { - // Ask netd to do a active map stats swap. When the binder call successfully returns, - // the system server should be able to safely read and clean the inactive map - // without race problem. - if (mUseBpfStats) { - if (mNetdService == null) { - mNetdService = NetdService.getInstance(); - } - mNetdService.trafficSwapActiveStatsMap(); - } - } - - private NetworkStats readNetworkStatsDetailInternal( int limitUid, String[] limitIfaces, int limitTag) throws IOException { // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other // code that will acquire other locks within the system server. See b/134244752. From 43fc79efce5f1ebf84ca7fc757874a9532a68ef3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 Jun 2019 17:46:15 +0000 Subject: [PATCH 0651/1150] Revert "Revert "Take all VPN underlying networks into account when migrating traffic for"" This reverts commit 48608ad513c64a1f7d5436b5e013d16f5319e583. Reason for revert: Fix available for deadlocks. Bug: 113122541 Bug: 134244752 Merged-In: Ib65214598837289bd39dbf040b56ab7835f893ba Change-Id: Ia90bf2c72ef686e80800d113d03548e0efcadb66 (cherry picked from commit 2cc14c8bed81164b2c7747f715ed57aa40dc84bc) --- core/java/android/net/NetworkStats.java | 330 +++++++++++------- .../server/net/NetworkStatsRecorder.java | 6 +- 2 files changed, 214 insertions(+), 122 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index e892b650bf..f09f2ee223 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,6 +18,7 @@ package android.net; import static android.os.Process.CLAT_UID; +import android.annotation.NonNull; import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; @@ -1175,133 +1176,217 @@ public class NetworkStats implements Parcelable { /** * VPN accounting. Move some VPN's underlying traffic to other UIDs that use tun0 iface. * - * This method should only be called on delta NetworkStats. Do not call this method on a - * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may - * change over time. + *

            This method should only be called on delta NetworkStats. Do not call this method on a + * snapshot {@link NetworkStats} object because the tunUid and/or the underlyingIface may change + * over time. * - * This method performs adjustments for one active VPN package and one VPN iface at a time. - * - * It is possible for the VPN software to use multiple underlying networks. This method - * only migrates traffic for the primary underlying network. + *

            This method performs adjustments for one active VPN package and one VPN iface at a time. * * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel - * @param underlyingIface the primary underlying network iface used by the VPN application - * @return true if it successfully adjusts the accounting for VPN, false otherwise + * @param underlyingIfaces underlying network ifaces used by the VPN application */ - public boolean migrateTun(int tunUid, String tunIface, String underlyingIface) { - Entry tunIfaceTotal = new Entry(); - Entry underlyingIfaceTotal = new Entry(); + public void migrateTun(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces) { + // Combined usage by all apps using VPN. + final Entry tunIfaceTotal = new Entry(); + // Usage by VPN, grouped by its {@code underlyingIfaces}. + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + // Usage by VPN, summed across all its {@code underlyingIfaces}. + final Entry underlyingIfacesTotal = new Entry(); - tunAdjustmentInit(tunUid, tunIface, underlyingIface, tunIfaceTotal, underlyingIfaceTotal); + for (int i = 0; i < perInterfaceTotal.length; i++) { + perInterfaceTotal[i] = new Entry(); + } - // If tunIface < underlyingIface, it leaves the overhead traffic in the VPN app. - // If tunIface > underlyingIface, the VPN app doesn't get credit for data compression. + tunAdjustmentInit(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, perInterfaceTotal, + underlyingIfacesTotal); + + // If tunIface < underlyingIfacesTotal, it leaves the overhead traffic in the VPN app. + // If tunIface > underlyingIfacesTotal, the VPN app doesn't get credit for data compression. // Negative stats should be avoided. - Entry pool = tunGetPool(tunIfaceTotal, underlyingIfaceTotal); - if (pool.isEmpty()) { - return true; - } - Entry moved = - addTrafficToApplications(tunUid, tunIface, underlyingIface, tunIfaceTotal, pool); - deductTrafficFromVpnApp(tunUid, underlyingIface, moved); - - if (!moved.isEmpty()) { - Slog.wtf(TAG, "Failed to deduct underlying network traffic from VPN package. Moved=" - + moved); - return false; - } - return true; + final Entry[] moved = + addTrafficToApplications(tunUid, tunIface, underlyingIfaces, tunIfaceTotal, + perInterfaceTotal, underlyingIfacesTotal); + deductTrafficFromVpnApp(tunUid, underlyingIfaces, moved); } /** * Initializes the data used by the migrateTun() method. * - * This is the first pass iteration which does the following work: - * (1) Adds up all the traffic through the tunUid's underlyingIface - * (both foreground and background). - * (2) Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *

            This is the first pass iteration which does the following work: + * + *

              + *
            • Adds up all the traffic through the tunUid's underlyingIfaces (both foreground and + * background). + *
            • Adds up all the traffic through tun0 excluding traffic from the vpn app itself. + *
            + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal output parameter; combined data usage by all apps using VPN + * @param perInterfaceTotal output parameter; data usage by VPN app, grouped by its {@code + * underlyingIfaces} + * @param underlyingIfacesTotal output parameter; data usage by VPN, summed across all of its + * {@code underlyingIfaces} */ - private void tunAdjustmentInit(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry recycle = new Entry(); + private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { getValues(i, recycle); if (recycle.uid == UID_ALL) { throw new IllegalStateException( "Cannot adjust VPN accounting on an iface aggregated NetworkStats."); - } if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { + } + if (recycle.set == SET_DBG_VPN_IN || recycle.set == SET_DBG_VPN_OUT) { throw new IllegalStateException( "Cannot adjust VPN accounting on a NetworkStats containing SET_DBG_VPN_*"); } - - if (recycle.uid == tunUid && recycle.tag == TAG_NONE - && Objects.equals(underlyingIface, recycle.iface)) { - underlyingIfaceTotal.add(recycle); + if (recycle.tag != TAG_NONE) { + // TODO(b/123666283): Take all tags for tunUid into account. + continue; } - if (recycle.uid != tunUid && recycle.tag == TAG_NONE - && Objects.equals(tunIface, recycle.iface)) { + if (recycle.uid == tunUid) { + // Add up traffic through tunUid's underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + perInterfaceTotal[j].add(recycle); + underlyingIfacesTotal.add(recycle); + break; + } + } + } else if (tunIface.equals(recycle.iface)) { // Add up all tunIface traffic excluding traffic from the vpn app itself. tunIfaceTotal.add(recycle); } } } - private static Entry tunGetPool(Entry tunIfaceTotal, Entry underlyingIfaceTotal) { - Entry pool = new Entry(); - pool.rxBytes = Math.min(tunIfaceTotal.rxBytes, underlyingIfaceTotal.rxBytes); - pool.rxPackets = Math.min(tunIfaceTotal.rxPackets, underlyingIfaceTotal.rxPackets); - pool.txBytes = Math.min(tunIfaceTotal.txBytes, underlyingIfaceTotal.txBytes); - pool.txPackets = Math.min(tunIfaceTotal.txPackets, underlyingIfaceTotal.txPackets); - pool.operations = Math.min(tunIfaceTotal.operations, underlyingIfaceTotal.operations); - return pool; - } + /** + * Distributes traffic across apps that are using given {@code tunIface}, and returns the total + * traffic that should be moved off of {@code tunUid} grouped by {@code underlyingIfaces}. + * + * @param tunUid uid of the VPN application + * @param tunIface iface of the vpn tunnel + * @param underlyingIfaces underlying network ifaces used by the VPN application + * @param tunIfaceTotal combined data usage across all apps using {@code tunIface} + * @param perInterfaceTotal data usage by VPN app, grouped by its {@code underlyingIfaces} + * @param underlyingIfacesTotal data usage by VPN, summed across all of its {@code + * underlyingIfaces} + */ + private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, + @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { + // Traffic that should be moved off of each underlying interface for tunUid (see + // deductTrafficFromVpnApp below). + final Entry[] moved = new Entry[underlyingIfaces.length]; + for (int i = 0; i < underlyingIfaces.length; i++) { + moved[i] = new Entry(); + } - private Entry addTrafficToApplications(int tunUid, String tunIface, String underlyingIface, - Entry tunIfaceTotal, Entry pool) { - Entry moved = new Entry(); - Entry tmpEntry = new Entry(); - tmpEntry.iface = underlyingIface; + final Entry tmpEntry = new Entry(); for (int i = 0; i < size; i++) { - // the vpn app is excluded from the redistribution but all moved traffic will be - // deducted from the vpn app (see deductTrafficFromVpnApp below). - if (Objects.equals(iface[i], tunIface) && uid[i] != tunUid) { - if (tunIfaceTotal.rxBytes > 0) { - tmpEntry.rxBytes = pool.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; - } else { - tmpEntry.rxBytes = 0; - } - if (tunIfaceTotal.rxPackets > 0) { - tmpEntry.rxPackets = pool.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; - } else { - tmpEntry.rxPackets = 0; - } - if (tunIfaceTotal.txBytes > 0) { - tmpEntry.txBytes = pool.txBytes * txBytes[i] / tunIfaceTotal.txBytes; - } else { - tmpEntry.txBytes = 0; - } - if (tunIfaceTotal.txPackets > 0) { - tmpEntry.txPackets = pool.txPackets * txPackets[i] / tunIfaceTotal.txPackets; - } else { - tmpEntry.txPackets = 0; - } - if (tunIfaceTotal.operations > 0) { - tmpEntry.operations = - pool.operations * operations[i] / tunIfaceTotal.operations; - } else { - tmpEntry.operations = 0; - } - tmpEntry.uid = uid[i]; - tmpEntry.tag = tag[i]; + if (!Objects.equals(iface[i], tunIface)) { + // Consider only entries that go onto the VPN interface. + continue; + } + if (uid[i] == tunUid) { + // Exclude VPN app from the redistribution, as it can choose to create packet + // streams by writing to itself. + continue; + } + tmpEntry.uid = uid[i]; + tmpEntry.tag = tag[i]; + tmpEntry.metered = metered[i]; + tmpEntry.roaming = roaming[i]; + tmpEntry.defaultNetwork = defaultNetwork[i]; + + // In a first pass, compute each UID's total share of data across all underlyingIfaces. + // This is computed on the basis of the share of each UID's usage over tunIface. + // TODO: Consider refactoring first pass into a separate helper method. + long totalRxBytes = 0; + if (tunIfaceTotal.rxBytes > 0) { + // Note - The multiplication below should not overflow since NetworkStatsService + // processes this every time device has transmitted/received amount equivalent to + // global threshold alert (~ 2MB) across all interfaces. + final long rxBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + // app must not be blamed for more than it consumed on tunIface + totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); + } + long totalRxPackets = 0; + if (tunIfaceTotal.rxPackets > 0) { + final long rxPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); + } + long totalTxBytes = 0; + if (tunIfaceTotal.txBytes > 0) { + final long txBytesAcrossUnderlyingIfaces = + underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); + } + long totalTxPackets = 0; + if (tunIfaceTotal.txPackets > 0) { + final long txPacketsAcrossUnderlyingIfaces = + underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); + } + long totalOperations = 0; + if (tunIfaceTotal.operations > 0) { + final long operationsAcrossUnderlyingIfaces = + underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; + totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); + } + // In a second pass, distribute these values across interfaces in the proportion that + // each interface represents of the total traffic of the underlying interfaces. + for (int j = 0; j < underlyingIfaces.length; j++) { + tmpEntry.iface = underlyingIfaces[j]; + tmpEntry.rxBytes = 0; + // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; - tmpEntry.metered = metered[i]; - tmpEntry.roaming = roaming[i]; - tmpEntry.defaultNetwork = defaultNetwork[i]; + if (underlyingIfacesTotal.rxBytes > 0) { + tmpEntry.rxBytes = + totalRxBytes + * perInterfaceTotal[j].rxBytes + / underlyingIfacesTotal.rxBytes; + } + tmpEntry.rxPackets = 0; + if (underlyingIfacesTotal.rxPackets > 0) { + tmpEntry.rxPackets = + totalRxPackets + * perInterfaceTotal[j].rxPackets + / underlyingIfacesTotal.rxPackets; + } + tmpEntry.txBytes = 0; + if (underlyingIfacesTotal.txBytes > 0) { + tmpEntry.txBytes = + totalTxBytes + * perInterfaceTotal[j].txBytes + / underlyingIfacesTotal.txBytes; + } + tmpEntry.txPackets = 0; + if (underlyingIfacesTotal.txPackets > 0) { + tmpEntry.txPackets = + totalTxPackets + * perInterfaceTotal[j].txPackets + / underlyingIfacesTotal.txPackets; + } + tmpEntry.operations = 0; + if (underlyingIfacesTotal.operations > 0) { + tmpEntry.operations = + totalOperations + * perInterfaceTotal[j].operations + / underlyingIfacesTotal.operations; + } + combineValues(tmpEntry); if (tag[i] == TAG_NONE) { - moved.add(tmpEntry); + moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; combineValues(tmpEntry); @@ -1311,38 +1396,45 @@ public class NetworkStats implements Parcelable { return moved; } - private void deductTrafficFromVpnApp(int tunUid, String underlyingIface, Entry moved) { - // Add debug info - moved.uid = tunUid; - moved.set = SET_DBG_VPN_OUT; - moved.tag = TAG_NONE; - moved.iface = underlyingIface; - moved.metered = METERED_ALL; - moved.roaming = ROAMING_ALL; - moved.defaultNetwork = DEFAULT_NETWORK_ALL; - combineValues(moved); + private void deductTrafficFromVpnApp( + int tunUid, + @NonNull String[] underlyingIfaces, + @NonNull Entry[] moved) { + for (int i = 0; i < underlyingIfaces.length; i++) { + // Add debug info + moved[i].uid = tunUid; + moved[i].set = SET_DBG_VPN_OUT; + moved[i].tag = TAG_NONE; + moved[i].iface = underlyingIfaces[i]; + moved[i].metered = METERED_ALL; + moved[i].roaming = ROAMING_ALL; + moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; + combineValues(moved[i]); - // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than - // the TAG_NONE traffic. - // - // Relies on the fact that the underlying traffic only has state ROAMING_NO and METERED_NO, - // which should be the case as it comes directly from the /proc file. We only blend in the - // roaming data after applying these adjustments, by checking the NetworkIdentity of the - // underlying iface. - int idxVpnBackground = findIndex(underlyingIface, tunUid, SET_DEFAULT, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnBackground != -1) { - tunSubtract(idxVpnBackground, this, moved); - } + // Caveat: if the vpn software uses tag, the total tagged traffic may be greater than + // the TAG_NONE traffic. + // + // Relies on the fact that the underlying traffic only has state ROAMING_NO and + // METERED_NO, which should be the case as it comes directly from the /proc file. + // We only blend in the roaming data after applying these adjustments, by checking the + // NetworkIdentity of the underlying iface. + final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnBackground != -1) { + // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed + // from foreground usage. + tunSubtract(idxVpnBackground, this, moved[i]); + } - int idxVpnForeground = findIndex(underlyingIface, tunUid, SET_FOREGROUND, TAG_NONE, - METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); - if (idxVpnForeground != -1) { - tunSubtract(idxVpnForeground, this, moved); + final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); + if (idxVpnForeground != -1) { + tunSubtract(idxVpnForeground, this, moved[i]); + } } } - private static void tunSubtract(int i, NetworkStats left, Entry right) { + private static void tunSubtract(int i, @NonNull NetworkStats left, @NonNull Entry right) { long rxBytes = Math.min(left.rxBytes[i], right.rxBytes); left.rxBytes[i] -= rxBytes; right.rxBytes -= rxBytes; diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a2e7e0cae9..bdff50053f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -41,10 +41,10 @@ import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoUtils; - import com.google.android.collect.Sets; +import libcore.io.IoUtils; + import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; @@ -234,7 +234,7 @@ public class NetworkStatsRecorder { if (vpnArray != null) { for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.primaryUnderlyingIface); + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); } } From a2a478128ef90407a5a94c2826222a53c01839cc Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 11 Jun 2019 18:21:30 -0700 Subject: [PATCH 0652/1150] Remove unused lastStats parameter This change removes an unused parameter that is always null in getNetworkStatsUidDetail Bug: 113122541 Bug: 134244752 Test: FrameworksNetTest passing Merged-In: I995b108ef30e1fbd6190131ed4db40a3d9327eb5 Change-Id: I575a7e4fa145f2c93537f33a2bfe952aeafd0e69 (cherry picked from commit d9d6958e06b75b295e8a6e5fd21d181783c7ec9d) --- .../server/net/NetworkStatsFactory.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 69efd02dea..c118bda88c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -16,6 +16,7 @@ package com.android.server.net; +import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.SET_ALL; import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; @@ -264,13 +265,21 @@ public class NetworkStatsFactory { } public NetworkStats readNetworkStatsDetail() throws IOException { - return readNetworkStatsDetail(UID_ALL, null, TAG_ALL, null); + return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); } - public NetworkStats readNetworkStatsDetail(int limitUid, String[] limitIfaces, int limitTag, - NetworkStats lastStats) throws IOException { - final NetworkStats stats = - readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag, lastStats); + /** + * Reads the detailed UID stats based on the provided parameters + * + * @param limitUid the UID to limit this query to + * @param limitIfaces the interfaces to limit this query to. Use {@link + * NetworkStats.INTERFACES_ALL} to select all interfaces + * @param limitTag the tags to limit this query to + * @return the NetworkStats instance containing network statistics at the present time. + */ + public NetworkStats readNetworkStatsDetail( + int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { + final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. // TODO: remove this and only apply adjustments in NetworkStatsService. @@ -292,17 +301,11 @@ public class NetworkStatsFactory { } } - // TODO: delete the lastStats parameter - private NetworkStats readNetworkStatsDetailInternal(int limitUid, String[] limitIfaces, - int limitTag, NetworkStats lastStats) throws IOException { + private NetworkStats readNetworkStatsDetailInternal( + int limitUid, String[] limitIfaces, int limitTag) throws IOException { if (USE_NATIVE_PARSING) { - final NetworkStats stats; - if (lastStats != null) { - stats = lastStats; - stats.setElapsedRealtime(SystemClock.elapsedRealtime()); - } else { - stats = new NetworkStats(SystemClock.elapsedRealtime(), -1); - } + final NetworkStats stats = + new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); if (mUseBpfStats) { synchronized (mPersistSnapshot) { try { From b0a112857aa259909b7d15fa3233c1df2b4cb5ce Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 12 Jun 2019 17:46:31 +0000 Subject: [PATCH 0653/1150] NetworkStatsFactory: Take VPNs into account for network/battery stats This change fixes detailed UID stats to ensure network and battery stats both take VPNs into account. NetworkStatsFactory is being made aware of VPNs enabled, and the full set of underlying networks present. Since traffic can only be migrated over a NetworkStats delta, NSF maintains a NetworkStats snapshot across all UIDs/ifaces/tags. This snapshot gets updated whenever NSF records a new snapshot (based on various hooks such as VPN updating its underlying networks, network getting lost, etc.), or NetworkStatsService's getDetailedUidStats() method being called. This change widens the scope of the existing mPersistentSnapshot lock, renaming it to mPersistentDataLock, and ensures that TUN migrations are not done in parallel. Additionally, mVpnInfos is updated via pointer-swapping, to reduce the scope of the mPersistentDataLock. The safety of this change is predicated on: 1. NetworkStatsFactory lock not held, so services cannot deadlock through the cyclical lock. 2. The broadening of the scope of the lock in NetworkStatsFactory has no threading implications, as it is always the last (leaf node) lock held, and therefore is impossible to have lock inversion. Additionally, to ensure VPNs work with 464xlat, the VPN info passed to the NetworkStatsFactory includes all underlying interfaces, instead of only passing the first one. This (partially) re-applies changes from: aosp/972848: Add one more test for VPN usage stats. aosp/972847: Addressing comments for http://ag/7700679. aosp/885338: NetworkStatsService: Fix getDetailedUidStats to take VPNs into account. Co-developed with: Varun Anand Bug: 113122541 Bug: 120145746 Bug: 129264869 Bug: 134244752 Test: FrameworksNetTest passing Test: Manual tests show data usage fixes maintained. Merged-In: I6466ec1411fc5ed6954125d27d353b6cd1be719e Change-Id: Id45ae956ad7165be346ecc010e17d260563ac1c0 (cherry picked from commit 7d5e62485b2025231a206d1833f14019a38f1bbf) --- .../android/net/INetworkStatsService.aidl | 1 - core/java/android/net/NetworkStats.java | 44 ++++-- .../server/net/NetworkStatsFactory.java | 135 +++++++++++++----- .../server/net/NetworkStatsService.java | 28 ++-- 4 files changed, 140 insertions(+), 68 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 41efc50408..e5f3d26667 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -66,7 +66,6 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces( in Network[] defaultNetworks, - in VpnInfo[] vpnArray, in NetworkState[] networkStates, in String activeIface); /** Force update of statistics. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index f09f2ee223..6c7aa1379f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -23,7 +23,6 @@ import android.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; -import android.util.Slog; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; @@ -37,6 +36,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.Map; import java.util.Objects; +import java.util.function.Predicate; /** * Collection of active network statistics. Can contain summary details across @@ -994,23 +994,33 @@ public class NetworkStats implements Parcelable { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { return; } + filter(e -> (limitUid == UID_ALL || limitUid == e.uid) + && (limitTag == TAG_ALL || limitTag == e.tag) + && (limitIfaces == INTERFACES_ALL + || ArrayUtils.contains(limitIfaces, e.iface))); + } + /** + * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. + * + *

            This mutates the original structure in place. + */ + public void filterDebugEntries() { + filter(e -> e.set < SET_DEBUG_START); + } + + private void filter(Predicate predicate) { Entry entry = new Entry(); int nextOutputEntry = 0; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - final boolean matches = - (limitUid == UID_ALL || limitUid == entry.uid) - && (limitTag == TAG_ALL || limitTag == entry.tag) - && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, entry.iface)); - - if (matches) { - setValues(nextOutputEntry, entry); + if (predicate.test(entry)) { + if (nextOutputEntry != i) { + setValues(nextOutputEntry, entry); + } nextOutputEntry++; } } - size = nextOutputEntry; } @@ -1289,7 +1299,8 @@ public class NetworkStats implements Parcelable { } final Entry tmpEntry = new Entry(); - for (int i = 0; i < size; i++) { + final int origSize = size; + for (int i = 0; i < origSize; i++) { if (!Objects.equals(iface[i], tunIface)) { // Consider only entries that go onto the VPN interface. continue; @@ -1305,8 +1316,9 @@ public class NetworkStats implements Parcelable { tmpEntry.roaming = roaming[i]; tmpEntry.defaultNetwork = defaultNetwork[i]; - // In a first pass, compute each UID's total share of data across all underlyingIfaces. - // This is computed on the basis of the share of each UID's usage over tunIface. + // In a first pass, compute this entry's total share of data across all + // underlyingIfaces. This is computed on the basis of the share of this entry's usage + // over tunIface. // TODO: Consider refactoring first pass into a separate helper method. long totalRxBytes = 0; if (tunIfaceTotal.rxBytes > 0) { @@ -1383,9 +1395,11 @@ public class NetworkStats implements Parcelable { * perInterfaceTotal[j].operations / underlyingIfacesTotal.operations; } - + // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying + // interface. Add that data usage to this object. combineValues(tmpEntry); if (tag[i] == TAG_NONE) { + // Add the migrated data to moved so it is deducted from the VPN app later. moved[j].add(tmpEntry); // Add debug info tmpEntry.set = SET_DBG_VPN_IN; @@ -1401,8 +1415,8 @@ public class NetworkStats implements Parcelable { @NonNull String[] underlyingIfaces, @NonNull Entry[] moved) { for (int i = 0; i < underlyingIfaces.length; i++) { - // Add debug info moved[i].uid = tunUid; + // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; moved[i].iface = underlyingIfaces[i]; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index c118bda88c..2d3c66d68f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -34,6 +34,7 @@ import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; @@ -71,11 +72,25 @@ public class NetworkStatsFactory { private INetd mNetdService; - // A persistent Snapshot since device start for eBPF stats - @GuardedBy("mPersistSnapshot") - private final NetworkStats mPersistSnapshot; + /** + * Guards persistent data access in this class + * + *

            In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out + * to other code that will acquire other locks within the system server. See b/134244752. + */ + private static final Object sPersistentDataLock = new Object(); + + /** Set containing info about active VPNs and their underlying networks. */ + private static volatile VpnInfo[] sVpnInfos = new VpnInfo[0]; + + // A persistent snapshot of cumulative stats since device start + @GuardedBy("sPersistentDataLock") + private NetworkStats mPersistSnapshot; + + // The persistent snapshot of tun and 464xlat adjusted stats since device start + @GuardedBy("sPersistentDataLock") + private NetworkStats mTunAnd464xlatAdjustedStats; - // TODO: only do adjustments in NetworkStatsService and remove this. /** * (Stacked interface) -> (base interface) association for all connected ifaces since boot. * @@ -91,6 +106,24 @@ public class NetworkStatsFactory { } } + /** + * Set active VPN information for data usage migration purposes + * + *

            Traffic on TUN-based VPNs inherently all appear to be originated from the VPN providing + * app's UID. This method is used to support migration of VPN data usage, ensuring data is + * accurately billed to the real owner of the traffic. + * + * @param vpnArray The snapshot of the currently-running VPNs. + */ + public static void updateVpnInfos(VpnInfo[] vpnArray) { + sVpnInfos = vpnArray.clone(); + } + + @VisibleForTesting + public static VpnInfo[] getVpnInfos() { + return sVpnInfos.clone(); + } + /** * Get a set of interfaces containing specified ifaces and stacked interfaces. * @@ -147,6 +180,7 @@ public class NetworkStatsFactory { mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); + mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } public NetworkStats readBpfNetworkStatsDev() throws IOException { @@ -279,16 +313,10 @@ public class NetworkStatsFactory { */ public NetworkStats readNetworkStatsDetail( int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { - final NetworkStats stats = readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); - - // No locking here: apply464xlatAdjustments behaves fine with an add-only ConcurrentHashMap. - // TODO: remove this and only apply adjustments in NetworkStatsService. - stats.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); - - return stats; + return readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); } - @GuardedBy("mPersistSnapshot") + @GuardedBy("sPersistentDataLock") private void requestSwapActiveStatsMapLocked() throws RemoteException { // Ask netd to do a active map stats swap. When the binder call successfully returns, // the system server should be able to safely read and clean the inactive map @@ -303,11 +331,18 @@ public class NetworkStatsFactory { private NetworkStats readNetworkStatsDetailInternal( int limitUid, String[] limitIfaces, int limitTag) throws IOException { - if (USE_NATIVE_PARSING) { - final NetworkStats stats = - new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); - if (mUseBpfStats) { - synchronized (mPersistSnapshot) { + // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other + // code that will acquire other locks within the system server. See b/134244752. + synchronized (sPersistentDataLock) { + // Take a reference. If this gets swapped out, we still have the old reference. + final VpnInfo[] vpnArray = sVpnInfos; + // Take a defensive copy. mPersistSnapshot is mutated in some cases below + final NetworkStats prev = mPersistSnapshot.clone(); + + if (USE_NATIVE_PARSING) { + final NetworkStats stats = + new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); + if (mUseBpfStats) { try { requestSwapActiveStatsMapLocked(); } catch (RemoteException e) { @@ -316,32 +351,66 @@ public class NetworkStatsFactory { // Stats are always read from the inactive map, so they must be read after the // swap if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, - null, TAG_ALL, mUseBpfStats) != 0) { + INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); } + + // BPF stats are incremental; fold into mPersistSnapshot. mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime()); mPersistSnapshot.combineAllValues(stats); - NetworkStats result = mPersistSnapshot.clone(); - result.filter(limitUid, limitIfaces, limitTag); - return result; + } else { + if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, + INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { + throw new IOException("Failed to parse network stats"); + } + if (SANITY_CHECK_NATIVE) { + final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, + UID_ALL, INTERFACES_ALL, TAG_ALL); + assertEquals(javaStats, stats); + } + + mPersistSnapshot = stats; } } else { - if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), limitUid, - limitIfaces, limitTag, mUseBpfStats) != 0) { - throw new IOException("Failed to parse network stats"); - } - if (SANITY_CHECK_NATIVE) { - final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, limitUid, - limitIfaces, limitTag); - assertEquals(javaStats, stats); - } - return stats; + mPersistSnapshot = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL, + TAG_ALL); } - } else { - return javaReadNetworkStatsDetail(mStatsXtUid, limitUid, limitIfaces, limitTag); + + NetworkStats adjustedStats = adjustForTunAnd464Xlat(mPersistSnapshot, prev, vpnArray); + + // Filter return values + adjustedStats.filter(limitUid, limitIfaces, limitTag); + return adjustedStats; } } + @GuardedBy("sPersistentDataLock") + private NetworkStats adjustForTunAnd464Xlat( + NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) { + // Calculate delta from last snapshot + final NetworkStats delta = uidDetailStats.subtract(previousStats); + + // Apply 464xlat adjustments before VPN adjustments. If VPNs are using v4 on a v6 only + // network, the overhead is their fault. + // No locking here: apply464xlatAdjustments behaves fine with an add-only + // ConcurrentHashMap. + delta.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); + + // Migrate data usage over a VPN to the TUN network. + for (VpnInfo info : vpnArray) { + delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + } + + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); + + // Update mTunAnd464xlatAdjustedStats with migrated delta. + mTunAnd464xlatAdjustedStats.combineAllValues(delta); + mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); + + return mTunAnd464xlatAdjustedStats.clone(); + } + /** * Parse and return {@link NetworkStats} with UID-level details. Values are * expected to monotonically increase since device boot. diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f34ace55a7..34ce8199a6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -131,7 +131,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; @@ -267,10 +266,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; - /** Set containing info about active VPNs and their underlying networks. */ - @GuardedBy("mStatsLock") - private VpnInfo[] mVpnInfos = new VpnInfo[0]; - private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -864,7 +859,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdateIfaces( Network[] defaultNetworks, - VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { checkNetworkStackPermission(mContext); @@ -872,7 +866,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); + updateIfaces(defaultNetworks, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1138,13 +1132,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void updateIfaces( Network[] defaultNetworks, - VpnInfo[] vpnArray, NetworkState[] networkStates, String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - mVpnInfos = vpnArray; mActiveIface = activeIface; updateIfacesLocked(defaultNetworks, networkStates); } finally { @@ -1154,10 +1146,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Inspect all current {@link NetworkState} to derive mapping from {@code - * iface} to {@link NetworkStatsHistory}. When multiple {@link NetworkInfo} - * are active on a single {@code iface}, they are combined under a single - * {@link NetworkIdentitySet}. + * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link + * NetworkStatsHistory}. When multiple {@link NetworkInfo} are active on a single {@code iface}, + * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { @@ -1283,18 +1274,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + mUidRecorder.recordSnapshotLocked( + uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); + mUidTagRecorder.recordSnapshotLocked( + uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // We need to make copies of member fields that are sent to the observer to avoid // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), vpnArray, currentTime); + new ArrayMap<>(mActiveUidIfaces), null /* vpnArray */, currentTime); } /** @@ -1667,8 +1659,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private NetworkStats getNetworkStatsUidDetail(String[] ifaces) throws RemoteException { - - // TODO: remove 464xlat adjustments from NetworkStatsFactory and apply all at once here. final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, ifaces); From 6cdb7a879060cdb7df1ef25c8ddcbb34e811bfd8 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 13 Jun 2019 10:54:38 -0700 Subject: [PATCH 0654/1150] Remove VPN info arrays from NetworkStats(Observer|Recorder) This change removes the now-unused VPN arrays in the network stats observer and recorder classes. These are always null values in every call site. Bug: 113122541 Bug: 120145746 Bug: 129264869 Bug: 134244752 Test: FrameworksNetTest passing Test: Manual tests show data usage fixes maintained. Merged-In: Ieb8645acc400fdaeb0df7092c5369b96f9f35af9 Change-Id: I66f263d7e12bce7668901306c0c2ecdda634abaf (cherry picked from commit f2465f87c20c7618b2727a9e8eab2a4d4559c2ff) --- .../server/net/NetworkStatsObservers.java | 13 +++++------ .../server/net/NetworkStatsRecorder.java | 22 ++++--------------- .../server/net/NetworkStatsService.java | 14 +++++------- 3 files changed, 14 insertions(+), 35 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/services/core/java/com/android/server/net/NetworkStatsObservers.java index d8408730dd..2564daeaa1 100644 --- a/services/core/java/com/android/server/net/NetworkStatsObservers.java +++ b/services/core/java/com/android/server/net/NetworkStatsObservers.java @@ -39,7 +39,6 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import java.util.concurrent.atomic.AtomicInteger; @@ -104,9 +103,9 @@ class NetworkStatsObservers { public void updateStats(NetworkStats xtSnapshot, NetworkStats uidSnapshot, ArrayMap activeIfaces, ArrayMap activeUidIfaces, - VpnInfo[] vpnArray, long currentTime) { + long currentTime) { StatsContext statsContext = new StatsContext(xtSnapshot, uidSnapshot, activeIfaces, - activeUidIfaces, vpnArray, currentTime); + activeUidIfaces, currentTime); getHandler().sendMessage(mHandler.obtainMessage(MSG_UPDATE_STATS, statsContext)); } @@ -354,7 +353,7 @@ class NetworkStatsObservers { // thread will update it. We pass a null VPN array because usage is aggregated by uid // for this snapshot, so VPN traffic can't be reattributed to responsible apps. mRecorder.recordSnapshotLocked(statsContext.mXtSnapshot, statsContext.mActiveIfaces, - null /* vpnArray */, statsContext.mCurrentTime); + statsContext.mCurrentTime); } /** @@ -396,7 +395,7 @@ class NetworkStatsObservers { // thread will update it. We pass the VPN info so VPN traffic is reattributed to // responsible apps. mRecorder.recordSnapshotLocked(statsContext.mUidSnapshot, statsContext.mActiveUidIfaces, - statsContext.mVpnArray, statsContext.mCurrentTime); + statsContext.mCurrentTime); } /** @@ -427,18 +426,16 @@ class NetworkStatsObservers { NetworkStats mUidSnapshot; ArrayMap mActiveIfaces; ArrayMap mActiveUidIfaces; - VpnInfo[] mVpnArray; long mCurrentTime; StatsContext(NetworkStats xtSnapshot, NetworkStats uidSnapshot, ArrayMap activeIfaces, ArrayMap activeUidIfaces, - VpnInfo[] vpnArray, long currentTime) { + long currentTime) { mXtSnapshot = xtSnapshot; mUidSnapshot = uidSnapshot; mActiveIfaces = activeIfaces; mActiveUidIfaces = activeUidIfaces; - mVpnArray = vpnArray; mCurrentTime = currentTime; } } diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index bdff50053f..06ec341d9e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -23,7 +23,6 @@ import static android.text.format.DateUtils.YEAR_IN_MILLIS; import static com.android.internal.util.Preconditions.checkNotNull; -import android.annotation.Nullable; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; @@ -37,7 +36,6 @@ import android.util.MathUtils; import android.util.Slog; import android.util.proto.ProtoOutputStream; -import com.android.internal.net.VpnInfo; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -202,18 +200,12 @@ public class NetworkStatsRecorder { } /** - * Record any delta that occurred since last {@link NetworkStats} snapshot, - * using the given {@link Map} to identify network interfaces. First - * snapshot is considered bootstrap, and is not counted as delta. - * - * @param vpnArray Optional info about the currently active VPN, if any. This is used to - * redistribute traffic from the VPN app to the underlying responsible apps. - * This should always be set to null if the provided snapshot is aggregated - * across all UIDs (e.g. contains UID_ALL buckets), regardless of VPN state. + * Record any delta that occurred since last {@link NetworkStats} snapshot, using the given + * {@link Map} to identify network interfaces. First snapshot is considered bootstrap, and is + * not counted as delta. */ public void recordSnapshotLocked(NetworkStats snapshot, - Map ifaceIdent, @Nullable VpnInfo[] vpnArray, - long currentTimeMillis) { + Map ifaceIdent, long currentTimeMillis) { final HashSet unknownIfaces = Sets.newHashSet(); // skip recording when snapshot missing @@ -232,12 +224,6 @@ public class NetworkStatsRecorder { final long end = currentTimeMillis; final long start = end - delta.getElapsedRealtime(); - if (vpnArray != null) { - for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); - } - } - NetworkStats.Entry entry = null; for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 34ce8199a6..42802f6c3c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1265,28 +1265,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); - mDevRecorder.recordSnapshotLocked( - devSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + mDevRecorder.recordSnapshotLocked(devSnapshot, mActiveIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordXt"); - mXtRecorder.recordSnapshotLocked( - xtSnapshot, mActiveIfaces, null /* vpnArray */, currentTime); + mXtRecorder.recordSnapshotLocked(xtSnapshot, mActiveIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); - mUidRecorder.recordSnapshotLocked( - uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); + mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "recordUidTag"); - mUidTagRecorder.recordSnapshotLocked( - uidSnapshot, mActiveUidIfaces, null /* vpnArray */, currentTime); + mUidTagRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); // We need to make copies of member fields that are sent to the observer to avoid // a race condition between the service handler thread and the observer's mStatsObservers.updateStats(xtSnapshot, uidSnapshot, new ArrayMap<>(mActiveIfaces), - new ArrayMap<>(mActiveUidIfaces), null /* vpnArray */, currentTime); + new ArrayMap<>(mActiveUidIfaces), currentTime); } /** From b26dfe9274f2a335ee6e8b1d60c9c16f4eb94a0d Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 20 Jun 2019 14:46:35 -0700 Subject: [PATCH 0655/1150] Inline readNetworkStatsDetailInternal, make mUseBpfStats final This change inlines the logic from readNetworkStatsDetailInternal, and reduces reundant checks in mUseBpfStats Bug: 113122541 Test: atest FrameworksNetTests run, passing Merged-In: If2ef8d8f038f32c8cf974aa02cfc1dc7e44dbad3 Change-Id: If7d41052115ed145da8a610d676f6ed33c8d5e63 (cherry picked from commit 2cb570ff3651d721d7e8d50504759f04923d5767) --- .../server/net/NetworkStatsFactory.java | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 2d3c66d68f..7687718b06 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -68,7 +68,7 @@ public class NetworkStatsFactory { /** Path to {@code /proc/net/xt_qtaguid/stats}. */ private final File mStatsXtUid; - private boolean mUseBpfStats; + private final boolean mUseBpfStats; private INetd mNetdService; @@ -302,6 +302,17 @@ public class NetworkStatsFactory { return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); } + @GuardedBy("sPersistentDataLock") + private void requestSwapActiveStatsMapLocked() throws RemoteException { + // Ask netd to do a active map stats swap. When the binder call successfully returns, + // the system server should be able to safely read and clean the inactive map + // without race problem. + if (mNetdService == null) { + mNetdService = NetdService.getInstance(); + } + mNetdService.trafficSwapActiveStatsMap(); + } + /** * Reads the detailed UID stats based on the provided parameters * @@ -312,24 +323,6 @@ public class NetworkStatsFactory { * @return the NetworkStats instance containing network statistics at the present time. */ public NetworkStats readNetworkStatsDetail( - int limitUid, @Nullable String[] limitIfaces, int limitTag) throws IOException { - return readNetworkStatsDetailInternal(limitUid, limitIfaces, limitTag); - } - - @GuardedBy("sPersistentDataLock") - private void requestSwapActiveStatsMapLocked() throws RemoteException { - // Ask netd to do a active map stats swap. When the binder call successfully returns, - // the system server should be able to safely read and clean the inactive map - // without race problem. - if (mUseBpfStats) { - if (mNetdService == null) { - mNetdService = NetdService.getInstance(); - } - mNetdService.trafficSwapActiveStatsMap(); - } - } - - private NetworkStats readNetworkStatsDetailInternal( int limitUid, String[] limitIfaces, int limitTag) throws IOException { // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other // code that will acquire other locks within the system server. See b/134244752. From 9d2ff01d46ee408086cd8bab9a285158bb3d4e8d Mon Sep 17 00:00:00 2001 From: Hugo Benichi Date: Wed, 15 May 2019 23:38:43 +0900 Subject: [PATCH 0656/1150] NetworkStats: Fix race condition causing system server crashes NetworkStatsService uses an internal boolean to know when it has started for the purpose of preventing access to other internal variables before they are initialized. However that boolean is set to true in systemReady() non-atomically with respect to the initialization of the other variables it guards, which can cause the system server to crash. This patch fixes this concurrency bug by moving setting the internal boolean flag and the variable it guards in one atomic synchronized block. This patch also removes code checking if bandwidth control is enabled, because this is now always true. Bug: 132767673 Test: Compiled. Change-Id: Ia089b5767ce271d669879c975508654d4dd03429 --- .../server/net/NetworkStatsService.java | 62 +++---------------- 1 file changed, 10 insertions(+), 52 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 2fc78d6f47..5505828063 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -373,14 +373,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } public void systemReady() { - mSystemReady = true; - - if (!isBandwidthControlEnabled()) { - Slog.w(TAG, "bandwidth controls disabled, unable to track stats"); - return; - } - synchronized (mStatsLock) { + mSystemReady = true; + // create data recorders along with historical rotators mDevRecorder = buildRecorder(PREFIX_DEV, mSettings.getDevConfig(), false); mXtRecorder = buildRecorder(PREFIX_XT, mSettings.getXtConfig(), false); @@ -426,7 +421,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // ignored; service lives in system_server } - registerPollAlarmLocked(); + // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. + final PendingIntent pollIntent = + PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + + final long currentRealtime = SystemClock.elapsedRealtime(); + mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, + mSettings.getPollInterval(), pollIntent); + registerGlobalAlert(); } @@ -486,23 +488,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - /** - * Clear any existing {@link #ACTION_NETWORK_STATS_POLL} alarms, and - * reschedule based on current {@link NetworkStatsSettings#getPollInterval()}. - */ - private void registerPollAlarmLocked() { - if (mPollIntent != null) { - mAlarmManager.cancel(mPollIntent); - } - - mPollIntent = PendingIntent.getBroadcast( - mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); - - final long currentRealtime = SystemClock.elapsedRealtime(); - mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, - mSettings.getPollInterval(), mPollIntent); - } - /** * Register for a global alert that is delivered through * {@link INetworkManagementEventObserver} once a threshold amount of data @@ -548,8 +533,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { - assertBandwidthControlEnabled(); - final int callingUid = Binder.getCallingUid(); final int usedFlags = isRateLimitedForPoll(callingUid) ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) @@ -742,7 +725,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { assertSystemReady(); - assertBandwidthControlEnabled(); // NOTE: if callers want to get non-augmented data, they should go // through the public API @@ -753,7 +735,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { assertSystemReady(); - assertBandwidthControlEnabled(); final NetworkStatsCollection uidComplete; synchronized (mStatsLock) { @@ -768,7 +749,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (Binder.getCallingUid() != uid) { mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); } - assertBandwidthControlEnabled(); // TODO: switch to data layer stats once kernel exports // for now, read network layer stats and flatten across all ifaces @@ -855,7 +835,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkState[] networkStates, String activeIface) { checkNetworkStackPermission(mContext); - assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { @@ -868,7 +847,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); - assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { @@ -879,8 +857,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private void advisePersistThreshold(long thresholdBytes) { - assertBandwidthControlEnabled(); - // clamp threshold into safe range mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); if (LOGV) { @@ -1739,24 +1715,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void assertBandwidthControlEnabled() { - if (!isBandwidthControlEnabled()) { - throw new IllegalStateException("Bandwidth module disabled"); - } - } - - private boolean isBandwidthControlEnabled() { - final long token = Binder.clearCallingIdentity(); - try { - return mNetworkManager.isBandwidthControlEnabled(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return false; - } finally { - Binder.restoreCallingIdentity(token); - } - } - private class DropBoxNonMonotonicObserver implements NonMonotonicObserver { @Override public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right, From 2d876790ebc48e6470172251802bdf7d50950f75 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 24 Jun 2019 12:42:24 +0900 Subject: [PATCH 0657/1150] Synchronize the NetworkStatsFactory constructor. This ensures the constructor takes the necessary lock before accessing memmber variables. Bug: 113122541 Test: atest FrameworksNetTests Change-Id: Ibd324ed922c738b8d77d4eb74f45b75c6645bdc7 --- .../java/com/android/server/net/NetworkStatsFactory.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 7687718b06..9344ef71c9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -179,8 +179,10 @@ public class NetworkStatsFactory { mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; - mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); - mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); + synchronized (sPersistentDataLock) { + mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); + mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); + } } public NetworkStats readBpfNetworkStatsDev() throws IOException { From e698f37ad27c8157d6e872e03dd8f28a8cf92ae5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 24 Jun 2019 13:28:04 +0900 Subject: [PATCH 0658/1150] Transfer ownership of NetworkStatsFactory to NetworkStatsService. NetworkStatsService is the only consumer of the data coming from NetworkStatsFactory, but the factory itself is instantiated and owned by NetworkManagementService. Move it into NetworkStatsService instead. Test: atest FrameworksNetTests Change-Id: I52df1e545c646927952579da22845a12d1d7563b --- .../server/net/NetworkStatsService.java | 51 +++++++++++++------ 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5505828063..e67b39137a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -180,6 +180,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final Context mContext; private final INetworkManagementService mNetworkManager; + private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; private final TelephonyManager mTeleManager; @@ -329,8 +330,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, wakeLock, getDefaultClock(), TelephonyManager.getDefault(), - new DefaultNetworkStatsSettings(context), new NetworkStatsObservers(), - getDefaultSystemDir(), getDefaultBaseDir()); + new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), + new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); service.registerLocalService(); HandlerThread handlerThread = new HandlerThread(TAG); @@ -347,7 +348,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, - NetworkStatsObservers statsObservers, File systemDir, File baseDir) { + NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, + File baseDir) { mContext = checkNotNull(context, "missing Context"); mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService"); mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager"); @@ -355,6 +357,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSettings = checkNotNull(settings, "missing NetworkStatsSettings"); mTeleManager = checkNotNull(teleManager, "missing TelephonyManager"); mWakeLock = checkNotNull(wakeLock, "missing WakeLock"); + mStatsFactory = checkNotNull(factory, "missing factory"); mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = checkNotNull(systemDir, "missing systemDir"); mBaseDir = checkNotNull(baseDir, "missing baseDir"); @@ -752,14 +755,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO: switch to data layer stats once kernel exports // for now, read network layer stats and flatten across all ifaces - final long token = Binder.clearCallingIdentity(); - final NetworkStats networkLayer; - try { - networkLayer = mNetworkManager.getNetworkStatsUidDetail(uid, - NetworkStats.INTERFACES_ALL); - } finally { - Binder.restoreCallingIdentity(token); - } + final NetworkStats networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); // splice in operation counts networkLayer.spliceOperationsFrom(mUidOperations); @@ -1190,7 +1186,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mobileIfaces.add(stackedIface); } - NetworkStatsFactory.noteStackedIface(stackedIface, baseIface); + mStatsFactory.noteStackedIface(stackedIface, baseIface); } } } @@ -1220,7 +1216,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats xtSnapshot = getNetworkStatsXt(); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); - final NetworkStats devSnapshot = mNetworkManager.getNetworkStatsSummaryDev(); + final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); Trace.traceEnd(TRACE_TAG_NETWORK); // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats @@ -1614,6 +1610,30 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private NetworkStats readNetworkStatsSummaryDev() { + try { + return mStatsFactory.readNetworkStatsSummaryDev(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private NetworkStats readNetworkStatsSummaryXt() { + try { + return mStatsFactory.readNetworkStatsSummaryXt(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + private NetworkStats readNetworkStatsUidDetail(int uid, String[] ifaces, int tag) { + try { + return mStatsFactory.readNetworkStatsDetail(uid, ifaces, tag); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + /** * Return snapshot of current UID statistics, including any * {@link TrafficStats#UID_TETHERING}, video calling data usage, and {@link #mUidOperations} @@ -1624,8 +1644,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private NetworkStats getNetworkStatsUidDetail(String[] ifaces) throws RemoteException { - final NetworkStats uidSnapshot = mNetworkManager.getNetworkStatsUidDetail(UID_ALL, - ifaces); + final NetworkStats uidSnapshot = readNetworkStatsUidDetail(UID_ALL, ifaces, TAG_ALL); // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); @@ -1655,7 +1674,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Return snapshot of current XT statistics with video calling data usage statistics. */ private NetworkStats getNetworkStatsXt() throws RemoteException { - final NetworkStats xtSnapshot = mNetworkManager.getNetworkStatsSummaryXt(); + final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( Context.TELEPHONY_SERVICE); From 0d09928534a3ff7b57828cdb8b2453d28f18fd38 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 24 Jun 2019 13:50:45 +0900 Subject: [PATCH 0659/1150] Remove all static members from NetworkStatsFactory. NetworkStatsFactory is owned by NetworkStatsService, and any accesses to NSF data should go through NSS. Test: atest FrameworksNetTests Change-Id: Idbd0dbbaeb11313f63474e7ec0e01f974349fc89 --- .../android/net/INetworkStatsService.aidl | 3 +- .../server/net/NetworkStatsFactory.java | 49 ++++++++----------- .../server/net/NetworkStatsService.java | 15 ++++-- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index e5f3d26667..9994f9f82b 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -67,7 +67,8 @@ interface INetworkStatsService { void forceUpdateIfaces( in Network[] defaultNetworks, in NetworkState[] networkStates, - in String activeIface); + in String activeIface, + in VpnInfo[] vpnInfos); /** Force update of statistics. */ @UnsupportedAppUsage void forceUpdate(); diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 9344ef71c9..3ca1803262 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -78,17 +78,17 @@ public class NetworkStatsFactory { *

            In order to prevent deadlocks, critical sections protected by this lock SHALL NOT call out * to other code that will acquire other locks within the system server. See b/134244752. */ - private static final Object sPersistentDataLock = new Object(); + private final Object mPersistentDataLock = new Object(); /** Set containing info about active VPNs and their underlying networks. */ - private static volatile VpnInfo[] sVpnInfos = new VpnInfo[0]; + private volatile VpnInfo[] mVpnInfos = new VpnInfo[0]; // A persistent snapshot of cumulative stats since device start - @GuardedBy("sPersistentDataLock") + @GuardedBy("mPersistentDataLock") private NetworkStats mPersistSnapshot; // The persistent snapshot of tun and 464xlat adjusted stats since device start - @GuardedBy("sPersistentDataLock") + @GuardedBy("mPersistentDataLock") private NetworkStats mTunAnd464xlatAdjustedStats; /** @@ -97,12 +97,13 @@ public class NetworkStatsFactory { * Because counters must never roll backwards, once a given interface is stacked on top of an * underlying interface, the stacked interface can never be stacked on top of * another interface. */ - private static final ConcurrentHashMap sStackedIfaces + private final ConcurrentHashMap mStackedIfaces = new ConcurrentHashMap<>(); - public static void noteStackedIface(String stackedIface, String baseIface) { + /** Informs the factory of a new stacked interface. */ + public void noteStackedIface(String stackedIface, String baseIface) { if (stackedIface != null && baseIface != null) { - sStackedIfaces.put(stackedIface, baseIface); + mStackedIfaces.put(stackedIface, baseIface); } } @@ -115,13 +116,8 @@ public class NetworkStatsFactory { * * @param vpnArray The snapshot of the currently-running VPNs. */ - public static void updateVpnInfos(VpnInfo[] vpnArray) { - sVpnInfos = vpnArray.clone(); - } - - @VisibleForTesting - public static VpnInfo[] getVpnInfos() { - return sVpnInfos.clone(); + public void updateVpnInfos(VpnInfo[] vpnArray) { + mVpnInfos = vpnArray.clone(); } /** @@ -132,7 +128,7 @@ public class NetworkStatsFactory { * {@link #noteStackedIface(String, String)}, but only interfaces noted before this method * is called are guaranteed to be included. */ - public static String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { + public String[] augmentWithStackedInterfaces(@Nullable String[] requiredIfaces) { if (requiredIfaces == NetworkStats.INTERFACES_ALL) { return null; } @@ -142,7 +138,7 @@ public class NetworkStatsFactory { // elements as they existed upon construction exactly once, and may // (but are not guaranteed to) reflect any modifications subsequent to construction". // This is enough here. - for (Map.Entry entry : sStackedIfaces.entrySet()) { + for (Map.Entry entry : mStackedIfaces.entrySet()) { if (relatedIfaces.contains(entry.getKey())) { relatedIfaces.add(entry.getValue()); } else if (relatedIfaces.contains(entry.getValue())) { @@ -158,17 +154,12 @@ public class NetworkStatsFactory { * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) */ - public static void apply464xlatAdjustments(NetworkStats baseTraffic, + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, sStackedIfaces, + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, useBpfStats); } - @VisibleForTesting - public static void clearStackedIfaces() { - sStackedIfaces.clear(); - } - public NetworkStatsFactory() { this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists()); } @@ -179,7 +170,7 @@ public class NetworkStatsFactory { mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; - synchronized (sPersistentDataLock) { + synchronized (mPersistentDataLock) { mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } @@ -304,7 +295,7 @@ public class NetworkStatsFactory { return readNetworkStatsDetail(UID_ALL, INTERFACES_ALL, TAG_ALL); } - @GuardedBy("sPersistentDataLock") + @GuardedBy("mPersistentDataLock") private void requestSwapActiveStatsMapLocked() throws RemoteException { // Ask netd to do a active map stats swap. When the binder call successfully returns, // the system server should be able to safely read and clean the inactive map @@ -328,9 +319,9 @@ public class NetworkStatsFactory { int limitUid, String[] limitIfaces, int limitTag) throws IOException { // In order to prevent deadlocks, anything protected by this lock MUST NOT call out to other // code that will acquire other locks within the system server. See b/134244752. - synchronized (sPersistentDataLock) { + synchronized (mPersistentDataLock) { // Take a reference. If this gets swapped out, we still have the old reference. - final VpnInfo[] vpnArray = sVpnInfos; + final VpnInfo[] vpnArray = mVpnInfos; // Take a defensive copy. mPersistSnapshot is mutated in some cases below final NetworkStats prev = mPersistSnapshot.clone(); @@ -379,7 +370,7 @@ public class NetworkStatsFactory { } } - @GuardedBy("sPersistentDataLock") + @GuardedBy("mPersistentDataLock") private NetworkStats adjustForTunAnd464Xlat( NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) { // Calculate delta from last snapshot @@ -389,7 +380,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(sStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e67b39137a..4f4377df09 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -130,6 +130,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; @@ -777,7 +778,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStats getDetailedUidStats(String[] requiredIfaces) { try { final String[] ifacesToQuery = - NetworkStatsFactory.augmentWithStackedInterfaces(requiredIfaces); + mStatsFactory.augmentWithStackedInterfaces(requiredIfaces); return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); @@ -829,7 +830,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void forceUpdateIfaces( Network[] defaultNetworks, NetworkState[] networkStates, - String activeIface) { + String activeIface, + VpnInfo[] vpnInfos) { checkNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); @@ -838,6 +840,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } finally { Binder.restoreCallingIdentity(token); } + + // Update the VPN underlying interfaces only after the poll is made and tun data has been + // migrated. Otherwise the migration would use the new interfaces instead of the ones that + // were current when the polled data was transferred. + mStatsFactory.updateVpnInfos(vpnInfos); } @Override @@ -1649,7 +1656,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, + mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); @@ -1660,7 +1667,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); if (vtStats != null) { vtStats.filter(UID_ALL, ifaces, TAG_ALL); - NetworkStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, + mStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, mUseBpfTrafficStats); uidSnapshot.combineAllValues(vtStats); } From 1c2d5c79e5ccd63ecba008a9bb34bc2262aba521 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 28 Jun 2019 16:47:49 +0800 Subject: [PATCH 0660/1150] Fix mobile data usage didn't get increased for xlat464 traffic Interface stats on stacked interfaces is usually clatd. For xt_qtaguid supported device, the stats is already accounted against its final egress interface by the kernel. Framework side does not need to handle stats on statcked interface at all. However, on devices that support BPF offload, xlat464 packets are seen by the iptables rules as arriving on stack interface only. Thus, add stack interface into accounting is needed. Bug: 136193260 Test: 1. atest FrameworksNetTests 2. atest android.app.usage.cts.NetworkUsageStatsTest 3. manual test on ipv6-only wifi network Change-Id: I8ebbefbe4df00e40f4896a17fa52c8438d41286e --- .../android/server/net/NetworkStatsService.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4f4377df09..90dc700e7d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1180,14 +1180,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // Traffic occurring on stacked interfaces is usually clatd, - // which is already accounted against its final egress interface - // by the kernel. Thus, we only need to collect stacked - // interface stats at the UID level. + // Traffic occurring on stacked interfaces is usually clatd. + // UID stats are always counted on the stacked interface and never + // on the base interface, because the packets on the base interface + // do not actually match application sockets until they are translated. + // + // Interface stats are more complicated. Packets subject to BPF offload + // never appear on the base interface and only appear on the stacked + // interface, so to ensure those packets increment interface stats, interface + // stats from stacked interfaces must be collected. final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { + if (mUseBpfTrafficStats) { + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); + } findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From c873970a8850b8cb981bd4bd93075b59a11dc1dc Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 28 Jun 2019 16:47:49 +0800 Subject: [PATCH 0661/1150] Fix mobile data usage didn't get increased for xlat464 traffic Interface stats on stacked interfaces is usually clatd. For xt_qtaguid supported device, the stats is already accounted against its final egress interface by the kernel. Framework side does not need to handle stats on statcked interface at all. However, on devices that support BPF offload, xlat464 packets are seen by the iptables rules as arriving on stack interface only. Thus, add stack interface into accounting is needed. Bug: 136193260 Test: 1. atest FrameworksNetTests 2. atest android.app.usage.cts.NetworkUsageStatsTest 3. manual test on ipv6-only wifi network Merged-In: I8ebbefbe4df00e40f4896a17fa52c8438d41286e Change-Id: I8ebbefbe4df00e40f4896a17fa52c8438d41286e (cherry-pick from aosp/1009306) --- .../android/server/net/NetworkStatsService.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 42802f6c3c..d1b5534e37 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1208,14 +1208,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // Traffic occurring on stacked interfaces is usually clatd, - // which is already accounted against its final egress interface - // by the kernel. Thus, we only need to collect stacked - // interface stats at the UID level. + // Traffic occurring on stacked interfaces is usually clatd. + // UID stats are always counted on the stacked interface and never + // on the base interface, because the packets on the base interface + // do not actually match application sockets until they are translated. + // + // Interface stats are more complicated. Packets subject to BPF offload + // never appear on the base interface and only appear on the stacked + // interface, so to ensure those packets increment interface stats, interface + // stats from stacked interfaces must be collected. final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { + if (mUseBpfTrafficStats) { + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); + } findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From 7d62dacad0bb324be3bd0ebde8370e3da4672520 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 28 Jun 2019 16:47:49 +0800 Subject: [PATCH 0662/1150] Fix mobile data usage didn't get increased for xlat464 traffic Interface stats on stacked interfaces is usually clatd. For xt_qtaguid supported device, the stats is already accounted against its final egress interface by the kernel. Framework side does not need to handle stats on statcked interface at all. However, on devices that support BPF offload, xlat464 packets are seen by the iptables rules as arriving on stack interface only. Thus, add stack interface into accounting is needed. Bug: 136193260 Test: 1. atest FrameworksNetTests 2. atest android.app.usage.cts.NetworkUsageStatsTest 3. manual test on ipv6-only wifi network Merged-In: I8ebbefbe4df00e40f4896a17fa52c8438d41286e Change-Id: I8ebbefbe4df00e40f4896a17fa52c8438d41286e (cherry-pick from aosp/1009306) (cherry picked from commit feb79bd0d7c5ecc7ac5ba9f54ed2d51ee9fd7e74) --- .../android/server/net/NetworkStatsService.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f34ace55a7..e0692f698b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1217,14 +1217,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // Traffic occurring on stacked interfaces is usually clatd, - // which is already accounted against its final egress interface - // by the kernel. Thus, we only need to collect stacked - // interface stats at the UID level. + // Traffic occurring on stacked interfaces is usually clatd. + // UID stats are always counted on the stacked interface and never + // on the base interface, because the packets on the base interface + // do not actually match application sockets until they are translated. + // + // Interface stats are more complicated. Packets subject to BPF offload + // never appear on the base interface and only appear on the stacked + // interface, so to ensure those packets increment interface stats, interface + // stats from stacked interfaces must be collected. final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { + if (mUseBpfTrafficStats) { + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); + } findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From c42bd04cae6b5b494bdcca490070783749dd8114 Mon Sep 17 00:00:00 2001 From: Malcolm Chen Date: Tue, 2 Jul 2019 22:29:35 -0700 Subject: [PATCH 0663/1150] Use new API to get mergedSubscriberIds based on grouping. In addition, make mMergedSubscriberIds a list to fit usage of multi-SIM devices. Bug: 135105735 Bug: 137137221 Test: manual Change-Id: I364262559789112f35b88f4c298463bf4af2e82a --- core/java/android/net/NetworkTemplate.java | 37 ++++++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index ae421a4991..87c7118c0e 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -48,6 +48,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.List; import java.util.Objects; /** @@ -481,17 +482,39 @@ public class NetworkTemplate implements Parcelable { * For example, given an incoming template matching B, and the currently * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. + * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. */ @UnsupportedAppUsage public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { - if (template.isMatchRuleMobile() && ArrayUtils.contains(merged, template.mSubscriberId)) { - // Requested template subscriber is part of the merge group; return - // a template that matches all merged subscribers. - return new NetworkTemplate(template.mMatchRule, merged[0], merged, - template.mNetworkId); - } else { - return template; + return normalize(template, Arrays.asList(merged)); + } + + /** + * Examine the given template and normalize if it refers to a "merged" + * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * for key purposes, and expand the template to match all other merged + * subscribers. + * + * There can be multiple merged subscriberIds for multi-SIM devices. + * + *

            + * For example, given an incoming template matching B, and the currently + * active merge set [A,B], we'd return a new template that primarily matches + * A, but also matches B. + */ + public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { + if (!template.isMatchRuleMobile()) return template; + + for (String[] merged : mergedList) { + if (ArrayUtils.contains(merged, template.mSubscriberId)) { + // Requested template subscriber is part of the merge group; return + // a template that matches all merged subscribers. + return new NetworkTemplate(template.mMatchRule, merged[0], merged, + template.mNetworkId); + } } + + return template; } @UnsupportedAppUsage From 3f5be3d04a218d40cd2eaeb4803739a1641b2a94 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 13 Jun 2019 16:12:02 +0900 Subject: [PATCH 0664/1150] Extract test utilities for ConnectivityService The utilities help using ConnectivityService in tests, and will be used to write integration tests for ConnectivityService. Test: atest FrameworksNetTests Change-Id: Ie895ad05139cd5768d3d8a9bd5589d72571f47e6 --- services/core/java/com/android/server/IpSecService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index b4e1c32f25..a0946a0d22 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -750,10 +750,10 @@ public class IpSecService extends IIpSecService.Stub { } } - // These values have been reserved in ConnectivityService + // These values have been reserved in NetIdManager @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00; - @VisibleForTesting static final int TUN_INTF_NETID_RANGE = 0x0400; + public static final int TUN_INTF_NETID_RANGE = 0x0400; private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); private int mNextTunnelNetIdIndex = 0; From e0073b10536002306eef2050cf67755a104bc0bb Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 28 Aug 2019 13:01:05 -0700 Subject: [PATCH 0665/1150] Add missing nullability annotations. To prepare for enabling MissingNullability Metalava check this CL works on adding missing nullability issues that metalava flags if we tell it to flag new things since API 29. This is not a complete CL, mostly addresses public api and toString/equals for @SystemApi Exempt-From-Owner-Approval: Large scale nullability clean up Bug: 124515653 Test: make -j checkapi Merged-In: I109260842cfc25f06e40694997fcbb4afa02c867 Change-Id: I109260842cfc25f06e40694997fcbb4afa02c867 --- core/java/android/net/IpSecManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 83813da80c..45d0c7313f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -861,6 +861,7 @@ public final class IpSecManager { return mResourceId; } + @NonNull @Override public String toString() { return new StringBuilder() From 925cff0b81877398764c24e81f3db433b6f055d6 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 28 Aug 2019 13:01:05 -0700 Subject: [PATCH 0666/1150] Add missing nullability annotations. To prepare for enabling MissingNullability Metalava check this CL works on adding missing nullability issues that metalava flags if we tell it to flag new things since API 29. This is not a complete CL, mostly addresses public api and toString/equals for @SystemApi Exempt-From-Owner-Approval: Large scale nullability clean up Bug: 124515653 Test: make -j checkapi Change-Id: I109260842cfc25f06e40694997fcbb4afa02c867 --- core/java/android/net/IpSecManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 83813da80c..45d0c7313f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -861,6 +861,7 @@ public final class IpSecManager { return mResourceId; } + @NonNull @Override public String toString() { return new StringBuilder() From d8d521aeeeb12aec148f58d198ccadaaf7c0ab83 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Wed, 28 Aug 2019 13:01:05 -0700 Subject: [PATCH 0667/1150] Add missing nullability annotations. To prepare for enabling MissingNullability Metalava check this CL works on adding missing nullability issues that metalava flags if we tell it to flag new things since API 29. This is not a complete CL, mostly addresses public api and toString/equals for @SystemApi Exempt-From-Owner-Approval: Large scale nullability clean up Bug: 124515653 Test: make -j checkapi Merged-In: I109260842cfc25f06e40694997fcbb4afa02c867 Change-Id: I109260842cfc25f06e40694997fcbb4afa02c867 --- core/java/android/net/IpSecManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 889e9bc787..2262a04647 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -853,6 +853,7 @@ public final class IpSecManager { return mResourceId; } + @NonNull @Override public String toString() { return new StringBuilder() From 1678614ca751a1574609150901278573fd3824fd Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 3 Oct 2019 11:09:00 -0700 Subject: [PATCH 0668/1150] Use TransformRecord to get SPI instead of SpiRecord IpSecService.applyTunnelModeTransform() currently does not take an SpiRecord instance, yet implicitly requires that the SpiRecord instance is still alive based on the stored SpiRecord resourceId in the TransformRecord's IpSecConfig. This check is unnecessary, as the SpiRecord has been subsumed into the TransformRecord, and the kernel resources are kept alive whether or not the SpiRecord is still held by the user. This allows users of the IpSecManager API to allocate short-lived SPIs during the creation of an IpSecTransform, without having to keep track of both of them (even though the SPI is no longer usable). The TransformRecord.getSpiRecord() call is already used in multiple other places in the same method. Bug: 142072071 Test: New tests added, passing. Change-Id: I1959f3080946267243564459ff4207647922566e --- services/core/java/com/android/server/IpSecService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a629b3fbb8..3964b39970 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1761,7 +1761,7 @@ public class IpSecService extends IIpSecService.Stub { socketRecord = userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); } - SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId()); + SpiRecord spiRecord = transformInfo.getSpiRecord(); int mark = (direction == IpSecManager.DIRECTION_OUT) @@ -1794,7 +1794,7 @@ public class IpSecService extends IIpSecService.Stub { // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, // but want to guarantee outbound packets are sent over the new SA. - spi = transformInfo.getSpiRecord().getSpi(); + spi = spiRecord.getSpi(); } // Always update the policy with the relevant XFRM_IF_ID From 504a98af330ee5a632705ea1822abd579709aac1 Mon Sep 17 00:00:00 2001 From: Joshua Baxter Date: Wed, 6 Nov 2019 00:05:24 +0000 Subject: [PATCH 0669/1150] docs: fix a couple of minor typos test: make ds-docs Change-Id: Ia68f66980e447209efb8102a156f78314c199f56 bug: 36979979 Exempt-From-Owner-Approval: docs-only change --- core/java/android/net/nsd/NsdManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 535bf675cd..64f20b839a 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -49,8 +49,8 @@ import java.util.concurrent.CountDownLatch; * limited to a local network over Multicast DNS. DNS service discovery is described at * http://files.dns-sd.org/draft-cheshire-dnsext-dns-sd.txt * - *

            The API is asynchronous and responses to requests from an application are on listener - * callbacks on a seperate internal thread. + *

            The API is asynchronous, and responses to requests from an application are on listener + * callbacks on a separate internal thread. * *

            There are three main operations the API supports - registration, discovery and resolution. *

            
            From fead53a3a5df976a14a4ae5b6ea2b5c1a021bfde Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Mon, 4 Nov 2019 11:16:45 +0000
            Subject: [PATCH 0670/1150] Add @UnsupportedAppUsage to test apis that are
             known to be used by apps.
            
            go/testapi-enforcement
            
            Bug: 133832325
            Test: m
            Change-Id: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6
            Merged-In: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6
            ---
             core/java/android/app/usage/NetworkStatsManager.java | 1 +
             1 file changed, 1 insertion(+)
            
            diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
            index 8e40449fa5..6bade90182 100644
            --- a/core/java/android/app/usage/NetworkStatsManager.java
            +++ b/core/java/android/app/usage/NetworkStatsManager.java
            @@ -146,6 +146,7 @@ public class NetworkStatsManager {
                 }
             
                 /** @hide */
            +    @UnsupportedAppUsage
                 @TestApi
                 public void setPollForce(boolean pollForce) {
                     if (pollForce) {
            
            From 39b880fb0859dbdf9055882367a1a9ada91c2c17 Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Thu, 31 Oct 2019 15:15:50 +0000
            Subject: [PATCH 0671/1150] Add @UnsupportedAppUsage to test apis that are
             known to be used by apps.
            
            go/testapi-enforcement
            
            Bug: 133832325
            Test: m
            Change-Id: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6
            Merged-In: Ifc8db120640a1554dcbf1722e61e09c7ddc65dd6
            ---
             core/java/android/app/usage/NetworkStatsManager.java | 1 +
             1 file changed, 1 insertion(+)
            
            diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
            index 8e40449fa5..6bade90182 100644
            --- a/core/java/android/app/usage/NetworkStatsManager.java
            +++ b/core/java/android/app/usage/NetworkStatsManager.java
            @@ -146,6 +146,7 @@ public class NetworkStatsManager {
                 }
             
                 /** @hide */
            +    @UnsupportedAppUsage
                 @TestApi
                 public void setPollForce(boolean pollForce) {
                     if (pollForce) {
            
            From 3e5af51f7c3b6036c4fb73a6c780b0bdaec673f2 Mon Sep 17 00:00:00 2001
            From: Jayachandran C 
            Date: Fri, 15 Nov 2019 09:58:04 -0800
            Subject: [PATCH 0672/1150] Remove usage of Telephonymanager getDefault() and
             from() hidden APIs
            
            This CL replaces with getSystemService(TelephonyManager.class)
            
            Bug: 140768340
            Test: atest frameworks/base/tests/net
            Change-Id: I0f14cc5440fa85c81ab90f3199e9e91c1b00f5e1
            ---
             .../core/java/com/android/server/net/NetworkStatsService.java   | 2 +-
             1 file changed, 1 insertion(+), 1 deletion(-)
            
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index 41806cabef..08c94267e9 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -337,7 +337,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                             powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
             
                     NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager,
            -                wakeLock, getDefaultClock(), TelephonyManager.getDefault(),
            +                wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class),
                             new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(),
                             new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir());
                     service.registerLocalService();
            
            From ada48c4ecd5ff70bcea4f38d99750297bd45c31e Mon Sep 17 00:00:00 2001
            From: Jayachandran C 
            Date: Mon, 25 Nov 2019 15:16:05 -0800
            Subject: [PATCH 0673/1150] Remove usage of hidden API
             TelephonyManager.getNetworkTypeName(int)
            
            This CL deletes the reference to this API as its used in a dead code
            which is used for debugging only.
            
            Bug: 140908357
            Test: Build
            Change-Id: I9fa1996ab5fdb5ab884128d06c2e92bab164dea7
            ---
             core/java/android/net/NetworkIdentity.java | 3 ---
             1 file changed, 3 deletions(-)
            
            diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
            index ce2de8554d..febc730480 100644
            --- a/core/java/android/net/NetworkIdentity.java
            +++ b/core/java/android/net/NetworkIdentity.java
            @@ -25,7 +25,6 @@ import android.net.wifi.WifiInfo;
             import android.net.wifi.WifiManager;
             import android.os.Build;
             import android.service.NetworkIdentityProto;
            -import android.telephony.TelephonyManager;
             import android.util.Slog;
             import android.util.proto.ProtoOutputStream;
             
            @@ -98,8 +97,6 @@ public class NetworkIdentity implements Comparable {
                     builder.append(", subType=");
                     if (COMBINE_SUBTYPE_ENABLED) {
                         builder.append("COMBINED");
            -        } else if (ConnectivityManager.isNetworkTypeMobile(mType)) {
            -            builder.append(TelephonyManager.getNetworkTypeName(mSubType));
                     } else {
                         builder.append(mSubType);
                     }
            
            From 904f511b91ce2b179692c32c2cc9f484ec07c4c1 Mon Sep 17 00:00:00 2001
            From: markchien 
            Date: Mon, 30 Sep 2019 14:40:57 +0800
            Subject: [PATCH 0674/1150] [Tether07] Migrate Tethering into module
            
            Now tethering would be run in dedicated service.
            TetheringManager is the interface used to communicate with
            TetheringService. The new call flow would be: ConnectivityManager
            -> ConnectivityService -> TetheringManager -> TetheringService.
            Note: the return value of #tether(), #untether() and #setUsbTethering()
            APIs would always be no error. Client can use #getLastTetherError()
            or #getTetheredIfaces or listen tether state change to check
            status of corresponding interface.
            
            Bug: 136040414
            Bug: 144742179
            Test: -build, flash, boot
                  -atest TetheringTests
                  -atest FrameworksNetTests
            
            Change-Id: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3
            ---
             .../core/java/com/android/server/net/NetworkStatsService.java    | 1 -
             1 file changed, 1 deletion(-)
            
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index 08c94267e9..e473c96980 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -138,7 +138,6 @@ import com.android.internal.util.FileRotator;
             import com.android.internal.util.IndentingPrintWriter;
             import com.android.server.EventLogTags;
             import com.android.server.LocalServices;
            -import com.android.server.connectivity.Tethering;
             
             import java.io.File;
             import java.io.FileDescriptor;
            
            From a2f6c26b7dda29a10193ecfe1e5bc6553ed74174 Mon Sep 17 00:00:00 2001
            From: markchien 
            Date: Mon, 30 Sep 2019 14:40:57 +0800
            Subject: [PATCH 0675/1150] [Tether07] Migrate Tethering into module
            
            Now tethering would be run in dedicated service.
            TetheringManager is the interface used to communicate with
            TetheringService. The new call flow would be: ConnectivityManager
            -> ConnectivityService -> TetheringManager -> TetheringService.
            Note: the return value of #tether(), #untether() and #setUsbTethering()
            APIs would always be no error. Client can use #getLastTetherError()
            or #getTetheredIfaces or listen tether state change to check
            status of corresponding interface.
            
            Bug: 136040414
            Bug: 144742179
            Test: -build, flash, boot
                  -atest TetheringTests
                  -atest FrameworksNetTests
            
            Change-Id: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3
            Merged-In: I7e78c0e0a3e70f940a749ba2a39ece7c7ec5b9b3
            ---
             .../core/java/com/android/server/net/NetworkStatsService.java    | 1 -
             1 file changed, 1 deletion(-)
            
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index 08c94267e9..e473c96980 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -138,7 +138,6 @@ import com.android.internal.util.FileRotator;
             import com.android.internal.util.IndentingPrintWriter;
             import com.android.server.EventLogTags;
             import com.android.server.LocalServices;
            -import com.android.server.connectivity.Tethering;
             
             import java.io.File;
             import java.io.FileDescriptor;
            
            From 912724932c0ec2cd8d839fb6e7f03c24c5f63be7 Mon Sep 17 00:00:00 2001
            From: paulhu 
            Date: Mon, 12 Aug 2019 16:25:11 +0800
            Subject: [PATCH 0676/1150] Replace the permission of internal connectivity
             checks
            
            A number of connectivity checks that protect system-only methods
            check for CONNECTIVITY_INTERNAL, but CONNECTIVITY_INTERNAL is a
            signature|privileged permission. We should audit the permission
            checks, and convert checks that protect code that should not be
            called outside the system to a signature permission. So replace
            all CONNECTIVITY_INTERNAL to other proper permissions.
            
            Bug: 32963470
            Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest
            Change-Id: I8f2dd1cd0609056494eaf612d39820e273ae093f
            Merged-In: I8f2dd1cd0609056494eaf612d39820e273ae093f
            ---
             .../java/com/android/server/NsdService.java   | 25 ++++++++-----------
             .../server/net/NetworkStatsService.java       |  6 ++---
             2 files changed, 13 insertions(+), 18 deletions(-)
            
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index 3efef017d2..b9b7bf73c1 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -16,19 +16,18 @@
             
             package com.android.server;
             
            -import android.content.Context;
             import android.content.ContentResolver;
            +import android.content.Context;
             import android.content.Intent;
            -import android.content.pm.PackageManager;
             import android.database.ContentObserver;
            +import android.net.NetworkStack;
             import android.net.Uri;
            -import android.net.nsd.NsdServiceInfo;
             import android.net.nsd.DnsSdTxtRecord;
             import android.net.nsd.INsdManager;
             import android.net.nsd.NsdManager;
            -import android.os.Binder;
            -import android.os.HandlerThread;
            +import android.net.nsd.NsdServiceInfo;
             import android.os.Handler;
            +import android.os.HandlerThread;
             import android.os.Message;
             import android.os.Messenger;
             import android.os.UserHandle;
            @@ -38,6 +37,12 @@ import android.util.Slog;
             import android.util.SparseArray;
             import android.util.SparseIntArray;
             
            +import com.android.internal.annotations.VisibleForTesting;
            +import com.android.internal.util.AsyncChannel;
            +import com.android.internal.util.DumpUtils;
            +import com.android.internal.util.State;
            +import com.android.internal.util.StateMachine;
            +
             import java.io.FileDescriptor;
             import java.io.PrintWriter;
             import java.net.InetAddress;
            @@ -45,13 +50,6 @@ import java.util.Arrays;
             import java.util.HashMap;
             import java.util.concurrent.CountDownLatch;
             
            -import com.android.internal.annotations.VisibleForTesting;
            -import com.android.internal.util.AsyncChannel;
            -import com.android.internal.util.DumpUtils;
            -import com.android.internal.util.Protocol;
            -import com.android.internal.util.State;
            -import com.android.internal.util.StateMachine;
            -
             /**
              * Network Service Discovery Service handles remote service discovery operation requests by
              * implementing the INsdManager interface.
            @@ -565,8 +563,7 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 public void setEnabled(boolean isEnabled) {
            -        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
            -                "NsdService");
            +        NetworkStack.checkNetworkStackPermission(mContext);
                     mNsdSettings.putEnabledStatus(isEnabled);
                     notifyEnabled(isEnabled);
                 }
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index e473c96980..16424f2fef 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -17,7 +17,6 @@
             package com.android.server.net;
             
             import static android.Manifest.permission.ACCESS_NETWORK_STATE;
            -import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
             import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
             import static android.content.Intent.ACTION_SHUTDOWN;
             import static android.content.Intent.ACTION_UID_REMOVED;
            @@ -91,6 +90,7 @@ import android.net.Network;
             import android.net.NetworkCapabilities;
             import android.net.NetworkIdentity;
             import android.net.NetworkInfo;
            +import android.net.NetworkStack;
             import android.net.NetworkState;
             import android.net.NetworkStats;
             import android.net.NetworkStats.NonMonotonicObserver;
            @@ -1020,8 +1020,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                 private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
            -            // on background handler thread, and verified CONNECTIVITY_INTERNAL
            -            // permission above.
                         performPoll(FLAG_PERSIST_NETWORK);
                     }
                 };
            @@ -1095,7 +1093,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                     @Override
                     public void limitReached(String limitName, String iface) {
                         // only someone like NMS should be calling us
            -            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
            +            NetworkStack.checkNetworkStackPermission(mContext);
             
                         if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
                             // kick off background poll to collect network stats unless there is already
            
            From 4d138ce23347aed3e2c39fed6ce553d2c8b97d39 Mon Sep 17 00:00:00 2001
            From: paulhu 
            Date: Mon, 12 Aug 2019 16:25:11 +0800
            Subject: [PATCH 0677/1150] Replace the permission of internal connectivity
             checks
            
            A number of connectivity checks that protect system-only methods
            check for CONNECTIVITY_INTERNAL, but CONNECTIVITY_INTERNAL is a
            signature|privileged permission. We should audit the permission
            checks, and convert checks that protect code that should not be
            called outside the system to a signature permission. So replace
            all CONNECTIVITY_INTERNAL to other proper permissions.
            
            Bug: 32963470
            Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest
            Change-Id: I8f2dd1cd0609056494eaf612d39820e273ae093f
            ---
             .../java/com/android/server/NsdService.java   | 25 ++++++++-----------
             .../server/net/NetworkStatsService.java       |  6 ++---
             2 files changed, 13 insertions(+), 18 deletions(-)
            
            diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
            index 3efef017d2..b9b7bf73c1 100644
            --- a/services/core/java/com/android/server/NsdService.java
            +++ b/services/core/java/com/android/server/NsdService.java
            @@ -16,19 +16,18 @@
             
             package com.android.server;
             
            -import android.content.Context;
             import android.content.ContentResolver;
            +import android.content.Context;
             import android.content.Intent;
            -import android.content.pm.PackageManager;
             import android.database.ContentObserver;
            +import android.net.NetworkStack;
             import android.net.Uri;
            -import android.net.nsd.NsdServiceInfo;
             import android.net.nsd.DnsSdTxtRecord;
             import android.net.nsd.INsdManager;
             import android.net.nsd.NsdManager;
            -import android.os.Binder;
            -import android.os.HandlerThread;
            +import android.net.nsd.NsdServiceInfo;
             import android.os.Handler;
            +import android.os.HandlerThread;
             import android.os.Message;
             import android.os.Messenger;
             import android.os.UserHandle;
            @@ -38,6 +37,12 @@ import android.util.Slog;
             import android.util.SparseArray;
             import android.util.SparseIntArray;
             
            +import com.android.internal.annotations.VisibleForTesting;
            +import com.android.internal.util.AsyncChannel;
            +import com.android.internal.util.DumpUtils;
            +import com.android.internal.util.State;
            +import com.android.internal.util.StateMachine;
            +
             import java.io.FileDescriptor;
             import java.io.PrintWriter;
             import java.net.InetAddress;
            @@ -45,13 +50,6 @@ import java.util.Arrays;
             import java.util.HashMap;
             import java.util.concurrent.CountDownLatch;
             
            -import com.android.internal.annotations.VisibleForTesting;
            -import com.android.internal.util.AsyncChannel;
            -import com.android.internal.util.DumpUtils;
            -import com.android.internal.util.Protocol;
            -import com.android.internal.util.State;
            -import com.android.internal.util.StateMachine;
            -
             /**
              * Network Service Discovery Service handles remote service discovery operation requests by
              * implementing the INsdManager interface.
            @@ -565,8 +563,7 @@ public class NsdService extends INsdManager.Stub {
                 }
             
                 public void setEnabled(boolean isEnabled) {
            -        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
            -                "NsdService");
            +        NetworkStack.checkNetworkStackPermission(mContext);
                     mNsdSettings.putEnabledStatus(isEnabled);
                     notifyEnabled(isEnabled);
                 }
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index e473c96980..16424f2fef 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -17,7 +17,6 @@
             package com.android.server.net;
             
             import static android.Manifest.permission.ACCESS_NETWORK_STATE;
            -import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
             import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
             import static android.content.Intent.ACTION_SHUTDOWN;
             import static android.content.Intent.ACTION_UID_REMOVED;
            @@ -91,6 +90,7 @@ import android.net.Network;
             import android.net.NetworkCapabilities;
             import android.net.NetworkIdentity;
             import android.net.NetworkInfo;
            +import android.net.NetworkStack;
             import android.net.NetworkState;
             import android.net.NetworkStats;
             import android.net.NetworkStats.NonMonotonicObserver;
            @@ -1020,8 +1020,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                 private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() {
                     @Override
                     public void onReceive(Context context, Intent intent) {
            -            // on background handler thread, and verified CONNECTIVITY_INTERNAL
            -            // permission above.
                         performPoll(FLAG_PERSIST_NETWORK);
                     }
                 };
            @@ -1095,7 +1093,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                     @Override
                     public void limitReached(String limitName, String iface) {
                         // only someone like NMS should be calling us
            -            mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
            +            NetworkStack.checkNetworkStackPermission(mContext);
             
                         if (LIMIT_GLOBAL_ALERT.equals(limitName)) {
                             // kick off background poll to collect network stats unless there is already
            
            From 5d4c651bdf7f08ce5955a9d94bd29772a74f05ef Mon Sep 17 00:00:00 2001
            From: Jeffrey Huang 
            Date: Thu, 5 Dec 2019 11:28:11 -0800
            Subject: [PATCH 0678/1150] Rename writeToProto to be dumpDebug
            
            We want to eventually migrate some of these APIs to be @SystemApi for mainline modules.
            The #dumpDebug name is more appropriate than #writeToProto.
            
            Bug: 142279786
            Test: Manual
            Change-Id: I60793e91cedf6b720d4ecef6a8484f4fed4ff30f
            ---
             core/java/android/net/NetworkIdentity.java         |  2 +-
             core/java/android/net/NetworkStatsHistory.java     | 14 +++++++-------
             .../com/android/server/net/NetworkIdentitySet.java |  4 ++--
             .../android/server/net/NetworkStatsCollection.java |  6 +++---
             .../android/server/net/NetworkStatsRecorder.java   |  4 ++--
             .../android/server/net/NetworkStatsService.java    | 10 +++++-----
             6 files changed, 20 insertions(+), 20 deletions(-)
            
            diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
            index febc730480..c1198aac27 100644
            --- a/core/java/android/net/NetworkIdentity.java
            +++ b/core/java/android/net/NetworkIdentity.java
            @@ -114,7 +114,7 @@ public class NetworkIdentity implements Comparable {
                     return builder.append("}").toString();
                 }
             
            -    public void writeToProto(ProtoOutputStream proto, long tag) {
            +    public void dumpDebug(ProtoOutputStream proto, long tag) {
                     final long start = proto.start(tag);
             
                     proto.write(NetworkIdentityProto.TYPE, mType);
            diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
            index f61260ee3e..d96d2ee481 100644
            --- a/core/java/android/net/NetworkStatsHistory.java
            +++ b/core/java/android/net/NetworkStatsHistory.java
            @@ -684,7 +684,7 @@ public class NetworkStatsHistory implements Parcelable {
                     }
                 }
             
            -    public void writeToProto(ProtoOutputStream proto, long tag) {
            +    public void dumpDebug(ProtoOutputStream proto, long tag) {
                     final long start = proto.start(tag);
             
                     proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
            @@ -693,11 +693,11 @@ public class NetworkStatsHistory implements Parcelable {
                         final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
             
                         proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
            -            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
            -            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
            -            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
            -            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
            -            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
            +            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
            +            dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
            +            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
            +            dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
            +            dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
             
                         proto.end(startBucket);
                     }
            @@ -705,7 +705,7 @@ public class NetworkStatsHistory implements Parcelable {
                     proto.end(start);
                 }
             
            -    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
            +    private static void dumpDebug(ProtoOutputStream proto, long tag, long[] array, int index) {
                     if (array != null) {
                         proto.write(tag, array[index]);
                     }
            diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
            index 68cd5e7aed..2326ad39fd 100644
            --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
            +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
            @@ -170,11 +170,11 @@ public class NetworkIdentitySet extends HashSet implements
                     return ident.compareTo(anotherIdent);
                 }
             
            -    public void writeToProto(ProtoOutputStream proto, long tag) {
            +    public void dumpDebug(ProtoOutputStream proto, long tag) {
                     final long start = proto.start(tag);
             
                     for (NetworkIdentity ident : this) {
            -            ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES);
            +            ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES);
                     }
             
                     proto.end(start);
            diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
            index ab525237db..05ab2ae87a 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
            @@ -687,7 +687,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
                     }
                 }
             
            -    public void writeToProto(ProtoOutputStream proto, long tag) {
            +    public void dumpDebug(ProtoOutputStream proto, long tag) {
                     final long start = proto.start(tag);
             
                     for (Key key : getSortedKeys()) {
            @@ -695,7 +695,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
             
                         // Key
                         final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
            -            key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY);
            +            key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY);
                         proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
                         proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
                         proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
            @@ -703,7 +703,7 @@ public class NetworkStatsCollection implements FileRotator.Reader {
             
                         // Value
                         final NetworkStatsHistory history = mStats.get(key);
            -            history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
            +            history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY);
                         proto.end(startStats);
                     }
             
            diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            index 06ec341d9e..6af962bbcc 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            @@ -470,12 +470,12 @@ public class NetworkStatsRecorder {
                     }
                 }
             
            -    public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
            +    public void dumpDebugLocked(ProtoOutputStream proto, long tag) {
                     final long start = proto.start(tag);
                     if (mPending != null) {
                         proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
                     }
            -        getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
            +        getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
                     proto.end(start);
                 }
             
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index 16424f2fef..673e8302a4 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -1609,10 +1609,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
             
                     dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
                     dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
            -        mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
            -        mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
            -        mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
            -        mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
            +        mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
            +        mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
            +        mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
            +        mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
             
                     proto.flush();
                 }
            @@ -1623,7 +1623,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                         final long start = proto.start(tag);
             
                         proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
            -            ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES);
            +            ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES);
             
                         proto.end(start);
                     }
            
            From b0db4fdb6543812fb0bb4af3bf0f98d89bb646bf Mon Sep 17 00:00:00 2001
            From: Aaron Huang 
            Date: Fri, 27 Sep 2019 22:31:22 +0800
            Subject: [PATCH 0679/1150] Add TrafficStats methods to public APIs
            
            Add methods to public APIs for mainline support.
            
            Bug: 139268426
            Bug: 135998869
            Test: atest FrameworksNetTests
                  ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh
                  atest android.net.cts
                  atest android.net.wifi.cts
            
            Change-Id: I21a9c0dbdc79b1f1041fc9e23c6a4e1e97ecde92
            ---
             core/java/android/net/TrafficStats.java | 23 +++++++++++++++++++----
             1 file changed, 19 insertions(+), 4 deletions(-)
            
            diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
            index 1c6a48434a..bf4884aa96 100644
            --- a/core/java/android/net/TrafficStats.java
            +++ b/core/java/android/net/TrafficStats.java
            @@ -16,6 +16,7 @@
             
             package android.net;
             
            +import android.annotation.NonNull;
             import android.annotation.SuppressLint;
             import android.annotation.SystemApi;
             import android.annotation.TestApi;
            @@ -595,8 +596,15 @@ public class TrafficStats {
                     return total;
                 }
             
            -    /** {@hide} */
            -    public static long getTxPackets(String iface) {
            +    /**
            +     * Return the number of packets transmitted on the specified interface since
            +     * device boot. Statistics are measured at the network layer, so both TCP and
            +     * UDP usage are included.
            +     *
            +     * @param iface The name of the interface.
            +     * @return The number of transmitted packets.
            +     */
            +    public static long getTxPackets(@NonNull String iface) {
                     try {
                         return getStatsService().getIfaceStats(iface, TYPE_TX_PACKETS);
                     } catch (RemoteException e) {
            @@ -604,8 +612,15 @@ public class TrafficStats {
                     }
                 }
             
            -    /** {@hide} */
            -    public static long getRxPackets(String iface) {
            +    /**
            +     * Return the number of packets received on the specified interface since
            +     * device boot. Statistics are measured at the network layer, so both TCP
            +     * and UDP usage are included.
            +     *
            +     * @param iface The name of the interface.
            +     * @return The number of received packets.
            +     */
            +    public static long getRxPackets(@NonNull String iface) {
                     try {
                         return getStatsService().getIfaceStats(iface, TYPE_RX_PACKETS);
                     } catch (RemoteException e) {
            
            From e5eb786c463f8c78898e6663ae7debe7c92d774c Mon Sep 17 00:00:00 2001
            From: junyulai 
            Date: Fri, 6 Dec 2019 18:50:41 +0800
            Subject: [PATCH 0680/1150] Update interface quota limit when network stats
             updated
            
            In previous design, interface quota limit does not changed
            when network stats are updated. However, this is incorrect
            today since there are some offloaded traffic that cannot
            be seen by kernel. If the limit is not updated, the offloaded
            traffic might still be able to use whole quota as if there is
            no embedded traffic.
            
            This change also removes the re-arm global alert after
            advising persist threshold if not changed, given that it will
            cause an additional alert while updating interface quota limit.
            
            Bug: 145792619
            Test: 1. atest NetworkStatsServiceTest
                  2. atest NetworkPolicyManagerServiceTest
                  3. manual test: run speedtest, check dumpsys netd
            
            Change-Id: I8d2203e713730d536430a234b1aa8b2468badee3
            ---
             .../java/com/android/server/net/NetworkStatsService.java   | 7 +++++--
             1 file changed, 5 insertions(+), 2 deletions(-)
            
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index 16424f2fef..a943e77284 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -873,6 +873,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                                 + mPersistThreshold);
                     }
             
            +        final long oldGlobalAlertBytes = mGlobalAlertBytes;
            +
                     // update and persist if beyond new thresholds
                     final long currentTime = mClock.millis();
                     synchronized (mStatsLock) {
            @@ -886,8 +888,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                         mUidTagRecorder.maybePersistLocked(currentTime);
                     }
             
            -        // re-arm global alert
            -        registerGlobalAlert();
            +        if (oldGlobalAlertBytes != mGlobalAlertBytes) {
            +            registerGlobalAlert();
            +        }
                 }
             
                 @Override
            
            From efd5607e471ac023fedc94033f10fdc234dfcaff Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Tue, 10 Dec 2019 17:47:51 +0000
            Subject: [PATCH 0681/1150] Use new UnsupportedAppUsage annotation.
            
            Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library.
            
            Bug: 145132366
            Test: m && diff unsupportedappusage_index.csv
            Change-Id: I8789f8499d4dca08580672e9e45ed9a7026dd686
            ---
             core/java/android/app/usage/NetworkStatsManager.java | 2 +-
             1 file changed, 1 insertion(+), 1 deletion(-)
            
            diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
            index 6bade90182..74129702b4 100644
            --- a/core/java/android/app/usage/NetworkStatsManager.java
            +++ b/core/java/android/app/usage/NetworkStatsManager.java
            @@ -21,8 +21,8 @@ import static com.android.internal.util.Preconditions.checkNotNull;
             import android.annotation.Nullable;
             import android.annotation.SystemService;
             import android.annotation.TestApi;
            -import android.annotation.UnsupportedAppUsage;
             import android.app.usage.NetworkStats.Bucket;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.content.Context;
             import android.net.ConnectivityManager;
             import android.net.DataUsageRequest;
            
            From d70aacdd3bfc85a71caf2d80689173df1872fe68 Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Tue, 10 Dec 2019 17:47:53 +0000
            Subject: [PATCH 0682/1150] Use new UnsupportedAppUsage annotation.
            
            Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library.
            
            Bug: 145132366
            Test: m && diff unsupportedappusage_index.csv
            Change-Id: I534e3fd1305e2f4af076986770033478448a665c
            ---
             core/java/android/net/nsd/NsdServiceInfo.java | 6 +++---
             1 file changed, 3 insertions(+), 3 deletions(-)
            
            diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java
            index 459b140980..0946499f16 100644
            --- a/core/java/android/net/nsd/NsdServiceInfo.java
            +++ b/core/java/android/net/nsd/NsdServiceInfo.java
            @@ -17,13 +17,13 @@
             package android.net.nsd;
             
             import android.annotation.NonNull;
            -import android.annotation.UnsupportedAppUsage;
            -import android.os.Parcelable;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
            +import android.os.Parcelable;
             import android.text.TextUtils;
            +import android.util.ArrayMap;
             import android.util.Base64;
             import android.util.Log;
            -import android.util.ArrayMap;
             
             import java.io.UnsupportedEncodingException;
             import java.net.InetAddress;
            
            From b874007169a536c58de0f53ee5063fa78c571ed7 Mon Sep 17 00:00:00 2001
            From: Daulet Zhanguzin 
            Date: Mon, 30 Dec 2019 15:41:28 +0000
            Subject: [PATCH 0683/1150] Replace
             com.android.internal.util.Preconditions.checkNotNull with
             java.util.Objects.requireNonNull
            
            Bug: 126528330
            
            Test: Treehugger
            Change-Id: I42117ebfb640e3b0b133183e5e146860bed8471a
            ---
             core/java/android/app/usage/NetworkStatsManager.java | 6 +++---
             1 file changed, 3 insertions(+), 3 deletions(-)
            
            diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java
            index 74129702b4..4346d9738e 100644
            --- a/core/java/android/app/usage/NetworkStatsManager.java
            +++ b/core/java/android/app/usage/NetworkStatsManager.java
            @@ -16,8 +16,6 @@
             
             package android.app.usage;
             
            -import static com.android.internal.util.Preconditions.checkNotNull;
            -
             import android.annotation.Nullable;
             import android.annotation.SystemService;
             import android.annotation.TestApi;
            @@ -42,6 +40,8 @@ import android.util.Log;
             
             import com.android.internal.annotations.VisibleForTesting;
             
            +import java.util.Objects;
            +
             /**
              * Provides access to network usage history and statistics. Usage data is collected in
              * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details.
            @@ -418,7 +418,7 @@ public class NetworkStatsManager {
                 /** @hide */
                 public void registerUsageCallback(NetworkTemplate template, int networkType,
                         long thresholdBytes, UsageCallback callback, @Nullable Handler handler) {
            -        checkNotNull(callback, "UsageCallback cannot be null");
            +        Objects.requireNonNull(callback, "UsageCallback cannot be null");
             
                     final Looper looper;
                     if (handler == null) {
            
            From 4c1c7d1a8d52c121becc6939e252341a4775383c Mon Sep 17 00:00:00 2001
            From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= 
            Date: Mon, 30 Dec 2019 07:51:27 -0800
            Subject: [PATCH 0684/1150] remove spurious 'struct' on Stats
            MIME-Version: 1.0
            Content-Type: text/plain; charset=UTF-8
            Content-Transfer-Encoding: 8bit
            
            Test: builds, atest
            Bug: 146787904
            Signed-off-by: Maciej Żenczykowski 
            Change-Id: I824daf0ebdddbac1b11cabfcb248ee4134586768
            ---
             .../com_android_server_net_NetworkStatsService.cpp   | 12 ++++++------
             1 file changed, 6 insertions(+), 6 deletions(-)
            
            diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            index 4d4a7b4164..740c618317 100644
            --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            @@ -54,7 +54,7 @@ enum StatsType {
                 TCP_TX_PACKETS = 5
             };
             
            -static uint64_t getStatsType(struct Stats* stats, StatsType type) {
            +static uint64_t getStatsType(Stats* stats, StatsType type) {
                 switch (type) {
                     case RX_BYTES:
                         return stats->rxBytes;
            @@ -73,7 +73,7 @@ static uint64_t getStatsType(struct Stats* stats, StatsType type) {
                 }
             }
             
            -static int parseIfaceStats(const char* iface, struct Stats* stats) {
            +static int parseIfaceStats(const char* iface, Stats* stats) {
                 FILE *fp = fopen(QTAGUID_IFACE_STATS, "r");
                 if (fp == NULL) {
                     return -1;
            @@ -117,7 +117,7 @@ static int parseIfaceStats(const char* iface, struct Stats* stats) {
                 return 0;
             }
             
            -static int parseUidStats(const uint32_t uid, struct Stats* stats) {
            +static int parseUidStats(const uint32_t uid, Stats* stats) {
                 FILE *fp = fopen(QTAGUID_UID_STATS, "r");
                 if (fp == NULL) {
                     return -1;
            @@ -150,7 +150,7 @@ static int parseUidStats(const uint32_t uid, struct Stats* stats) {
             }
             
             static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
            -    struct Stats stats;
            +    Stats stats;
                 memset(&stats, 0, sizeof(Stats));
             
                 if (useBpfStats) {
            @@ -175,7 +175,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
                     return UNKNOWN;
                 }
             
            -    struct Stats stats;
            +    Stats stats;
                 memset(&stats, 0, sizeof(Stats));
             
                 if (useBpfStats) {
            @@ -194,7 +194,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
             }
             
             static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
            -    struct Stats stats;
            +    Stats stats;
                 memset(&stats, 0, sizeof(Stats));
             
                 if (useBpfStats) {
            
            From 0f8521ff0afbad1b303e34f77dbcf10422b9d0c2 Mon Sep 17 00:00:00 2001
            From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= 
            Date: Mon, 30 Dec 2019 07:54:22 -0800
            Subject: [PATCH 0685/1150] convert 'Stats stats; memset(&stats, 0,
             sizeof(Stats));' to 'Stats stats = {};'
            MIME-Version: 1.0
            Content-Type: text/plain; charset=UTF-8
            Content-Transfer-Encoding: 8bit
            
            Not only is it more concise, but it's also just a tad more correct:
            since it really should have been 'sizeof(stats)' not 'sizeof(Stats)'.
            
            Test: builds, atest
            Bug: 146787904
            Signed-off-by: Maciej Żenczykowski 
            Change-Id: I6cf0295878c7b34cedfe3ae44ff7410ef419f8b9
            ---
             .../jni/com_android_server_net_NetworkStatsService.cpp   | 9 +++------
             1 file changed, 3 insertions(+), 6 deletions(-)
            
            diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            index 740c618317..4696dd0bb8 100644
            --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            @@ -150,8 +150,7 @@ static int parseUidStats(const uint32_t uid, Stats* stats) {
             }
             
             static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) {
            -    Stats stats;
            -    memset(&stats, 0, sizeof(Stats));
            +    Stats stats = {};
             
                 if (useBpfStats) {
                     if (bpfGetIfaceStats(NULL, &stats) == 0) {
            @@ -175,8 +174,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
                     return UNKNOWN;
                 }
             
            -    Stats stats;
            -    memset(&stats, 0, sizeof(Stats));
            +    Stats stats = {};
             
                 if (useBpfStats) {
                     if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) {
            @@ -194,8 +192,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type,
             }
             
             static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) {
            -    Stats stats;
            -    memset(&stats, 0, sizeof(Stats));
            +    Stats stats = {};
             
                 if (useBpfStats) {
                     if (bpfGetUidStats(uid, &stats) == 0) {
            
            From f1cf57d37fa98a52a018f7fd0a2d0a76b9e4c104 Mon Sep 17 00:00:00 2001
            From: Daulet Zhanguzin 
            Date: Fri, 3 Jan 2020 13:37:24 +0000
            Subject: [PATCH 0686/1150] Replace
             com.android.internal.util.Preconditions.checkNotNull with
             java.util.Objects.requireNonNull
            
            Bug: 126528330
            
            Test: Treehugger
            Change-Id: I978d5d0959f7800e859bfb384458ba52adc0c2b0
            ---
             .../server/net/NetworkStatsRecorder.java      | 23 ++++++-----
             .../server/net/NetworkStatsService.java       | 39 ++++++++++---------
             2 files changed, 31 insertions(+), 31 deletions(-)
            
            diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            index 06ec341d9e..a94a2f79ab 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
            @@ -21,8 +21,6 @@ import static android.net.TrafficStats.KB_IN_BYTES;
             import static android.net.TrafficStats.MB_IN_BYTES;
             import static android.text.format.DateUtils.YEAR_IN_MILLIS;
             
            -import static com.android.internal.util.Preconditions.checkNotNull;
            -
             import android.net.NetworkStats;
             import android.net.NetworkStats.NonMonotonicObserver;
             import android.net.NetworkStatsHistory;
            @@ -54,6 +52,7 @@ import java.lang.ref.WeakReference;
             import java.util.Arrays;
             import java.util.HashSet;
             import java.util.Map;
            +import java.util.Objects;
             
             /**
              * Logic to record deltas between periodic {@link NetworkStats} snapshots into
            @@ -116,9 +115,9 @@ public class NetworkStatsRecorder {
                  */
                 public NetworkStatsRecorder(FileRotator rotator, NonMonotonicObserver observer,
                         DropBoxManager dropBox, String cookie, long bucketDuration, boolean onlyTags) {
            -        mRotator = checkNotNull(rotator, "missing FileRotator");
            -        mObserver = checkNotNull(observer, "missing NonMonotonicObserver");
            -        mDropBox = checkNotNull(dropBox, "missing DropBoxManager");
            +        mRotator = Objects.requireNonNull(rotator, "missing FileRotator");
            +        mObserver = Objects.requireNonNull(observer, "missing NonMonotonicObserver");
            +        mDropBox = Objects.requireNonNull(dropBox, "missing DropBoxManager");
                     mCookie = cookie;
             
                     mBucketDuration = bucketDuration;
            @@ -165,7 +164,7 @@ public class NetworkStatsRecorder {
                  * as reference is valid.
                  */
                 public NetworkStatsCollection getOrLoadCompleteLocked() {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
                     NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
                     if (res == null) {
                         res = loadLocked(Long.MIN_VALUE, Long.MAX_VALUE);
            @@ -175,7 +174,7 @@ public class NetworkStatsRecorder {
                 }
             
                 public NetworkStatsCollection getOrLoadPartialLocked(long start, long end) {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
                     NetworkStatsCollection res = mComplete != null ? mComplete.get() : null;
                     if (res == null) {
                         res = loadLocked(start, end);
            @@ -280,7 +279,7 @@ public class NetworkStatsRecorder {
                  * {@link #mPersistThresholdBytes}.
                  */
                 public void maybePersistLocked(long currentTimeMillis) {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
                     final long pendingBytes = mPending.getTotalBytes();
                     if (pendingBytes >= mPersistThresholdBytes) {
                         forcePersistLocked(currentTimeMillis);
            @@ -293,7 +292,7 @@ public class NetworkStatsRecorder {
                  * Force persisting any pending deltas.
                  */
                 public void forcePersistLocked(long currentTimeMillis) {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
                     if (mPending.isDirty()) {
                         if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie);
                         try {
            @@ -356,7 +355,7 @@ public class NetworkStatsRecorder {
                     private final NetworkStatsCollection mCollection;
             
                     public CombiningRewriter(NetworkStatsCollection collection) {
            -            mCollection = checkNotNull(collection, "missing NetworkStatsCollection");
            +            mCollection = Objects.requireNonNull(collection, "missing NetworkStatsCollection");
                     }
             
                     @Override
            @@ -418,7 +417,7 @@ public class NetworkStatsRecorder {
                 }
             
                 public void importLegacyNetworkLocked(File file) throws IOException {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
             
                     // legacy file still exists; start empty to avoid double importing
                     mRotator.deleteAll();
            @@ -438,7 +437,7 @@ public class NetworkStatsRecorder {
                 }
             
                 public void importLegacyUidLocked(File file) throws IOException {
            -        checkNotNull(mRotator, "missing FileRotator");
            +        Objects.requireNonNull(mRotator, "missing FileRotator");
             
                     // legacy file still exists; start empty to avoid double importing
                     mRotator.deleteAll();
            diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
            index a943e77284..a41fb7d327 100644
            --- a/services/core/java/com/android/server/net/NetworkStatsService.java
            +++ b/services/core/java/com/android/server/net/NetworkStatsService.java
            @@ -65,7 +65,6 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS;
             import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
             import static android.text.format.DateUtils.SECOND_IN_MILLIS;
             
            -import static com.android.internal.util.Preconditions.checkNotNull;
             import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT;
             import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats;
             import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet;
            @@ -148,6 +147,7 @@ import java.time.ZoneOffset;
             import java.util.Arrays;
             import java.util.HashSet;
             import java.util.List;
            +import java.util.Objects;
             
             /**
              * Collect and persist detailed network statistics, and provide this data to
            @@ -357,17 +357,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                         TelephonyManager teleManager, NetworkStatsSettings settings,
                         NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir,
                         File baseDir) {
            -        mContext = checkNotNull(context, "missing Context");
            -        mNetworkManager = checkNotNull(networkManager, "missing INetworkManagementService");
            -        mAlarmManager = checkNotNull(alarmManager, "missing AlarmManager");
            -        mClock = checkNotNull(clock, "missing Clock");
            -        mSettings = checkNotNull(settings, "missing NetworkStatsSettings");
            -        mTeleManager = checkNotNull(teleManager, "missing TelephonyManager");
            -        mWakeLock = checkNotNull(wakeLock, "missing WakeLock");
            -        mStatsFactory = checkNotNull(factory, "missing factory");
            -        mStatsObservers = checkNotNull(statsObservers, "missing NetworkStatsObservers");
            -        mSystemDir = checkNotNull(systemDir, "missing systemDir");
            -        mBaseDir = checkNotNull(baseDir, "missing baseDir");
            +        mContext = Objects.requireNonNull(context, "missing Context");
            +        mNetworkManager = Objects.requireNonNull(networkManager,
            +            "missing INetworkManagementService");
            +        mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager");
            +        mClock = Objects.requireNonNull(clock, "missing Clock");
            +        mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings");
            +        mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager");
            +        mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock");
            +        mStatsFactory = Objects.requireNonNull(factory, "missing factory");
            +        mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers");
            +        mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir");
            +        mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir");
                     mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists();
                 }
             
            @@ -896,11 +897,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                 @Override
                 public DataUsageRequest registerUsageCallback(String callingPackage,
                             DataUsageRequest request, Messenger messenger, IBinder binder) {
            -        checkNotNull(callingPackage, "calling package is null");
            -        checkNotNull(request, "DataUsageRequest is null");
            -        checkNotNull(request.template, "NetworkTemplate is null");
            -        checkNotNull(messenger, "messenger is null");
            -        checkNotNull(binder, "binder is null");
            +        Objects.requireNonNull(callingPackage, "calling package is null");
            +        Objects.requireNonNull(request, "DataUsageRequest is null");
            +        Objects.requireNonNull(request.template, "NetworkTemplate is null");
            +        Objects.requireNonNull(messenger, "messenger is null");
            +        Objects.requireNonNull(binder, "binder is null");
             
                     int callingUid = Binder.getCallingUid();
                     @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage);
            @@ -921,7 +922,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
             
                 @Override
                 public void unregisterUsageRequest(DataUsageRequest request) {
            -        checkNotNull(request, "DataUsageRequest is null");
            +        Objects.requireNonNull(request, "DataUsageRequest is null");
             
                     int callingUid = Binder.getCallingUid();
                     final long token = Binder.clearCallingIdentity();
            @@ -1795,7 +1796,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub {
                     private final ContentResolver mResolver;
             
                     public DefaultNetworkStatsSettings(Context context) {
            -            mResolver = checkNotNull(context.getContentResolver());
            +            mResolver = Objects.requireNonNull(context.getContentResolver());
                         // TODO: adjust these timings for production builds
                     }
             
            
            From d482d27a8d4240b0276c9346098aa0837e5a74ff Mon Sep 17 00:00:00 2001
            From: Daulet Zhanguzin 
            Date: Fri, 3 Jan 2020 09:46:50 +0000
            Subject: [PATCH 0687/1150] Replace
             com.android.internal.util.Preconditions.checkNotNull with
             java.util.Objects.requireNonNull
            
            Bug: 126528330
            
            Test: Treehugger
            Exempt-From-Owner-Approval: Global refactoring.
            Change-Id: Idb1b6ba41af3b52f3376b1157259af3c30328c4e
            ---
             .../java/com/android/server/IpSecService.java | 19 +++++++++----------
             .../android/server/NativeDaemonConnector.java |  3 ++-
             2 files changed, 11 insertions(+), 11 deletions(-)
            
            diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
            index a629b3fbb8..c98762074b 100644
            --- a/services/core/java/com/android/server/IpSecService.java
            +++ b/services/core/java/com/android/server/IpSecService.java
            @@ -25,8 +25,6 @@ import static android.system.OsConstants.EINVAL;
             import static android.system.OsConstants.IPPROTO_UDP;
             import static android.system.OsConstants.SOCK_DGRAM;
             
            -import static com.android.internal.util.Preconditions.checkNotNull;
            -
             import android.annotation.NonNull;
             import android.app.AppOpsManager;
             import android.content.Context;
            @@ -76,6 +74,7 @@ import java.net.InetSocketAddress;
             import java.net.UnknownHostException;
             import java.util.ArrayList;
             import java.util.List;
            +import java.util.Objects;
             
             /**
              * A service to manage multiple clients that want to access the IpSec API. The service is
            @@ -566,7 +565,7 @@ public class IpSecService extends IIpSecService.Stub {
                     }
             
                     void put(int key, RefcountedResource obj) {
            -            checkNotNull(obj, "Null resources cannot be added");
            +            Objects.requireNonNull(obj, "Null resources cannot be added");
                         mArray.put(key, obj);
                     }
             
            @@ -1101,7 +1100,7 @@ public class IpSecService extends IIpSecService.Stub {
                     if (requestedSpi > 0 && requestedSpi < 256) {
                         throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255.");
                     }
            -        checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
            +        Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex");
             
                     int callingUid = Binder.getCallingUid();
                     UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
            @@ -1218,7 +1217,7 @@ public class IpSecService extends IIpSecService.Stub {
                         throw new IllegalArgumentException(
                                 "Specified port number must be a valid non-reserved UDP port");
                     }
            -        checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
            +        Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket");
             
                     int callingUid = Binder.getCallingUid();
                     UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid);
            @@ -1278,8 +1277,8 @@ public class IpSecService extends IIpSecService.Stub {
                         String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder,
                         String callingPackage) {
                     enforceTunnelFeatureAndPermissions(callingPackage);
            -        checkNotNull(binder, "Null Binder passed to createTunnelInterface");
            -        checkNotNull(underlyingNetwork, "No underlying network was specified");
            +        Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface");
            +        Objects.requireNonNull(underlyingNetwork, "No underlying network was specified");
                     checkInetAddress(localAddr);
                     checkInetAddress(remoteAddr);
             
            @@ -1556,7 +1555,7 @@ public class IpSecService extends IIpSecService.Stub {
                                 "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS");
                     }
             
            -        checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels");
            +        Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels");
                     switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) {
                         case AppOpsManager.MODE_DEFAULT:
                             mContext.enforceCallingOrSelfPermission(
            @@ -1625,12 +1624,12 @@ public class IpSecService extends IIpSecService.Stub {
                 @Override
                 public synchronized IpSecTransformResponse createTransform(
                         IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException {
            -        checkNotNull(c);
            +        Objects.requireNonNull(c);
                     if (c.getMode() == IpSecTransform.MODE_TUNNEL) {
                         enforceTunnelFeatureAndPermissions(callingPackage);
                     }
                     checkIpSecConfig(c);
            -        checkNotNull(binder, "Null Binder passed to createTransform");
            +        Objects.requireNonNull(binder, "Null Binder passed to createTransform");
                     final int resourceId = mNextResourceId++;
             
                     UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid());
            diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
            index ad02aad6e4..eac767f735 100644
            --- a/services/core/java/com/android/server/NativeDaemonConnector.java
            +++ b/services/core/java/com/android/server/NativeDaemonConnector.java
            @@ -46,6 +46,7 @@ import java.util.concurrent.BlockingQueue;
             import java.util.concurrent.CountDownLatch;
             import java.util.concurrent.TimeUnit;
             import java.util.LinkedList;
            +import java.util.Objects;
             
             /**
              * Generic connector class for interfacing with a native daemon which uses the
            @@ -126,7 +127,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo
                  */
                 public void setWarnIfHeld(Object warnIfHeld) {
                     Preconditions.checkState(mWarnIfHeld == null);
            -        mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld);
            +        mWarnIfHeld = Objects.requireNonNull(warnIfHeld);
                 }
             
                 @Override
            
            From 725ce2f6c62b59d911e92ae430602f4c3a0443a4 Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Tue, 10 Dec 2019 17:47:52 +0000
            Subject: [PATCH 0688/1150] Use new UnsupportedAppUsage annotation.
            
            Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library.
            
            Bug: 145132366
            Test: m && diff unsupportedappusage_index.csv
            Change-Id: I0c336de56bc4a041dc97ff9b7927f62f0b44b457
            ---
             core/java/android/net/EthernetManager.java     | 2 +-
             core/java/android/net/NetworkStats.java        | 2 +-
             core/java/android/net/NetworkStatsHistory.java | 2 +-
             core/java/android/net/NetworkTemplate.java     | 2 +-
             core/java/android/net/TrafficStats.java        | 2 +-
             5 files changed, 5 insertions(+), 5 deletions(-)
            
            diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
            index 72565024d3..fd015b4fe5 100644
            --- a/core/java/android/net/EthernetManager.java
            +++ b/core/java/android/net/EthernetManager.java
            @@ -17,7 +17,7 @@
             package android.net;
             
             import android.annotation.SystemService;
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.content.Context;
             import android.os.Handler;
             import android.os.Message;
            diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
            index 6c7aa1379f..45bf4d2e13 100644
            --- a/core/java/android/net/NetworkStats.java
            +++ b/core/java/android/net/NetworkStats.java
            @@ -19,7 +19,7 @@ package android.net;
             import static android.os.Process.CLAT_UID;
             
             import android.annotation.NonNull;
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.os.SystemClock;
            diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
            index d96d2ee481..6d46c205b2 100644
            --- a/core/java/android/net/NetworkStatsHistory.java
            +++ b/core/java/android/net/NetworkStatsHistory.java
            @@ -30,7 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS;
             
             import static com.android.internal.util.ArrayUtils.total;
             
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.service.NetworkStatsHistoryBucketProto;
            diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
            index 87c7118c0e..5e6c47a47a 100644
            --- a/core/java/android/net/NetworkTemplate.java
            +++ b/core/java/android/net/NetworkTemplate.java
            @@ -34,7 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO;
             import static android.net.NetworkStats.ROAMING_YES;
             import static android.net.wifi.WifiInfo.removeDoubleQuotes;
             
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.util.BackupUtils;
            diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
            index bf4884aa96..162d6e27bd 100644
            --- a/core/java/android/net/TrafficStats.java
            +++ b/core/java/android/net/TrafficStats.java
            @@ -20,10 +20,10 @@ import android.annotation.NonNull;
             import android.annotation.SuppressLint;
             import android.annotation.SystemApi;
             import android.annotation.TestApi;
            -import android.annotation.UnsupportedAppUsage;
             import android.app.DownloadManager;
             import android.app.backup.BackupManager;
             import android.app.usage.NetworkStatsManager;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.content.Context;
             import android.media.MediaPlayer;
             import android.os.Build;
            
            From 2b30a23147d134924c7c23d91dce5669cda8ae76 Mon Sep 17 00:00:00 2001
            From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= 
            Date: Mon, 30 Dec 2019 11:41:41 -0800
            Subject: [PATCH 0689/1150] minor change to keep it building
            MIME-Version: 1.0
            Content-Type: text/plain; charset=UTF-8
            Content-Transfer-Encoding: 8bit
            
            This is part of 3 commits in 3 diff git repos, the main one is:
              https://android-review.googlesource.com/c/platform/system/netd/+/1200479
              "share eBPF struct definitions between ebpf and C++ netd"
            
            as a side effect of which 'android::bpf::Stats' becomes simply '::Stats'
            
            Test: builds
            Bug: 146787904
            Signed-off-by: Maciej Żenczykowski 
            Change-Id: I8548b27d1d8a7938f96c9fd9a185dae882e406f6
            ---
             services/core/jni/com_android_server_net_NetworkStatsService.cpp | 1 -
             1 file changed, 1 deletion(-)
            
            diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            index 4696dd0bb8..0275f3ea32 100644
            --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp
            @@ -33,7 +33,6 @@
             #include "bpf/BpfUtils.h"
             #include "netdbpf/BpfNetworkStats.h"
             
            -using android::bpf::Stats;
             using android::bpf::bpfGetUidStats;
             using android::bpf::bpfGetIfaceStats;
             
            
            From fb65456372ecc114eaefef4ef338119f1c6154c0 Mon Sep 17 00:00:00 2001
            From: markchien 
            Date: Fri, 6 Dec 2019 15:24:53 +0800
            Subject: [PATCH 0690/1150] Fix some @hide usage in Tethering
            
            Using alternative way to replace some @hide API.
            
            Bug: 144814072
            Test: build, flash, boot
                  atest TetheringTests
            
            Change-Id: I1e12d69db1ad91dff553e142e17c6a70808e1639
            ---
             .../net/util/TetheringMessageBase.java        | 25 +++++++++++++++++++
             1 file changed, 25 insertions(+)
             create mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java
            
            diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
            new file mode 100644
            index 0000000000..1b763ce920
            --- /dev/null
            +++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
            @@ -0,0 +1,25 @@
            +/*
            + * Copyright (C) 2020 The Android Open Source Project
            + *
            + * Licensed under the Apache License, Version 2.0 (the "License");
            + * you may not use this file except in compliance with the License.
            + * You may obtain a copy of the License at
            + *
            + *      http://www.apache.org/licenses/LICENSE-2.0
            + *
            + * Unless required by applicable law or agreed to in writing, software
            + * distributed under the License is distributed on an "AS IS" BASIS,
            + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
            + * See the License for the specific language governing permissions and
            + * limitations under the License.
            + */
            +package android.net.util;
            +
            +/**
            + * This class defines Message.what base addresses for various state machine.
            + */
            +public class TetheringMessageBase {
            +    public static final int BASE_MASTER   = 0;
            +    public static final int BASE_IPSERVER = 100;
            +
            +}
            
            From af1eb472bf2ec4d91a3efdcdb5475b02e3ca0f7b Mon Sep 17 00:00:00 2001
            From: Artur Satayev 
            Date: Tue, 10 Dec 2019 17:47:52 +0000
            Subject: [PATCH 0691/1150] Use new UnsupportedAppUsage annotation.
            
            Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library.
            
            Bug: 145132366
            Test: m && diff unsupportedappusage_index.csv
            Change-Id: I0c336de56bc4a041dc97ff9b7927f62f0b44b457
            Merged-In: I0c336de56bc4a041dc97ff9b7927f62f0b44b457
            ---
             core/java/android/net/EthernetManager.java     | 2 +-
             core/java/android/net/NetworkStats.java        | 2 +-
             core/java/android/net/NetworkStatsHistory.java | 2 +-
             core/java/android/net/NetworkTemplate.java     | 2 +-
             core/java/android/net/TrafficStats.java        | 2 +-
             5 files changed, 5 insertions(+), 5 deletions(-)
            
            diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java
            index 72565024d3..fd015b4fe5 100644
            --- a/core/java/android/net/EthernetManager.java
            +++ b/core/java/android/net/EthernetManager.java
            @@ -17,7 +17,7 @@
             package android.net;
             
             import android.annotation.SystemService;
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.content.Context;
             import android.os.Handler;
             import android.os.Message;
            diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
            index 6c7aa1379f..45bf4d2e13 100644
            --- a/core/java/android/net/NetworkStats.java
            +++ b/core/java/android/net/NetworkStats.java
            @@ -19,7 +19,7 @@ package android.net;
             import static android.os.Process.CLAT_UID;
             
             import android.annotation.NonNull;
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.os.SystemClock;
            diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
            index f61260ee3e..7b799e2624 100644
            --- a/core/java/android/net/NetworkStatsHistory.java
            +++ b/core/java/android/net/NetworkStatsHistory.java
            @@ -30,7 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS;
             
             import static com.android.internal.util.ArrayUtils.total;
             
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.service.NetworkStatsHistoryBucketProto;
            diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
            index 87c7118c0e..5e6c47a47a 100644
            --- a/core/java/android/net/NetworkTemplate.java
            +++ b/core/java/android/net/NetworkTemplate.java
            @@ -34,7 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO;
             import static android.net.NetworkStats.ROAMING_YES;
             import static android.net.wifi.WifiInfo.removeDoubleQuotes;
             
            -import android.annotation.UnsupportedAppUsage;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
             import android.util.BackupUtils;
            diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
            index bf4884aa96..162d6e27bd 100644
            --- a/core/java/android/net/TrafficStats.java
            +++ b/core/java/android/net/TrafficStats.java
            @@ -20,10 +20,10 @@ import android.annotation.NonNull;
             import android.annotation.SuppressLint;
             import android.annotation.SystemApi;
             import android.annotation.TestApi;
            -import android.annotation.UnsupportedAppUsage;
             import android.app.DownloadManager;
             import android.app.backup.BackupManager;
             import android.app.usage.NetworkStatsManager;
            +import android.compat.annotation.UnsupportedAppUsage;
             import android.content.Context;
             import android.media.MediaPlayer;
             import android.os.Build;
            
            From 5fa370c470095bba7ba1fb882bd398484261cd83 Mon Sep 17 00:00:00 2001
            From: evitayan 
            Date: Mon, 30 Dec 2019 16:05:38 -0800
            Subject: [PATCH 0692/1150] Allow mainline IPsec(IKE) to statically include
             @PolicyDirection
            
            @PolicyDirection was hidden API defined in IpSecManager and
            mainline module IPsec(IKE) needs to depend on it.
            
            To remove this hidden API dependency, this commit:
            - Moves definition of @PolicyDirection to a separate class
            - Creates sharing filegroup framework-ike-shared-srcs for mainline
              IKE and include PolicyDirection.java
            
            Bug: 146360859
            Test: build, flash, boot
            Test: atest FrameworksIkeTests
            Change-Id: Ic6d7c06d4b92e16a9a65430365c9acc73932147b
            ---
             core/java/android/net/IpSecManager.java | 9 +--------
             1 file changed, 1 insertion(+), 8 deletions(-)
            
            diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
            index 45d0c7313f..09ec6c35fc 100644
            --- a/core/java/android/net/IpSecManager.java
            +++ b/core/java/android/net/IpSecManager.java
            @@ -17,7 +17,6 @@ package android.net;
             
             import static com.android.internal.util.Preconditions.checkNotNull;
             
            -import android.annotation.IntDef;
             import android.annotation.NonNull;
             import android.annotation.RequiresFeature;
             import android.annotation.RequiresPermission;
            @@ -26,6 +25,7 @@ import android.annotation.SystemService;
             import android.annotation.TestApi;
             import android.content.Context;
             import android.content.pm.PackageManager;
            +import android.net.annotations.PolicyDirection;
             import android.os.Binder;
             import android.os.ParcelFileDescriptor;
             import android.os.RemoteException;
            @@ -41,8 +41,6 @@ import dalvik.system.CloseGuard;
             
             import java.io.FileDescriptor;
             import java.io.IOException;
            -import java.lang.annotation.Retention;
            -import java.lang.annotation.RetentionPolicy;
             import java.net.DatagramSocket;
             import java.net.InetAddress;
             import java.net.Socket;
            @@ -78,11 +76,6 @@ public final class IpSecManager {
                  */
                 public static final int DIRECTION_OUT = 1;
             
            -    /** @hide */
            -    @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
            -    @Retention(RetentionPolicy.SOURCE)
            -    public @interface PolicyDirection {}
            -
                 /**
                  * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index.
                  *
            
            From 10a00a2819ba7d371eea50d7ece07d20275c85c9 Mon Sep 17 00:00:00 2001
            From: junyulai 
            Date: Fri, 15 Nov 2019 17:15:01 +0800
            Subject: [PATCH 0693/1150] [SP01] Add NetworkStats to system API
            
            In order to let external module report their network stats,
            expose necessary APIs to construct NetworkStats object.
            
            Test: atest FrameworksNetTests CtsUsageStatsTestCases
            Test: m doc-comment-check-docs
            Bug: 130855321
            Change-Id: Id3ec8aaff3df67948c25eac2319a74cf33a27979
            ---
             core/java/android/net/NetworkStats.java       | 221 +++++++++++++++---
             core/java/android/net/TrafficStats.java       |   2 +-
             .../server/net/NetworkStatsFactory.java       |   6 +-
             .../server/net/NetworkStatsService.java       |  10 +-
             4 files changed, 194 insertions(+), 45 deletions(-)
            
            diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
            index 45bf4d2e13..96d7a80886 100644
            --- a/core/java/android/net/NetworkStats.java
            +++ b/core/java/android/net/NetworkStats.java
            @@ -19,6 +19,9 @@ package android.net;
             import static android.os.Process.CLAT_UID;
             
             import android.annotation.NonNull;
            +import android.annotation.Nullable;
            +import android.annotation.SuppressLint;
            +import android.annotation.SystemApi;
             import android.compat.annotation.UnsupportedAppUsage;
             import android.os.Parcel;
             import android.os.Parcelable;
            @@ -48,59 +51,104 @@ import java.util.function.Predicate;
              * @hide
              */
             // @NotThreadSafe
            -public class NetworkStats implements Parcelable {
            +@SystemApi
            +public final class NetworkStats implements Parcelable {
                 private static final String TAG = "NetworkStats";
            +
                 /** {@link #iface} value when interface details unavailable. */
            -    public static final String IFACE_ALL = null;
            +    @SuppressLint("CompileTimeConstant")
            +    @Nullable public static final String IFACE_ALL = null;
            +    /**
            +     * Virtual network interface for video telephony. This is for VT data usage counting
            +     * purpose.
            +     */
            +    public static final String IFACE_VT = "vt_data0";
            +
                 /** {@link #uid} value when UID details unavailable. */
                 public static final int UID_ALL = -1;
            -    /** {@link #tag} value matching any tag. */
            +    /** Special UID value for data usage by tethering. */
            +    public static final int UID_TETHERING = -5;
            +
            +    /**
            +     * {@link #tag} value matching any tag.
            +     * @hide
            +     */
                 // TODO: Rename TAG_ALL to TAG_ANY.
                 public static final int TAG_ALL = -1;
            -    /** {@link #set} value for all sets combined, not including debug sets. */
            +    /**
            +     * {@link #set} value for all sets combined, not including debug sets.
            +     * @hide
            +     */
                 public static final int SET_ALL = -1;
                 /** {@link #set} value where background data is accounted. */
                 public static final int SET_DEFAULT = 0;
                 /** {@link #set} value where foreground data is accounted. */
                 public static final int SET_FOREGROUND = 1;
            -    /** All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values. */
            +    /**
            +     * All {@link #set} value greater than SET_DEBUG_START are debug {@link #set} values.
            +     * @hide
            +     */
                 public static final int SET_DEBUG_START = 1000;
            -    /** Debug {@link #set} value when the VPN stats are moved in. */
            +    /**
            +     * Debug {@link #set} value when the VPN stats are moved in.
            +     * @hide
            +     */
                 public static final int SET_DBG_VPN_IN = 1001;
            -    /** Debug {@link #set} value when the VPN stats are moved out of a vpn UID. */
            +    /**
            +     * Debug {@link #set} value when the VPN stats are moved out of a vpn UID.
            +     * @hide
            +     */
                 public static final int SET_DBG_VPN_OUT = 1002;
             
            -    /** Include all interfaces when filtering */
            -    public static final String[] INTERFACES_ALL = null;
            +    /**
            +     * Include all interfaces when filtering
            +     * @hide
            +     */
            +    public @Nullable static final String[] INTERFACES_ALL = null;
             
                 /** {@link #tag} value for total data across all tags. */
                 // TODO: Rename TAG_NONE to TAG_ALL.
                 public static final int TAG_NONE = 0;
             
            -    /** {@link #metered} value to account for all metered states. */
            +    /**
            +     * {@link #metered} value to account for all metered states.
            +     * @hide
            +     */
                 public static final int METERED_ALL = -1;
                 /** {@link #metered} value where native, unmetered data is accounted. */
                 public static final int METERED_NO = 0;
                 /** {@link #metered} value where metered data is accounted. */
                 public static final int METERED_YES = 1;
             
            -    /** {@link #roaming} value to account for all roaming states. */
            +    /**
            +     * {@link #roaming} value to account for all roaming states.
            +     * @hide
            +     */
                 public static final int ROAMING_ALL = -1;
                 /** {@link #roaming} value where native, non-roaming data is accounted. */
                 public static final int ROAMING_NO = 0;
                 /** {@link #roaming} value where roaming data is accounted. */
                 public static final int ROAMING_YES = 1;
             
            -    /** {@link #onDefaultNetwork} value to account for all default network states. */
            +    /**
            +     * {@link #onDefaultNetwork} value to account for all default network states.
            +     * @hide
            +     */
                 public static final int DEFAULT_NETWORK_ALL = -1;
                 /** {@link #onDefaultNetwork} value to account for usage while not the default network. */
                 public static final int DEFAULT_NETWORK_NO = 0;
                 /** {@link #onDefaultNetwork} value to account for usage while the default network. */
                 public static final int DEFAULT_NETWORK_YES = 1;
             
            -    /** Denotes a request for stats at the interface level. */
            +    /**
            +     * Denotes a request for stats at the interface level.
            +     * @hide
            +     */
                 public static final int STATS_PER_IFACE = 0;
            -    /** Denotes a request for stats at the interface and UID level. */
            +    /**
            +     * Denotes a request for stats at the interface and UID level.
            +     * @hide
            +     */
                 public static final int STATS_PER_UID = 1;
             
                 private static final String CLATD_INTERFACE_PREFIX = "v4-";
            @@ -144,60 +192,78 @@ public class NetworkStats implements Parcelable {
                 @UnsupportedAppUsage
                 private long[] operations;
             
            +    /** @hide */
            +    @SystemApi
                 public static class Entry {
            +        /** @hide */
                     @UnsupportedAppUsage
                     public String iface;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public int uid;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public int set;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public int tag;
                     /**
                      * Note that this is only populated w/ the default value when read from /proc or written
                      * to disk. We merge in the correct value when reporting this value to clients of
                      * getSummary().
            +         * @hide
                      */
                     public int metered;
                     /**
                      * Note that this is only populated w/ the default value when read from /proc or written
                      * to disk. We merge in the correct value when reporting this value to clients of
                      * getSummary().
            +         * @hide
                      */
                     public int roaming;
                     /**
                      * Note that this is only populated w/ the default value when read from /proc or written
                      * to disk. We merge in the correct value when reporting this value to clients of
                      * getSummary().
            +         * @hide
                      */
                     public int defaultNetwork;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public long rxBytes;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public long rxPackets;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public long txBytes;
            +        /** @hide */
                     @UnsupportedAppUsage
                     public long txPackets;
            +        /** @hide */
            +        @UnsupportedAppUsage
                     public long operations;
             
            +        /** @hide */
                     @UnsupportedAppUsage
                     public Entry() {
                         this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L);
                     }
             
            +        /** @hide */
                     public Entry(long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
                         this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets,
                                 operations);
                     }
             
            +        /** @hide */
                     public Entry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets,
                             long txBytes, long txPackets, long operations) {
                         this(iface, uid, set, tag, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO,
                                 rxBytes, rxPackets, txBytes, txPackets, operations);
                     }
             
            -        public Entry(String iface, int uid, int set, int tag, int metered, int roaming,
            +        public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming,
                              int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
                              long operations) {
                         this.iface = iface;
            @@ -214,15 +280,18 @@ public class NetworkStats implements Parcelable {
                         this.operations = operations;
                     }
             
            +        /** @hide */
                     public boolean isNegative() {
                         return rxBytes < 0 || rxPackets < 0 || txBytes < 0 || txPackets < 0 || operations < 0;
                     }
             
            +        /** @hide */
                     public boolean isEmpty() {
                         return rxBytes == 0 && rxPackets == 0 && txBytes == 0 && txPackets == 0
                                 && operations == 0;
                     }
             
            +        /** @hide */
                     public void add(Entry another) {
                         this.rxBytes += another.rxBytes;
                         this.rxPackets += another.rxPackets;
            @@ -249,6 +318,7 @@ public class NetworkStats implements Parcelable {
                         return builder.toString();
                     }
             
            +        /** @hide */
                     @Override
                     public boolean equals(Object o) {
                         if (o instanceof Entry) {
            @@ -262,13 +332,13 @@ public class NetworkStats implements Parcelable {
                         return false;
                     }
             
            +        /** @hide */
                     @Override
                     public int hashCode() {
                         return Objects.hash(uid, set, tag, metered, roaming, defaultNetwork, iface);
                     }
                 }
             
            -    @UnsupportedAppUsage
                 public NetworkStats(long elapsedRealtime, int initialSize) {
                     this.elapsedRealtime = elapsedRealtime;
                     this.size = 0;
            @@ -292,6 +362,7 @@ public class NetworkStats implements Parcelable {
                     }
                 }
             
            +    /** @hide */
                 @UnsupportedAppUsage
                 public NetworkStats(Parcel parcel) {
                     elapsedRealtime = parcel.readLong();
            @@ -312,7 +383,7 @@ public class NetworkStats implements Parcelable {
                 }
             
                 @Override
            -    public void writeToParcel(Parcel dest, int flags) {
            +    public void writeToParcel(@NonNull Parcel dest, int flags) {
                     dest.writeLong(elapsedRealtime);
                     dest.writeInt(size);
                     dest.writeInt(capacity);
            @@ -330,19 +401,23 @@ public class NetworkStats implements Parcelable {
                     dest.writeLongArray(operations);
                 }
             
            +    /**
            +     * @hide
            +     */
                 @Override
                 public NetworkStats clone() {
                     final NetworkStats clone = new NetworkStats(elapsedRealtime, size);
                     NetworkStats.Entry entry = null;
                     for (int i = 0; i < size; i++) {
                         entry = getValues(i, entry);
            -            clone.addValues(entry);
            +            clone.addEntry(entry);
                     }
                     return clone;
                 }
             
                 /**
                  * Clear all data stored in this object.
            +     * @hide
                  */
                 public void clear() {
                     this.capacity = 0;
            @@ -360,25 +435,28 @@ public class NetworkStats implements Parcelable {
                     this.operations = EmptyArray.LONG;
                 }
             
            +    /** @hide */
                 @VisibleForTesting
                 public NetworkStats addIfaceValues(
                         String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) {
            -        return addValues(
            +        return addEntry(
                             iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L);
                 }
             
            +    /** @hide */
                 @VisibleForTesting
            -    public NetworkStats addValues(String iface, int uid, int set, int tag, long rxBytes,
            +    public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes,
                         long rxPackets, long txBytes, long txPackets, long operations) {
            -        return addValues(new Entry(
            +        return addEntry(new Entry(
                             iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations));
                 }
             
            +    /** @hide */
                 @VisibleForTesting
            -    public NetworkStats addValues(String iface, int uid, int set, int tag, int metered, int roaming,
            +    public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming,
                         int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets,
                         long operations) {
            -        return addValues(new Entry(
            +        return addEntry(new Entry(
                             iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets,
                             txBytes, txPackets, operations));
                 }
            @@ -386,8 +464,9 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Add new stats entry, copying from given {@link Entry}. The {@link Entry}
                  * object can be recycled across multiple calls.
            +     * @hide
                  */
            -    public NetworkStats addValues(Entry entry) {
            +    public NetworkStats addEntry(Entry entry) {
                     if (size >= capacity) {
                         final int newLength = Math.max(size, 10) * 3 / 2;
                         iface = Arrays.copyOf(iface, newLength);
            @@ -428,6 +507,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Return specific stats entry.
            +     * @hide
                  */
                 @UnsupportedAppUsage
                 public Entry getValues(int i, Entry recycle) {
            @@ -467,10 +547,12 @@ public class NetworkStats implements Parcelable {
                     operations[dest] = operations[src];
                 }
             
            +    /** @hide */
                 public long getElapsedRealtime() {
                     return elapsedRealtime;
                 }
             
            +    /** @hide */
                 public void setElapsedRealtime(long time) {
                     elapsedRealtime = time;
                 }
            @@ -478,21 +560,25 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Return age of this {@link NetworkStats} object with respect to
                  * {@link SystemClock#elapsedRealtime()}.
            +     * @hide
                  */
                 public long getElapsedRealtimeAge() {
                     return SystemClock.elapsedRealtime() - elapsedRealtime;
                 }
             
            +    /** @hide */
                 @UnsupportedAppUsage
                 public int size() {
                     return size;
                 }
             
            +    /** @hide */
                 @VisibleForTesting
                 public int internalSize() {
                     return capacity;
                 }
             
            +    /** @hide */
                 @Deprecated
                 public NetworkStats combineValues(String iface, int uid, int tag, long rxBytes, long rxPackets,
                         long txBytes, long txPackets, long operations) {
            @@ -501,6 +587,7 @@ public class NetworkStats implements Parcelable {
                             txPackets, operations);
                 }
             
            +    /** @hide */
                 public NetworkStats combineValues(String iface, int uid, int set, int tag,
                         long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) {
                     return combineValues(new Entry(
            @@ -509,16 +596,20 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Combine given values with an existing row, or create a new row if
            -     * {@link #findIndex(String, int, int, int, int)} is unable to find match. Can
            -     * also be used to subtract values from existing rows.
            +     * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
            +     * also be used to subtract values from existing rows. This method mutates the referencing
            +     * {@link NetworkStats} object.
            +     *
            +     * @param entry the {@link Entry} to combine.
            +     * @return a reference to this mutated {@link NetworkStats} object.
            +     * @hide
                  */
            -    @UnsupportedAppUsage
            -    public NetworkStats combineValues(Entry entry) {
            +    public @NonNull NetworkStats combineValues(@NonNull Entry entry) {
                     final int i = findIndex(entry.iface, entry.uid, entry.set, entry.tag, entry.metered,
                             entry.roaming, entry.defaultNetwork);
                     if (i == -1) {
                         // only create new entry when positive contribution
            -            addValues(entry);
            +            addEntry(entry);
                     } else {
                         rxBytes[i] += entry.rxBytes;
                         rxPackets[i] += entry.rxPackets;
            @@ -530,10 +621,33 @@ public class NetworkStats implements Parcelable {
                 }
             
                 /**
            -     * Combine all values from another {@link NetworkStats} into this object.
            +     * Add given values with an existing row, or create a new row if
            +     * {@link #findIndex(String, int, int, int, int, int, int)} is unable to find match. Can
            +     * also be used to subtract values from existing rows.
            +     *
            +     * @param entry the {@link Entry} to add.
            +     * @return a new constructed {@link NetworkStats} object that contains the result.
                  */
            -    @UnsupportedAppUsage
            -    public void combineAllValues(NetworkStats another) {
            +    public @NonNull NetworkStats addValues(@NonNull Entry entry) {
            +        return this.clone().combineValues(entry);
            +    }
            +
            +    /**
            +     * Add the given {@link NetworkStats} objects.
            +     *
            +     * @return the sum of two objects.
            +     */
            +    public @NonNull NetworkStats add(@NonNull NetworkStats another) {
            +        final NetworkStats ret = this.clone();
            +        ret.combineAllValues(another);
            +        return ret;
            +    }
            +
            +    /**
            +     * Combine all values from another {@link NetworkStats} into this object.
            +     * @hide
            +     */
            +    public void combineAllValues(@NonNull NetworkStats another) {
                     NetworkStats.Entry entry = null;
                     for (int i = 0; i < another.size; i++) {
                         entry = another.getValues(i, entry);
            @@ -543,6 +657,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Find first stats index that matches the requested parameters.
            +     * @hide
                  */
                 public int findIndex(String iface, int uid, int set, int tag, int metered, int roaming,
                         int defaultNetwork) {
            @@ -560,6 +675,7 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Find first stats index that matches the requested parameters, starting
                  * search around the hinted index as an optimization.
            +     * @hide
                  */
                 @VisibleForTesting
                 public int findIndexHinted(String iface, int uid, int set, int tag, int metered, int roaming,
            @@ -589,6 +705,7 @@ public class NetworkStats implements Parcelable {
                  * Splice in {@link #operations} from the given {@link NetworkStats} based
                  * on matching {@link #uid} and {@link #tag} rows. Ignores {@link #iface},
                  * since operation counts are at data layer.
            +     * @hide
                  */
                 public void spliceOperationsFrom(NetworkStats stats) {
                     for (int i = 0; i < size; i++) {
            @@ -604,6 +721,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Return list of unique interfaces known by this data structure.
            +     * @hide
                  */
                 public String[] getUniqueIfaces() {
                     final HashSet ifaces = new HashSet();
            @@ -617,6 +735,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Return list of unique UIDs known by this data structure.
            +     * @hide
                  */
                 @UnsupportedAppUsage
                 public int[] getUniqueUids() {
            @@ -636,6 +755,7 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Return total bytes represented by this snapshot object, usually used when
                  * checking if a {@link #subtract(NetworkStats)} delta passes a threshold.
            +     * @hide
                  */
                 @UnsupportedAppUsage
                 public long getTotalBytes() {
            @@ -645,6 +765,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Return total of all fields represented by this snapshot object.
            +     * @hide
                  */
                 @UnsupportedAppUsage
                 public Entry getTotal(Entry recycle) {
            @@ -654,6 +775,7 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Return total of all fields represented by this snapshot object matching
                  * the requested {@link #uid}.
            +     * @hide
                  */
                 @UnsupportedAppUsage
                 public Entry getTotal(Entry recycle, int limitUid) {
            @@ -663,11 +785,13 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Return total of all fields represented by this snapshot object matching
                  * the requested {@link #iface}.
            +     * @hide
                  */
                 public Entry getTotal(Entry recycle, HashSet limitIface) {
                     return getTotal(recycle, limitIface, UID_ALL, false);
                 }
             
            +    /** @hide */
                 @UnsupportedAppUsage
                 public Entry getTotalIncludingTags(Entry recycle) {
                     return getTotal(recycle, null, UID_ALL, true);
            @@ -717,6 +841,7 @@ public class NetworkStats implements Parcelable {
             
                 /**
                  * Fast path for battery stats.
            +     * @hide
                  */
                 public long getTotalPackets() {
                     long total = 0;
            @@ -729,9 +854,12 @@ public class NetworkStats implements Parcelable {
                 /**
                  * Subtract the given {@link NetworkStats}, effectively leaving the delta
                  * between two snapshots in time. Assumes that statistics rows collect over
            -     * time, and that none of them have disappeared.
            +     * time, and that none of them have disappeared. This method does not mutate
            +     * the referencing object.
            +     *
            +     * @return the delta between two objects.
                  */
            -    public NetworkStats subtract(NetworkStats right) {
            +    public @NonNull NetworkStats subtract(@NonNull NetworkStats right) {
                     return subtract(this, right, null, null);
                 }
             
            @@ -742,6 +870,7 @@ public class NetworkStats implements Parcelable {
                  * 

            * If counters have rolled backwards, they are clamped to {@code 0} and * reported to the given {@link NonMonotonicObserver}. + * @hide */ public static NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver observer, C cookie) { @@ -759,6 +888,7 @@ public class NetworkStats implements Parcelable { * If recycle is supplied, this NetworkStats object will be * reused (and returned) as the result if it is large enough to contain * the data. + * @hide */ public static NetworkStats subtract(NetworkStats left, NetworkStats right, NonMonotonicObserver observer, C cookie, NetworkStats recycle) { @@ -817,7 +947,7 @@ public class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addValues(entry); + result.addEntry(entry); } return result; @@ -847,6 +977,7 @@ public class NetworkStats implements Parcelable { * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @param useBpfStats True if eBPF is in use. + * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { @@ -899,6 +1030,7 @@ public class NetworkStats implements Parcelable { * {@link #apply464xlatAdjustments(NetworkStats, NetworkStats, Map)} with {@code this} as * base and stacked traffic. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. + * @hide */ public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); @@ -907,6 +1039,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #iface}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByIface() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -938,6 +1071,7 @@ public class NetworkStats implements Parcelable { /** * Return total statistics grouped by {@link #uid}; doesn't mutate the * original structure. + * @hide */ public NetworkStats groupedByUid() { final NetworkStats stats = new NetworkStats(elapsedRealtime, 10); @@ -968,6 +1102,7 @@ public class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * @hide */ public void removeUids(int[] uids) { int nextOutputEntry = 0; @@ -989,6 +1124,7 @@ public class NetworkStats implements Parcelable { * @param limitUid UID to filter for, or {@link #UID_ALL}. * @param limitIfaces Interfaces to filter for, or {@link #INTERFACES_ALL}. * @param limitTag Tag to filter for, or {@link #TAG_ALL}. + * @hide */ public void filter(int limitUid, String[] limitIfaces, int limitTag) { if (limitUid == UID_ALL && limitTag == TAG_ALL && limitIfaces == INTERFACES_ALL) { @@ -1004,6 +1140,7 @@ public class NetworkStats implements Parcelable { * Only keep entries with {@link #set} value less than {@link #SET_DEBUG_START}. * *

            This mutates the original structure in place. + * @hide */ public void filterDebugEntries() { filter(e -> e.set < SET_DEBUG_START); @@ -1024,6 +1161,7 @@ public class NetworkStats implements Parcelable { size = nextOutputEntry; } + /** @hide */ public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("NetworkStats: elapsedRealtime="); pw.println(elapsedRealtime); @@ -1047,6 +1185,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToString(int set) { switch (set) { @@ -1067,6 +1206,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #set} value. + * @hide */ public static String setToCheckinString(int set) { switch (set) { @@ -1087,6 +1227,7 @@ public class NetworkStats implements Parcelable { /** * @return true if the querySet matches the dataSet. + * @hide */ public static boolean setMatches(int querySet, int dataSet) { if (querySet == dataSet) { @@ -1098,6 +1239,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #tag} value. + * @hide */ public static String tagToString(int tag) { return "0x" + Integer.toHexString(tag); @@ -1105,6 +1247,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #metered} value. + * @hide */ public static String meteredToString(int metered) { switch (metered) { @@ -1121,6 +1264,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #roaming} value. + * @hide */ public static String roamingToString(int roaming) { switch (roaming) { @@ -1137,6 +1281,7 @@ public class NetworkStats implements Parcelable { /** * Return text description of {@link #defaultNetwork} value. + * @hide */ public static String defaultNetworkToString(int defaultNetwork) { switch (defaultNetwork) { @@ -1151,6 +1296,7 @@ public class NetworkStats implements Parcelable { } } + /** @hide */ @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); @@ -1163,8 +1309,7 @@ public class NetworkStats implements Parcelable { return 0; } - @UnsupportedAppUsage - public static final @android.annotation.NonNull Creator CREATOR = new Creator() { + public static final @NonNull Creator CREATOR = new Creator() { @Override public NetworkStats createFromParcel(Parcel in) { return new NetworkStats(in); @@ -1176,6 +1321,7 @@ public class NetworkStats implements Parcelable { } }; + /** @hide */ public interface NonMonotonicObserver { public void foundNonMonotonic( NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie); @@ -1195,6 +1341,7 @@ public class NetworkStats implements Parcelable { * @param tunUid uid of the VPN application * @param tunIface iface of the vpn tunnel * @param underlyingIfaces underlying network ifaces used by the VPN application + * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, @NonNull String[] underlyingIfaces) { diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 162d6e27bd..8108cf08d5 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -89,7 +89,7 @@ public class TrafficStats { * * @hide */ - public static final int UID_TETHERING = -5; + public static final int UID_TETHERING = NetworkStats.UID_TETHERING; /** * Tag values in this range are reserved for the network stack. The network stack is diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3ca1803262..22b01bee6c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addValues(entry); + stats.addEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addValues(entry); + stats.addEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a41fb7d327..a80fc05802 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,7 @@ import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; +import static android.net.NetworkStats.IFACE_VT; import static android.net.NetworkStats.INTERFACES_ALL; import static android.net.NetworkStats.METERED_ALL; import static android.net.NetworkStats.ROAMING_ALL; @@ -211,7 +212,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Virtual network interface for video telephony. This is for VT data usage counting purpose. */ - public static final String VT_INTERFACE = "vt_data0"; + // TODO: Remove this after no one is using it. + public static final String VT_INTERFACE = NetworkStats.IFACE_VT; /** * Settings that can be changed externally. @@ -712,7 +714,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addValues(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; @@ -1179,8 +1181,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */); - findOrCreateNetworkIdentitySet(mActiveIfaces, VT_INTERFACE).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, VT_INTERFACE).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } if (isMobile) { From 84b2c43b56a19b176b0d78757083aee64e2e9c18 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 18 Nov 2019 18:10:39 +0800 Subject: [PATCH 0694/1150] [SP02] Add provider interfaces to system API This change contains a base class that allows external modules to implement a custom network statistics provider. And a callback interface that allows the implementation to signal the system. These interfaces will be used in the follow-up changes that implement the functionality. Test: atest FrameworksNetTests CtsUsageStatsTestCases Test: m doc-comment-check-docs Bug: 130855321 Change-Id: Ib23377c8b9cef02bc32253462b068fd10734d21a --- .../provider/INetworkStatsProvider.aidl | 28 +++++++++++++++++ .../INetworkStatsProviderCallback.aidl | 31 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 core/java/android/net/netstats/provider/INetworkStatsProvider.aidl create mode 100644 core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl new file mode 100644 index 0000000000..55b3d4edb1 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +/** + * Interface for NetworkStatsService to query network statistics and set data limits. + * + * @hide + */ +oneway interface INetworkStatsProvider { + void requestStatsUpdate(int token); + void setLimit(String iface, long quotaBytes); + void setAlert(long quotaBytes); +} diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl new file mode 100644 index 0000000000..3ea9318f10 --- /dev/null +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.net.NetworkStats; + +/** + * Interface for implementor of {@link INetworkStatsProviderCallback} to push events + * such as network statistics update or notify limit reached. + * @hide + */ +oneway interface INetworkStatsProviderCallback { + void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void onAlertReached(); + void onLimitReached(); + void unregister(); +} From 3d5d3b32af5ccb70f010b9bb87b5d6b190c02933 Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:51 +0000 Subject: [PATCH 0695/1150] Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I8789f8499d4dca08580672e9e45ed9a7026dd686 Merged-In: I8789f8499d4dca08580672e9e45ed9a7026dd686 --- core/java/android/app/usage/NetworkStatsManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 6bade90182..74129702b4 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -21,8 +21,8 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; -import android.annotation.UnsupportedAppUsage; import android.app.usage.NetworkStats.Bucket; +import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; From 892e3bf7b6b253dc3c09416abce915f3e766c9f6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 13 Jan 2020 14:36:55 +0800 Subject: [PATCH 0696/1150] [SP03.1] Replace com.android.internal.util.Preconditions.checkNotNull Extracted from ag/9990011 to make NetworkStatsManager sync with internal line, given that it is missing in aosp/1198084. Bug: 126528330 Test: Treehugger Change-Id: I77f50326869799f51d4636cb7c6d7c97daf531e6 Merged-In: I42117ebfb640e3b0b133183e5e146860bed8471a --- core/java/android/app/usage/NetworkStatsManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 74129702b4..4346d9738e 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,8 +16,6 @@ package android.app.usage; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.Nullable; import android.annotation.SystemService; import android.annotation.TestApi; @@ -42,6 +40,8 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import java.util.Objects; + /** * Provides access to network usage history and statistics. Usage data is collected in * discrete bins of time called 'Buckets'. See {@link NetworkStats.Bucket} for details. @@ -418,7 +418,7 @@ public class NetworkStatsManager { /** @hide */ public void registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { - checkNotNull(callback, "UsageCallback cannot be null"); + Objects.requireNonNull(callback, "UsageCallback cannot be null"); final Looper looper; if (handler == null) { From b3f085c5a86f4284dffb8831109b8a956960ea2b Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 21 Nov 2019 16:26:27 +0800 Subject: [PATCH 0697/1150] [SP03] support registerNetworkStatsProvider API This change provides an API that allow external modules to register a custom provider of NetworkStats to merge the network statistics that cannot be seen by the kernel to system. Test: atest FrameworksNetTests CtsUsageStatsTestCases Test: atest NetworkPolicyManagerServiceTest Test: m doc-comment-check-docs Bug: 130855321 Change-Id: I265bc637c40666cde505fde5056d2d9bfc5fb204 --- .../app/usage/NetworkStatsManager.java | 34 ++++ .../android/net/INetworkStatsService.aidl | 5 + .../server/net/NetworkStatsService.java | 192 +++++++++++++++++- 3 files changed, 225 insertions(+), 6 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 4346d9738e..9c4a8f4fbe 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,7 +16,10 @@ package android.app.usage; +import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.app.usage.NetworkStats.Bucket; @@ -27,6 +30,9 @@ import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkTemplate; +import android.net.netstats.provider.AbstractNetworkStatsProvider; +import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProviderWrapper; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -519,6 +525,34 @@ public class NetworkStatsManager { private DataUsageRequest request; } + /** + * Registers a custom provider of {@link android.net.NetworkStats} to combine the network + * statistics that cannot be seen by the kernel to system. To unregister, invoke + * {@link NetworkStatsProviderCallback#unregister()}. + * + * @param tag a human readable identifier of the custom network stats provider. + * @param provider a custom implementation of {@link AbstractNetworkStatsProvider} that needs to + * be registered to the system. + * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the + * system. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull String tag, + @NonNull AbstractNetworkStatsProvider provider) { + try { + final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); + return new NetworkStatsProviderCallback( + mService.registerNetworkStatsProvider(tag, wrapper)); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + // Unreachable code, but compiler doesn't know about it. + return null; + } + private static NetworkTemplate createTemplate(int networkType, String subscriberId) { final NetworkTemplate template; switch (networkType) { diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 9994f9f82b..5fa515a143 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,6 +23,8 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.netstats.provider.INetworkStatsProvider; +import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; import android.os.Messenger; import com.android.internal.net.VpnInfo; @@ -89,4 +91,7 @@ interface INetworkStatsService { /** Get the total network stats information since boot */ long getTotalStats(int type); + /** Registers a network stats provider */ + INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, + in INetworkStatsProvider provider); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a80fc05802..29a3974df9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -18,6 +18,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; +import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; @@ -71,6 +72,7 @@ import static com.android.server.NetworkManagementSocketTagger.resetKernelUidSta import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -97,6 +99,9 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.net.netstats.provider.INetworkStatsProvider; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProviderCallback; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -109,6 +114,7 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; +import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -248,6 +254,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private final Object mStatsLock = new Object(); + private final Object mStatsProviderLock = new Object(); /** Set of currently active ifaces. */ @GuardedBy("mStatsLock") @@ -272,6 +279,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); + private final RemoteCallbackList mStatsProviderCbList = + new RemoteCallbackList<>(); + @GuardedBy("mStatsLock") private NetworkStatsRecorder mDevRecorder; @GuardedBy("mStatsLock") @@ -502,9 +512,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Register for a global alert that is delivered through - * {@link INetworkManagementEventObserver} once a threshold amount of data - * has been transferred. + * Register for a global alert that is delivered through {@link INetworkManagementEventObserver} + * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has + * been transferred. */ private void registerGlobalAlert() { try { @@ -514,6 +524,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); } @Override @@ -803,8 +814,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void incrementOperationCount(int uid, int tag, int operationCount) { if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.UPDATE_DEVICE_STATS, TAG); + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); } if (operationCount < 0) { @@ -1095,7 +1105,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Observer that watches for {@link INetworkManagementService} alerts. */ - private INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { + private final INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us @@ -1252,6 +1262,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { xtSnapshot.combineAllValues(tetherSnapshot); devSnapshot.combineAllValues(tetherSnapshot); + // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data + // from stats providers that isn't already counted by dev and XT stats. + Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); + final NetworkStats providersnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); + Trace.traceEnd(TRACE_TAG_NETWORK); + xtSnapshot.combineAllValues(providersnapshot); + devSnapshot.combineAllValues(providersnapshot); + // For xt/dev, we pass a null VPN array because usage is aggregated by UID, so VPN traffic // can't be reattributed to responsible apps. Trace.traceBegin(TRACE_TAG_NETWORK, "recordDev"); @@ -1355,6 +1373,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performSampleLocked(); } + // request asynchronous stats update from all providers for next poll. + // TODO: request with a valid token. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -1476,6 +1498,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void forceUpdate() { NetworkStatsService.this.forceUpdate(); } + + @Override + public void setStatsProviderLimit(@NonNull String iface, long quota) { + Slog.v(TAG, "setStatsProviderLimit(" + iface + "," + quota + ")"); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + } } @Override @@ -1690,6 +1718,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { uidSnapshot.combineAllValues(vtStats); } + // get a stale copy of uid stats snapshot provided by providers. + final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); + providerStats.filter(UID_ALL, ifaces, TAG_ALL); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats, mUseBpfTrafficStats); + uidSnapshot.combineAllValues(providerStats); + uidSnapshot.combineAllValues(mUidOperations); return uidSnapshot; @@ -1726,6 +1760,152 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + /** + * Registers a custom provider of {@link android.net.NetworkStats} to combine the network + * statistics that cannot be seen by the kernel to system. To unregister, invoke the + * {@code unregister()} of the returned callback. + * + * @param tag a human readable identifier of the custom network stats provider. + * @param provider the binder interface of + * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} that + * needs to be registered to the system. + * + * @return a binder interface of + * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be + * used to report events to the system. + */ + public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull String tag, @NonNull INetworkStatsProvider provider) { + mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + Objects.requireNonNull(provider, "provider is null"); + Objects.requireNonNull(tag, "tag is null"); + try { + NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( + tag, provider, mAlertObserver, mStatsProviderCbList); + mStatsProviderCbList.register(callback); + Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + + getCallingUid() + "/" + getCallingPid()); + return callback; + } catch (RemoteException e) { + Log.e(TAG, "registerNetworkStatsProvider failed", e); + } + return null; + } + + // Collect stats from local cache of providers. + private @NonNull NetworkStats getNetworkStatsFromProviders(int how) { + final NetworkStats ret = new NetworkStats(0L, 0); + invokeForAllStatsProviderCallbacks((cb) -> ret.combineAllValues(cb.getCachedStats(how))); + return ret; + } + + @FunctionalInterface + private interface ThrowingConsumer { + void accept(S s) throws T; + } + + private void invokeForAllStatsProviderCallbacks( + @NonNull ThrowingConsumer task) { + synchronized (mStatsProviderCbList) { + final int length = mStatsProviderCbList.beginBroadcast(); + try { + for (int i = 0; i < length; i++) { + final NetworkStatsProviderCallbackImpl cb = + mStatsProviderCbList.getBroadcastItem(i); + try { + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); + } + } + } finally { + mStatsProviderCbList.finishBroadcast(); + } + } + } + + private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub + implements IBinder.DeathRecipient { + @NonNull final String mTag; + @NonNull private final Object mProviderStatsLock = new Object(); + @NonNull final INetworkStatsProvider mProvider; + @NonNull final INetworkManagementEventObserver mAlertObserver; + @NonNull final RemoteCallbackList mStatsProviderCbList; + + @GuardedBy("mProviderStatsLock") + // STATS_PER_IFACE and STATS_PER_UID + private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); + @GuardedBy("mProviderStatsLock") + private final NetworkStats mUidStats = new NetworkStats(0L, 0); + + NetworkStatsProviderCallbackImpl( + @NonNull String tag, @NonNull INetworkStatsProvider provider, + @NonNull INetworkManagementEventObserver alertObserver, + @NonNull RemoteCallbackList cbList) + throws RemoteException { + mTag = tag; + mProvider = provider; + mProvider.asBinder().linkToDeath(this, 0); + mAlertObserver = alertObserver; + mStatsProviderCbList = cbList; + } + + @NonNull + public NetworkStats getCachedStats(int how) { + synchronized (mProviderStatsLock) { + NetworkStats stats; + switch (how) { + case STATS_PER_IFACE: + stats = mIfaceStats; + break; + case STATS_PER_UID: + stats = mUidStats; + break; + default: + throw new IllegalArgumentException("Invalid type: " + how); + } + // Return a defensive copy instead of local reference. + return stats.clone(); + } + } + + @Override + public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + @Nullable NetworkStats uidStats) { + // TODO: 1. Use token to map ifaces to correct NetworkIdentity. + // 2. Store the difference and store it directly to the recorder. + synchronized (mProviderStatsLock) { + if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); + if (uidStats != null) mUidStats.combineAllValues(uidStats); + } + } + + @Override + public void onAlertReached() throws RemoteException { + mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); + } + + @Override + public void onLimitReached() { + Log.d(TAG, mTag + ": onLimitReached"); + LocalServices.getService(NetworkPolicyManagerInternal.class) + .onStatsProviderLimitReached(mTag); + } + + @Override + public void binderDied() { + Log.d(TAG, mTag + ": binderDied"); + mStatsProviderCbList.unregister(this); + } + + @Override + public void unregister() { + Log.d(TAG, mTag + ": unregister"); + mStatsProviderCbList.unregister(this); + } + + } + @VisibleForTesting static class HandlerCallback implements Handler.Callback { private final NetworkStatsService mService; From c215221f567e5a0d6aebe12c8a6d223f614507e5 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 22 Nov 2019 22:27:21 +0800 Subject: [PATCH 0698/1150] [SP04] add unit test for NetworkStatsProvider Test: atest NetworkStatsServiceTest Bug: 130855321 Change-Id: I0c19d8bedcb9398da3f464efe01e775fde9f8a78 --- .../java/com/android/server/net/NetworkStatsService.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 29a3974df9..fc39a253bc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -182,7 +182,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * This avoids firing the global alert too often on devices with high transfer speeds and * high quota. */ - private static final int PERFORM_POLL_DELAY_MS = 1000; + private static final int DEFAULT_PERFORM_POLL_DELAY_MS = 1000; private static final String TAG_NETSTATS_ERROR = "netstats_error"; @@ -226,6 +226,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public interface NetworkStatsSettings { public long getPollInterval(); + public long getPollDelay(); public boolean getSampleEnabled(); public boolean getAugmentEnabled(); @@ -1116,7 +1117,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // such a call pending; UID stats are handled during normal polling interval. if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, - PERFORM_POLL_DELAY_MS); + mSettings.getPollDelay()); } } } @@ -1995,6 +1996,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); } @Override + public long getPollDelay() { + return DEFAULT_PERFORM_POLL_DELAY_MS; + } + @Override public long getGlobalAlertBytes(long def) { return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); } From ea0a0c347f5eb629d4d9195dadda029dabc8364c Mon Sep 17 00:00:00 2001 From: Artur Satayev Date: Tue, 10 Dec 2019 17:47:53 +0000 Subject: [PATCH 0699/1150] Use new UnsupportedAppUsage annotation. Existing annotations in libcore/ and frameworks/ will deleted after the migration. This also means that any java library that compiles @UnsupportedAppUsage requires a direct dependency on "unsupportedappusage" java_library. Bug: 145132366 Test: m && diff unsupportedappusage_index.csv Change-Id: I534e3fd1305e2f4af076986770033478448a665c Merged-In: I534e3fd1305e2f4af076986770033478448a665c --- core/java/android/net/nsd/NsdServiceInfo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/core/java/android/net/nsd/NsdServiceInfo.java index 459b140980..0946499f16 100644 --- a/core/java/android/net/nsd/NsdServiceInfo.java +++ b/core/java/android/net/nsd/NsdServiceInfo.java @@ -17,13 +17,13 @@ package android.net.nsd; import android.annotation.NonNull; -import android.annotation.UnsupportedAppUsage; -import android.os.Parcelable; +import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; +import android.os.Parcelable; import android.text.TextUtils; +import android.util.ArrayMap; import android.util.Base64; import android.util.Log; -import android.util.ArrayMap; import java.io.UnsupportedEncodingException; import java.net.InetAddress; From b8c3a054d5043d5c6c5512409d70105acf5a4a45 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Jan 2020 20:22:17 +0800 Subject: [PATCH 0700/1150] Move DnsSdTxtRecord to net common static library DnsSdTxtRecord is moved to frameworks/libs/net for mainline support. Also change the import path using this class. Bug: 139268426 Bug: 135998869 Test: atest FrameworksNetTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I6118b313ce668707d598aa2eab9baee2f7622dbc --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index b9b7bf73c1..4a1820a8e5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -22,10 +22,10 @@ import android.content.Intent; import android.database.ContentObserver; import android.net.NetworkStack; import android.net.Uri; -import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; From 1b031a2900896e4ab172b1b6bfccc762d562a515 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 13 Jan 2020 14:16:01 -0800 Subject: [PATCH 0701/1150] NetworkStatsFactory.cpp: IWYU Bug: 140330870 Test: N/A Change-Id: Id6107c8a83b22ac56f4da61a5d5757d29ecb07ac --- services/core/jni/com_android_server_net_NetworkStatsFactory.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp index 9cd743b346..8b6526ff49 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include From 004a9039c29c473aa5a4ac4dfdbb5058380dc2a4 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 10 Jan 2020 13:57:07 +0800 Subject: [PATCH 0702/1150] [SP11] add dumpsys support to dump stats inside providers Sample output is like below: Stats Providers: OffloadController Xt: NetworkStats: ... OffloadController Uid: NetworkStats: ... ImsPhoneCallTracker Xt: NetworkStats: ... Test: adb shell dumpsys netstats (--uid) Bug: 130855321 Change-Id: I968006de83e13e66bb3359135f0237daf7252bd2 --- .../android/server/net/NetworkStatsService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index fc39a253bc..415ccb8fe8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1610,6 +1610,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { pw.decreaseIndent(); pw.println(); + pw.println("Stats Providers:"); + pw.increaseIndent(); + invokeForAllStatsProviderCallbacks((cb) -> { + pw.println(cb.mTag + " Xt:"); + pw.increaseIndent(); + pw.print(cb.getCachedStats(STATS_PER_IFACE).toString()); + pw.decreaseIndent(); + if (includeUid) { + pw.println(cb.mTag + " Uid:"); + pw.increaseIndent(); + pw.print(cb.getCachedStats(STATS_PER_UID).toString()); + pw.decreaseIndent(); + } + }); + pw.decreaseIndent(); + pw.println("Dev stats:"); pw.increaseIndent(); mDevRecorder.dumpLocked(pw, fullHistory); From 815e0fde8704ccb85c85c92f72756ac1e4dab563 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 24 Jan 2020 19:29:17 +0900 Subject: [PATCH 0703/1150] Support putting one Ethernet interface in server mode. requestTetheredInterface can be used to put an interface in server mode, which will persist until release() is called on the returned request, or until the requesting process dies. Test: Enabled ethernet tethering with change on top Bug: 130840861 Change-Id: Id96d581acb3fa4e52ca62dd94ec257f56bd3a1ce --- core/java/android/net/EthernetManager.java | 78 ++++++++++++++++++- core/java/android/net/IEthernetManager.aidl | 3 + .../net/ITetheredInterfaceCallback.aidl | 23 ++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 core/java/android/net/ITetheredInterfaceCallback.aidl diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index fd015b4fe5..95000f5744 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.NonNull; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -24,6 +25,7 @@ import android.os.Message; import android.os.RemoteException; import java.util.ArrayList; +import java.util.Objects; /** * A class representing the IP configuration of the Ethernet network. @@ -37,7 +39,7 @@ public class EthernetManager { private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MSG_AVAILABILITY_CHANGED) { @@ -180,4 +182,78 @@ public class EthernetManager { } } } + + /** + * A request for a tethered interface. + */ + public static class TetheredInterfaceRequest { + private final IEthernetManager mService; + private final ITetheredInterfaceCallback mCb; + + private TetheredInterfaceRequest(@NonNull IEthernetManager service, + @NonNull ITetheredInterfaceCallback cb) { + this.mService = service; + this.mCb = cb; + } + + /** + * Release the request, causing the interface to revert back from tethering mode if there + * is no other requestor. + */ + public void release() { + try { + mService.releaseTetheredInterface(mCb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + /** + * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. + */ + public interface TetheredInterfaceCallback { + /** + * Called when the tethered interface is available. + * @param iface The name of the interface. + */ + void onAvailable(@NonNull String iface); + + /** + * Called when the tethered interface is now unavailable. + */ + void onUnavailable(); + } + + /** + * Request a tethered interface in tethering mode. + * + *

            When this method is called and there is at least one ethernet interface available, the + * system will designate one to act as a tethered interface. If there is already a tethered + * interface, the existing interface will be used. + * @param callback A callback to be called once the request has been fulfilled. + */ + @NonNull + public TetheredInterfaceRequest requestTetheredInterface( + @NonNull TetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "Callback must be non-null"); + final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { + @Override + public void onAvailable(String iface) { + callback.onAvailable(iface); + } + + @Override + public void onUnavailable() { + callback.onUnavailable(); + } + }; + + try { + mService.requestTetheredInterface(cbInternal); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return new TetheredInterfaceRequest(mService, cbInternal); + } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 94960b51d3..ccc6e35209 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; /** * Interface that answers queries about, and allows changing @@ -32,4 +33,6 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void requestTetheredInterface(in ITetheredInterfaceCallback callback); + void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl new file mode 100644 index 0000000000..e3d075988c --- /dev/null +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +interface ITetheredInterfaceCallback { + void onAvailable(in String iface); + void onUnavailable(); +} \ No newline at end of file From 355e6f0692902bb439f605b28a8f4d58df8b5544 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 24 Jan 2020 22:57:09 +0900 Subject: [PATCH 0704/1150] Add support for Ethernet tethering Ethernet tethering can be started via startTethering(TETHERING_ETHERNET). Test: flashed, enabled ethernet tethering, verified internet access on downstream. Bug: 130840861 Change-Id: I34842acd94b972e440c3622f7617df10c18acf65 --- core/java/android/net/EthernetManager.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 95000f5744..a3899b705c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,9 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; @@ -32,6 +34,8 @@ import java.util.Objects; * * @hide */ +@SystemApi +@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; @@ -62,12 +66,14 @@ public class EthernetManager { /** * A listener interface to receive notification on changes in Ethernet. + * @hide */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. + * @hide */ @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); @@ -78,6 +84,7 @@ public class EthernetManager { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. + * @hide */ public EthernetManager(Context context, IEthernetManager service) { mContext = context; @@ -87,6 +94,7 @@ public class EthernetManager { /** * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + * @hide */ @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { @@ -99,6 +107,7 @@ public class EthernetManager { /** * Set Ethernet configuration. + * @hide */ @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { @@ -111,6 +120,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. + * @hide */ @UnsupportedAppUsage public boolean isAvailable() { @@ -121,6 +131,7 @@ public class EthernetManager { * Indicates whether the system has given interface. * * @param iface Ethernet interface name + * @hide */ @UnsupportedAppUsage public boolean isAvailable(String iface) { @@ -135,6 +146,7 @@ public class EthernetManager { * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void addListener(Listener listener) { @@ -153,6 +165,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. + * @hide */ @UnsupportedAppUsage public String[] getAvailableInterfaces() { @@ -167,6 +180,7 @@ public class EthernetManager { * Removes a listener. * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void removeListener(Listener listener) { From b13338a8e389e3a5551c55fc1bc857d32d344eee Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 27 Jan 2020 13:27:50 -0800 Subject: [PATCH 0705/1150] Networking: Rename removeDoubleQuotes to sanitizeSsid Bug: 145745815 Test: compiles Change-Id: Iaa6f0d65cab556c24b0a9010427de8e6a02836c1 Merged-In: Iaa6f0d65cab556c24b0a9010427de8e6a02836c1 (clean cherry-pick from internal branch) --- core/java/android/net/NetworkTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5e6c47a47a..5498f74ba2 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -32,7 +32,7 @@ import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; -import static android.net.wifi.WifiInfo.removeDoubleQuotes; +import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -401,7 +401,7 @@ public class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return Objects.equals( - removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); + sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); default: return false; } From 8b5779ee384824a036f55ef453ed4e6bc09a804e Mon Sep 17 00:00:00 2001 From: David Su Date: Mon, 27 Jan 2020 13:27:50 -0800 Subject: [PATCH 0706/1150] Networking: Rename removeDoubleQuotes to sanitizeSsid Bug: 145745815 Test: compiles Change-Id: Iaa6f0d65cab556c24b0a9010427de8e6a02836c1 --- core/java/android/net/NetworkTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5e6c47a47a..5498f74ba2 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -32,7 +32,7 @@ import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; -import static android.net.wifi.WifiInfo.removeDoubleQuotes; +import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -401,7 +401,7 @@ public class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return Objects.equals( - removeDoubleQuotes(mNetworkId), removeDoubleQuotes(ident.mNetworkId)); + sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); default: return false; } From c359926d90cada661ca5c1cc4f0e99aebfbe67bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 27 Jan 2020 17:36:56 -0800 Subject: [PATCH 0707/1150] Fix incorrect interpolation of active bucket for partial requests. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Just because the bucket is active (ie. overlaps with 'now') doesn't mean the request necessarily covers the entire bucket. For example a bucketDuration=5 with a bucket from curStart=1 to curEnd=6 with now=4 and requests: - from start=0 to end=3 --> overlap=[1,3] --> bucketSpan=2 - from start=2 to end=3 --> overlap=[2,3] --> bucketSpan=1 - from start=2 to end=5 --> overlap=[2,4] --> bucketSpan=2 - from start=2 to end=7 --> overlap=[2,4] --> bucketSpan=2 and the previously correctly handled cases: - from start=0 to end=5 --> overlap=[1,4] --> bucketSpan=3 - from start=0 to end=7 --> overlap=[1,4] --> bucketSpan=3 We fix this by bounding the end of buckets to now, this means that bucketDuration is no longer a constant, but it simplifies all the rest of the logic. Test: builds, atest Bug: 143338233 Signed-off-by: Maciej Żenczykowski Change-Id: I642b57f7b8486071ad7808fd9b901859923b6d25 --- .../java/android/net/NetworkStatsHistory.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 7b799e2624..c82c288222 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -548,32 +548,32 @@ public class NetworkStatsHistory implements Parcelable { final int startIndex = getIndexAfter(end); for (int i = startIndex; i >= 0; i--) { final long curStart = bucketStart[i]; - final long curEnd = curStart + bucketDuration; + long curEnd = curStart + bucketDuration; // bucket is older than request; we're finished if (curEnd <= start) break; // bucket is newer than request; keep looking if (curStart >= end) continue; - // include full value for active buckets, otherwise only fractional - final boolean activeBucket = curStart < now && curEnd > now; - final long overlap; - if (activeBucket) { - overlap = bucketDuration; - } else { - final long overlapEnd = curEnd < end ? curEnd : end; - final long overlapStart = curStart > start ? curStart : start; - overlap = overlapEnd - overlapStart; - } + // the active bucket is shorter then a normal completed bucket + if (curEnd > now) curEnd = now; + // usually this is simply bucketDuration + final long bucketSpan = curEnd - curStart; + // prevent division by zero + if (bucketSpan <= 0) continue; + + final long overlapEnd = curEnd < end ? curEnd : end; + final long overlapStart = curStart > start ? curStart : start; + final long overlap = overlapEnd - overlapStart; if (overlap <= 0) continue; // integer math each time is faster than floating point - if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketDuration; - if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketDuration; - if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketDuration; - if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketDuration; - if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketDuration; - if (operations != null) entry.operations += operations[i] * overlap / bucketDuration; + if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketSpan; + if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketSpan; + if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketSpan; + if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketSpan; + if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketSpan; + if (operations != null) entry.operations += operations[i] * overlap / bucketSpan; } return entry; } From 22a02a74220142b4da35b0b47ad75709e3f8f75b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 24 Jan 2020 19:29:17 +0900 Subject: [PATCH 0708/1150] Support putting one Ethernet interface in server mode. requestTetheredInterface can be used to put an interface in server mode, which will persist until release() is called on the returned request, or until the requesting process dies. Test: Enabled ethernet tethering with change on top Bug: 130840861 Merged-In: Id96d581acb3fa4e52ca62dd94ec257f56bd3a1ce Change-Id: Id96d581acb3fa4e52ca62dd94ec257f56bd3a1ce (clean cherry-pick from internal branch) --- core/java/android/net/EthernetManager.java | 78 ++++++++++++++++++- core/java/android/net/IEthernetManager.aidl | 3 + .../net/ITetheredInterfaceCallback.aidl | 23 ++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 core/java/android/net/ITetheredInterfaceCallback.aidl diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index fd015b4fe5..95000f5744 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.NonNull; import android.annotation.SystemService; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -24,6 +25,7 @@ import android.os.Message; import android.os.RemoteException; import java.util.ArrayList; +import java.util.Objects; /** * A class representing the IP configuration of the Ethernet network. @@ -37,7 +39,7 @@ public class EthernetManager { private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler() { + private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { @Override public void handleMessage(Message msg) { if (msg.what == MSG_AVAILABILITY_CHANGED) { @@ -180,4 +182,78 @@ public class EthernetManager { } } } + + /** + * A request for a tethered interface. + */ + public static class TetheredInterfaceRequest { + private final IEthernetManager mService; + private final ITetheredInterfaceCallback mCb; + + private TetheredInterfaceRequest(@NonNull IEthernetManager service, + @NonNull ITetheredInterfaceCallback cb) { + this.mService = service; + this.mCb = cb; + } + + /** + * Release the request, causing the interface to revert back from tethering mode if there + * is no other requestor. + */ + public void release() { + try { + mService.releaseTetheredInterface(mCb); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + } + } + + /** + * Callback for {@link #requestTetheredInterface(TetheredInterfaceCallback)}. + */ + public interface TetheredInterfaceCallback { + /** + * Called when the tethered interface is available. + * @param iface The name of the interface. + */ + void onAvailable(@NonNull String iface); + + /** + * Called when the tethered interface is now unavailable. + */ + void onUnavailable(); + } + + /** + * Request a tethered interface in tethering mode. + * + *

            When this method is called and there is at least one ethernet interface available, the + * system will designate one to act as a tethered interface. If there is already a tethered + * interface, the existing interface will be used. + * @param callback A callback to be called once the request has been fulfilled. + */ + @NonNull + public TetheredInterfaceRequest requestTetheredInterface( + @NonNull TetheredInterfaceCallback callback) { + Objects.requireNonNull(callback, "Callback must be non-null"); + final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { + @Override + public void onAvailable(String iface) { + callback.onAvailable(iface); + } + + @Override + public void onUnavailable() { + callback.onUnavailable(); + } + }; + + try { + mService.requestTetheredInterface(cbInternal); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + return new TetheredInterfaceRequest(mService, cbInternal); + } } diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index 94960b51d3..ccc6e35209 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.ITetheredInterfaceCallback; /** * Interface that answers queries about, and allows changing @@ -32,4 +33,6 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void requestTetheredInterface(in ITetheredInterfaceCallback callback); + void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl new file mode 100644 index 0000000000..e3d075988c --- /dev/null +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** @hide */ +interface ITetheredInterfaceCallback { + void onAvailable(in String iface); + void onUnavailable(); +} \ No newline at end of file From 07b469658f11c2412c027779526f10d7b67988a4 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 24 Jan 2020 22:57:09 +0900 Subject: [PATCH 0709/1150] Add support for Ethernet tethering Ethernet tethering can be started via startTethering(TETHERING_ETHERNET). Test: flashed, enabled ethernet tethering, verified internet access on downstream. Bug: 130840861 Merged-In: I34842acd94b972e440c3622f7617df10c18acf65 Change-Id: I34842acd94b972e440c3622f7617df10c18acf65 (cherry-pick with conflicts in test-current.txt) --- core/java/android/net/EthernetManager.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 95000f5744..a3899b705c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,7 +17,9 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Handler; @@ -32,6 +34,8 @@ import java.util.Objects; * * @hide */ +@SystemApi +@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; @@ -62,12 +66,14 @@ public class EthernetManager { /** * A listener interface to receive notification on changes in Ethernet. + * @hide */ public interface Listener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name * @param isAvailable {@code true} if Ethernet port exists. + * @hide */ @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); @@ -78,6 +84,7 @@ public class EthernetManager { * Applications will almost always want to use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve * the standard {@link android.content.Context#ETHERNET_SERVICE Context.ETHERNET_SERVICE}. + * @hide */ public EthernetManager(Context context, IEthernetManager service) { mContext = context; @@ -87,6 +94,7 @@ public class EthernetManager { /** * Get Ethernet configuration. * @return the Ethernet Configuration, contained in {@link IpConfiguration}. + * @hide */ @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { @@ -99,6 +107,7 @@ public class EthernetManager { /** * Set Ethernet configuration. + * @hide */ @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { @@ -111,6 +120,7 @@ public class EthernetManager { /** * Indicates whether the system currently has one or more Ethernet interfaces. + * @hide */ @UnsupportedAppUsage public boolean isAvailable() { @@ -121,6 +131,7 @@ public class EthernetManager { * Indicates whether the system has given interface. * * @param iface Ethernet interface name + * @hide */ @UnsupportedAppUsage public boolean isAvailable(String iface) { @@ -135,6 +146,7 @@ public class EthernetManager { * Adds a listener. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void addListener(Listener listener) { @@ -153,6 +165,7 @@ public class EthernetManager { /** * Returns an array of available Ethernet interface names. + * @hide */ @UnsupportedAppUsage public String[] getAvailableInterfaces() { @@ -167,6 +180,7 @@ public class EthernetManager { * Removes a listener. * @param listener A {@link Listener} to remove. * @throws IllegalArgumentException If the listener is null. + * @hide */ @UnsupportedAppUsage public void removeListener(Listener listener) { From 950d79e145c190b33271f58e418b94186bc1d2ef Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 8 Jan 2020 20:34:36 +0800 Subject: [PATCH 0710/1150] [SP10] Add IntDef annotations for system api of NetworkStats Test: m -j Bug: 130855321 Change-Id: I8855ec95d5d086fc14e2eb71558bc2dcd9a830e5 --- core/java/android/net/NetworkStats.java | 62 +++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 96d7a80886..2f536ffd8c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -18,6 +18,7 @@ package android.net; import static android.os.Process.CLAT_UID; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; @@ -35,6 +36,8 @@ import libcore.util.EmptyArray; import java.io.CharArrayWriter; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; import java.util.Map; @@ -100,6 +103,19 @@ public final class NetworkStats implements Parcelable { */ public static final int SET_DBG_VPN_OUT = 1002; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SET_" }, value = { + SET_ALL, + SET_DEFAULT, + SET_FOREGROUND, + SET_DEBUG_START, + SET_DBG_VPN_IN, + SET_DBG_VPN_OUT + }) + public @interface State { + } + /** * Include all interfaces when filtering * @hide @@ -120,6 +136,17 @@ public final class NetworkStats implements Parcelable { /** {@link #metered} value where metered data is accounted. */ public static final int METERED_YES = 1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "METERED_" }, value = { + METERED_ALL, + METERED_NO, + METERED_YES + }) + public @interface Meteredness { + } + + /** * {@link #roaming} value to account for all roaming states. * @hide @@ -130,6 +157,16 @@ public final class NetworkStats implements Parcelable { /** {@link #roaming} value where roaming data is accounted. */ public static final int ROAMING_YES = 1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "ROAMING_" }, value = { + ROAMING_ALL, + ROAMING_NO, + ROAMING_YES + }) + public @interface Roaming { + } + /** * {@link #onDefaultNetwork} value to account for all default network states. * @hide @@ -140,6 +177,16 @@ public final class NetworkStats implements Parcelable { /** {@link #onDefaultNetwork} value to account for usage while the default network. */ public static final int DEFAULT_NETWORK_YES = 1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "DEFAULT_NETWORK_" }, value = { + DEFAULT_NETWORK_ALL, + DEFAULT_NETWORK_NO, + DEFAULT_NETWORK_YES + }) + public @interface DefaultNetwork { + } + /** * Denotes a request for stats at the interface level. * @hide @@ -151,6 +198,15 @@ public final class NetworkStats implements Parcelable { */ public static final int STATS_PER_UID = 1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "STATS_PER_" }, value = { + STATS_PER_IFACE, + STATS_PER_UID + }) + public @interface StatsType { + } + private static final String CLATD_INTERFACE_PREFIX = "v4-"; // Delta between IPv4 header (20b) and IPv6 header (40b). // Used for correct stats accounting on clatd interfaces. @@ -263,9 +319,9 @@ public final class NetworkStats implements Parcelable { rxBytes, rxPackets, txBytes, txPackets, operations); } - public Entry(@Nullable String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { + public Entry(@Nullable String iface, int uid, @State int set, int tag, + @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, + long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { this.iface = iface; this.uid = uid; this.set = set; From d7fc38a1cb358daf9228c2992d30ac5019c1aff3 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 12 Nov 2019 22:31:51 -0800 Subject: [PATCH 0711/1150] Implement Ikev2VpnRunner This change adds the implementation for IKEv2/IPsec VPNs. Bug: 144246767 Test: Manually tested Change-Id: I5ccec756cec49ccf57ccc4d5ad800eeb5d595a76 --- core/java/android/net/IpSecManager.java | 2 +- .../java/com/android/server/IpSecService.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 09ec6c35fc..d83715c692 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -51,7 +51,7 @@ import java.net.Socket; * *

            Note that not all aspects of IPsec are permitted by this API. Applications may create * transport mode security associations and apply them to individual sockets. Applications looking - * to create a VPN should use {@link VpnService}. + * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}. * * @see RFC 4301, Security Architecture for the * Internet Protocol diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index c98762074b..9540f43364 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1556,16 +1556,16 @@ public class IpSecService extends IIpSecService.Stub { } Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); + + // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system + // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS + // permission or is the System Server. + if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow( + TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { + return; } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); } private void createOrUpdateTransform( From 514983cc3efb1fb4d51d79c043a66fb01d556343 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 12 Nov 2019 22:31:51 -0800 Subject: [PATCH 0712/1150] Implement Ikev2VpnRunner This change adds the implementation for IKEv2/IPsec VPNs. Bug: 144246767 Test: Manually tested Change-Id: I5ccec756cec49ccf57ccc4d5ad800eeb5d595a76 Merged-In: I5ccec756cec49ccf57ccc4d5ad800eeb5d595a76 --- core/java/android/net/IpSecManager.java | 2 +- .../java/com/android/server/IpSecService.java | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 09ec6c35fc..d83715c692 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -51,7 +51,7 @@ import java.net.Socket; * *

            Note that not all aspects of IPsec are permitted by this API. Applications may create * transport mode security associations and apply them to individual sockets. Applications looking - * to create a VPN should use {@link VpnService}. + * to create an IPsec VPN should use {@link VpnManager} and {@link Ikev2VpnProfile}. * * @see RFC 4301, Security Architecture for the * Internet Protocol diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index a629b3fbb8..98ac4cb712 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1557,16 +1557,16 @@ public class IpSecService extends IIpSecService.Stub { } checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); - switch (getAppOpsManager().noteOp(TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { - case AppOpsManager.MODE_DEFAULT: - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); - break; - case AppOpsManager.MODE_ALLOWED: - return; - default: - throw new SecurityException("Request to ignore AppOps for non-legacy API"); + + // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system + // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS + // permission or is the System Server. + if (AppOpsManager.MODE_ALLOWED == getAppOpsManager().noteOpNoThrow( + TUNNEL_OP, Binder.getCallingUid(), callingPackage)) { + return; } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MANAGE_IPSEC_TUNNELS, "IpSecService"); } private void createOrUpdateTransform( From b375131b031e6ea56b190e7dcf58c5b75aabe4f8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 14 Jan 2020 18:41:08 +0800 Subject: [PATCH 0713/1150] [SP12] Remove the usage of getVtDataUsage Currently NetworkStatsService holding a lock when invoking getVtDataUsage, which causes a lot of deadlock problems since Phone will also have binder calls to system_server. Thus, this change uses a new set of API to break such situation, that allows VT to report stats asynchronously. Test: atest FrameworksNetTests FrameworksTelephonyTests Bug: 130855321 Fix: 143923500 Change-Id: Ifdb8599c3bade09208b4730710fc99da1afad71d --- .../server/net/NetworkStatsService.java | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index fc39a253bc..60af1d6bc2 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1249,7 +1249,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats uidSnapshot = getNetworkStatsUidDetail(INTERFACES_ALL); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotXt"); - final NetworkStats xtSnapshot = getNetworkStatsXt(); + final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); Trace.traceEnd(TRACE_TAG_NETWORK); Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotDev"); final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); @@ -1707,18 +1707,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUseBpfTrafficStats); uidSnapshot.combineAllValues(tetherSnapshot); - final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - - // fold video calling data usage stats into uid snapshot - final NetworkStats vtStats = telephonyManager.getVtDataUsage(STATS_PER_UID); - if (vtStats != null) { - vtStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, vtStats, - mUseBpfTrafficStats); - uidSnapshot.combineAllValues(vtStats); - } - // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); @@ -1730,24 +1718,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return uidSnapshot; } - /** - * Return snapshot of current XT statistics with video calling data usage statistics. - */ - private NetworkStats getNetworkStatsXt() throws RemoteException { - final NetworkStats xtSnapshot = readNetworkStatsSummaryXt(); - - final TelephonyManager telephonyManager = (TelephonyManager) mContext.getSystemService( - Context.TELEPHONY_SERVICE); - - // Merge video calling data usage into XT - final NetworkStats vtSnapshot = telephonyManager.getVtDataUsage(STATS_PER_IFACE); - if (vtSnapshot != null) { - xtSnapshot.combineAllValues(vtSnapshot); - } - - return xtSnapshot; - } - /** * Return snapshot of current tethering statistics. Will return empty * {@link NetworkStats} if any problems are encountered. From 0d16cdde0f7604f4129eee95fe46a01a0a9ebc81 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 21 Jan 2020 13:52:04 +0800 Subject: [PATCH 0714/1150] [SP16] Address comments on aosp/1172143 Test: atest FrameworksNetTests Test: atest NetworkPolicyManagerServiceTest Test: m doc-comment-check-docs Bug: 130855321 Change-Id: Iccaab09f5b9668ec4a7249737c64a69cecb08d15 --- .../app/usage/NetworkStatsManager.java | 16 ++++++++------ .../server/net/NetworkStatsService.java | 22 ++++++++++--------- 2 files changed, 21 insertions(+), 17 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9c4a8f4fbe..5b98188300 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -526,15 +526,17 @@ public class NetworkStatsManager { } /** - * Registers a custom provider of {@link android.net.NetworkStats} to combine the network - * statistics that cannot be seen by the kernel to system. To unregister, invoke - * {@link NetworkStatsProviderCallback#unregister()}. + * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics + * to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}. + * Note that no de-duplication of statistics between providers is performed, so each provider + * must only report network traffic that is not being reported by any other provider. * - * @param tag a human readable identifier of the custom network stats provider. - * @param provider a custom implementation of {@link AbstractNetworkStatsProvider} that needs to - * be registered to the system. + * @param tag a human readable identifier of the custom network stats provider. This is only + * used for debugging. + * @param provider the subclass of {@link AbstractNetworkStatsProvider} that needs to be + * registered to the system. * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the - * system. + * system or unregister the provider. * @hide */ @SystemApi diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 415ccb8fe8..2af6e349ff 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -255,7 +255,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private final Object mStatsLock = new Object(); - private final Object mStatsProviderLock = new Object(); /** Set of currently active ifaces. */ @GuardedBy("mStatsLock") @@ -1501,8 +1500,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void setStatsProviderLimit(@NonNull String iface, long quota) { - Slog.v(TAG, "setStatsProviderLimit(" + iface + "," + quota + ")"); + public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { + Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); } } @@ -1783,9 +1782,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@code unregister()} of the returned callback. * * @param tag a human readable identifier of the custom network stats provider. - * @param provider the binder interface of - * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} that - * needs to be registered to the system. + * @param provider the {@link INetworkStatsProvider} binder corresponding to the + * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be + * registered. * * @return a binder interface of * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be @@ -1823,7 +1822,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void invokeForAllStatsProviderCallbacks( @NonNull ThrowingConsumer task) { - synchronized (mStatsProviderCbList) { + synchronized (mStatsLock) { final int length = mStatsProviderCbList.beginBroadcast(); try { for (int i = 0; i < length; i++) { @@ -1844,13 +1843,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static class NetworkStatsProviderCallbackImpl extends INetworkStatsProviderCallback.Stub implements IBinder.DeathRecipient { @NonNull final String mTag; - @NonNull private final Object mProviderStatsLock = new Object(); + @NonNull final INetworkStatsProvider mProvider; @NonNull final INetworkManagementEventObserver mAlertObserver; @NonNull final RemoteCallbackList mStatsProviderCbList; + @NonNull private final Object mProviderStatsLock = new Object(); + @GuardedBy("mProviderStatsLock") - // STATS_PER_IFACE and STATS_PER_UID + // Track STATS_PER_IFACE and STATS_PER_UID separately. private final NetworkStats mIfaceStats = new NetworkStats(0L, 0); @GuardedBy("mProviderStatsLock") private final NetworkStats mUidStats = new NetworkStats(0L, 0); @@ -1881,7 +1882,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { default: throw new IllegalArgumentException("Invalid type: " + how); } - // Return a defensive copy instead of local reference. + // Callers might be able to mutate the returned object. Return a defensive copy + // instead of local reference. return stats.clone(); } } From 137e140e1035c9cd0fd82d29325edf256e80eb38 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 12 Feb 2020 14:55:54 +0800 Subject: [PATCH 0715/1150] [SP17] Wait for stats providers to report stats update From current design, the traffic accounted by stats providers will be updated asynchronously when force polling. When upper layer make two subsequently queries. They will get stale stats upon the first query, and may get newest/stale stats base on the result of race. Thus, wait for a bit of time to allow asynchronous stats update complete to reduce the chance of race. In pratice, it would be finished in ~2ms when testing. Test: systrace.py network Test: atest FrameworksNetTests Bug: 147460444 Change-Id: I22a00fc4049cddf77fd578e25769ae1979f2cc6d --- .../server/net/NetworkStatsService.java | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 415ccb8fe8..1c52110449 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -155,6 +155,8 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; /** * Collect and persist detailed network statistics, and provide this data to @@ -280,8 +282,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); + private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; private final RemoteCallbackList mStatsProviderCbList = new RemoteCallbackList<>(); + /** Semaphore used to wait for stats provider to respond to request stats update. */ + private final Semaphore mStatsProviderSem = new Semaphore(0, true); @GuardedBy("mStatsLock") private NetworkStatsRecorder mDevRecorder; @@ -1337,6 +1342,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; + // Request asynchronous stats update from all providers for next poll. And wait a bit of + // time to allow providers report-in given that normally binder call should be fast. + // TODO: request with a valid token. + Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); + final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); + mStatsProviderSem.drainPermits(); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + try { + mStatsProviderSem.tryAcquire(registeredCallbackCount, + MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Strictly speaking it's possible a provider happened to deliver between the timeout + // and the log, and that doesn't matter too much as this is just a debug log. + Log.d(TAG, "requestStatsUpdate - providers responded " + + mStatsProviderSem.availablePermits() + + "/" + registeredCallbackCount + " : " + e); + } + Trace.traceEnd(TRACE_TAG_NETWORK); + // TODO: consider marking "untrusted" times in historical stats final long currentTime = mClock.millis(); @@ -1374,10 +1398,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performSampleLocked(); } - // request asynchronous stats update from all providers for next poll. - // TODO: request with a valid token. - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); - // finally, dispatch updated event to any listeners final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); @@ -1798,7 +1818,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Objects.requireNonNull(tag, "tag is null"); try { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( - tag, provider, mAlertObserver, mStatsProviderCbList); + tag, provider, mStatsProviderSem, mAlertObserver, + mStatsProviderCbList); mStatsProviderCbList.register(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); @@ -1846,6 +1867,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final String mTag; @NonNull private final Object mProviderStatsLock = new Object(); @NonNull final INetworkStatsProvider mProvider; + @NonNull private final Semaphore mSemaphore; @NonNull final INetworkManagementEventObserver mAlertObserver; @NonNull final RemoteCallbackList mStatsProviderCbList; @@ -1857,12 +1879,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl( @NonNull String tag, @NonNull INetworkStatsProvider provider, + @NonNull Semaphore semaphore, @NonNull INetworkManagementEventObserver alertObserver, @NonNull RemoteCallbackList cbList) throws RemoteException { mTag = tag; mProvider = provider; mProvider.asBinder().linkToDeath(this, 0); + mSemaphore = semaphore; mAlertObserver = alertObserver; mStatsProviderCbList = cbList; } @@ -1895,6 +1919,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (ifaceStats != null) mIfaceStats.combineAllValues(ifaceStats); if (uidStats != null) mUidStats.combineAllValues(uidStats); } + mSemaphore.release(); } @Override From 466e2e953b3bd2afda835cab6b81838b41b54a1b Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 24 Feb 2020 19:17:42 +0800 Subject: [PATCH 0716/1150] Add permission check functions to NetworkStatsService This is shameless copied from ConnectivityService and plan to be used in follow-up change. For long term perspective we should have a permission util that contains those util in one place. Test: m -j Change-Id: I837545b54f36c8f21c878cbb1fd028ff23be6cb8 --- .../server/net/NetworkStatsService.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 896bf676d4..211d496a5b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -23,6 +23,7 @@ import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; @@ -1766,6 +1767,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // TODO: It is copied from ConnectivitySerivce, consider refactor these check permission + // functions to a proper util. + private boolean checkAnyPermissionOf(String... permissions) { + for (String permission : permissions) { + if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { + return true; + } + } + return false; + } + + private void enforceAnyPermissionOf(String... permissions) { + if (!checkAnyPermissionOf(permissions)) { + throw new SecurityException("Requires one of the following permissions: " + + String.join(", ", permissions) + "."); + } + } + /** * Registers a custom provider of {@link android.net.NetworkStats} to combine the network * statistics that cannot be seen by the kernel to system. To unregister, invoke the From 1c20161672fa78addaf15116a209b1c207a37751 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 24 Feb 2020 18:16:54 +0800 Subject: [PATCH 0717/1150] [SP20] Check signature permission when accessing network stats provider Currently, registerNetworkStatsProvider requires the UPDATE_DEVICE_STATS permission. This is a privileged permission so it can be granted to preinstalled apps. Thus, apps like GmsCore, or preinstalled apps will be able to update network stats. This change checks for a new permission that would only allow signature apps to declare that. Also check MAINLINE_NETWORK_STACK permission to allow NetworkStack process to use it. Test: adb shell dumpsys netstats Test: atest FrameworksNetTests Bug: 149652079 Change-Id: Idfebd0a1988c3dcfd812d87e30f6a2034d6fbf6b --- core/java/android/app/usage/NetworkStatsManager.java | 5 ++++- .../java/com/android/server/net/NetworkStatsService.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5b98188300..7d13f050a7 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -29,6 +29,7 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; +import android.net.NetworkStack; import android.net.NetworkTemplate; import android.net.netstats.provider.AbstractNetworkStatsProvider; import android.net.netstats.provider.NetworkStatsProviderCallback; @@ -540,7 +541,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull AbstractNetworkStatsProvider provider) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 211d496a5b..9e5f704e83 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.Intent.ACTION_SHUTDOWN; @@ -1801,7 +1802,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); Objects.requireNonNull(provider, "provider is null"); Objects.requireNonNull(tag, "tag is null"); try { From e3576345d62d85d2d93fb3ee334747cf3a0af851 Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 26 Feb 2020 20:54:55 +0800 Subject: [PATCH 0718/1150] Fix crash and duplicated ethernet tethering request This change fix two things: 1. Handle ethernet callback in internal thread to avoid crash. IpServer should be created from tethering thread, otherwise mIpNeighborMonitor of IpServer would throw IllegalStateException("start() called from off-thread") 2. Ethernet tethering request may be duplicated if multiple startTethering is called but no stopTethering Bug: 130840861 Bug: 148824036 Test: ON/OFF ethernet tehtering manually atest TetheringTests Change-Id: I7c5127e96d80d077735010d2e62c7227805ccb10 --- core/java/android/net/EthernetManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index a3899b705c..139f5bebcd 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -28,6 +28,7 @@ import android.os.RemoteException; import java.util.ArrayList; import java.util.Objects; +import java.util.concurrent.Executor; /** * A class representing the IP configuration of the Ethernet network. @@ -248,18 +249,19 @@ public class EthernetManager { * @param callback A callback to be called once the request has been fulfilled. */ @NonNull - public TetheredInterfaceRequest requestTetheredInterface( - @NonNull TetheredInterfaceCallback callback) { + public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, + @NonNull final TetheredInterfaceCallback callback) { Objects.requireNonNull(callback, "Callback must be non-null"); + Objects.requireNonNull(executor, "Executor must be non-null"); final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { @Override public void onAvailable(String iface) { - callback.onAvailable(iface); + executor.execute(() -> callback.onAvailable(iface)); } @Override public void onUnavailable() { - callback.onUnavailable(); + executor.execute(() -> callback.onUnavailable()); } }; From 8005a2285fa071b7b59e6d23801240a1e6a59c8d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Jan 2020 20:22:17 +0800 Subject: [PATCH 0719/1150] Move DnsSdTxtRecord to net common static library DnsSdTxtRecord is moved to frameworks/libs/net for mainline support. Also change the import path using this class. Bug: 139268426 Bug: 135998869 Test: atest FrameworksNetTests ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh Change-Id: I6118b313ce668707d598aa2eab9baee2f7622dbc Merged-In: I6118b313ce668707d598aa2eab9baee2f7622dbc --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index b9b7bf73c1..4a1820a8e5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -22,10 +22,10 @@ import android.content.Intent; import android.database.ContentObserver; import android.net.NetworkStack; import android.net.Uri; -import android.net.nsd.DnsSdTxtRecord; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; From 28561caf5858ba9f6691a4e4c6c3d707b74ebdd9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 3 Mar 2020 15:53:56 +0800 Subject: [PATCH 0720/1150] Remove setHandler in NetworkStatsService Currently, internal handler is set by setHandler after constructing NSS object. This was introduced in ag/866187 to access the handler in the unit test. However, the design put NSS in a bad situation where all classes that need handler or executor could not be final and need to be dynamically allocated in order to get a valid handler. Thus, since the usage of handler is removed in previous patch, this change eliminate setHandler by initializing the handler in the constructor. Test: atest FrameworksNetTests Bug: 150664039 Change-Id: I794a24d00b0ca9fdc78091e7b9ab7307e0f034b7 --- .../server/net/NetworkStatsService.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 896bf676d4..66e691a79f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -306,9 +306,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - /** Must be set in factory by calling #setHandler. */ - private Handler mHandler; - private Handler.Callback mHandlerCallback; + @NonNull + private final Handler mHandler; private volatile boolean mSystemReady; private long mPersistThreshold = 2 * MB_IN_BYTES; @@ -324,6 +323,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final static int DUMP_STATS_SESSION_COUNT = 20; + @NonNull + private final Dependencies mDeps; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -339,9 +341,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Clock.systemUTC()); } - private static final class NetworkStatsHandler extends Handler { - NetworkStatsHandler(Looper looper, Handler.Callback callback) { - super(looper, callback); + private final class NetworkStatsHandler extends Handler { + NetworkStatsHandler(@NonNull Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERFORM_POLL: { + performPoll(FLAG_PERSIST_ALL); + break; + } + case MSG_PERFORM_POLL_REGISTER_ALERT: { + performPoll(FLAG_PERSIST_NETWORK); + registerGlobalAlert(); + break; + } + } } } @@ -355,14 +372,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), - new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); + new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), + new Dependencies()); service.registerLocalService(); - HandlerThread handlerThread = new HandlerThread(TAG); - Handler.Callback callback = new HandlerCallback(service); - handlerThread.start(); - Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback); - service.setHandler(handler, callback); return service; } @@ -373,7 +386,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir) { + File baseDir, @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, "missing INetworkManagementService"); @@ -387,6 +400,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); + mDeps = Objects.requireNonNull(deps, "missing Dependencies"); + + final HandlerThread handlerThread = mDeps.makeHandlerThread(); + handlerThread.start(); + mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + } + + /** + * Dependencies of NetworkStatsService, for injection in tests. + */ + // TODO: Move more stuff into dependencies object. + @VisibleForTesting + public static class Dependencies { + /** + * Create a HandlerThread to use in NetworkStatsService. + */ + @NonNull + public HandlerThread makeHandlerThread() { + return new HandlerThread(TAG); + } } private void registerLocalService() { @@ -394,12 +427,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new NetworkStatsManagerInternalImpl()); } - @VisibleForTesting - void setHandler(Handler handler, Handler.Callback callback) { - mHandler = handler; - mHandlerCallback = callback; - } - public void systemReady() { synchronized (mStatsLock) { mSystemReady = true; @@ -1920,33 +1947,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } - @VisibleForTesting - static class HandlerCallback implements Handler.Callback { - private final NetworkStatsService mService; - - HandlerCallback(NetworkStatsService service) { - this.mService = service; - } - - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERFORM_POLL: { - mService.performPoll(FLAG_PERSIST_ALL); - return true; - } - case MSG_PERFORM_POLL_REGISTER_ALERT: { - mService.performPoll(FLAG_PERSIST_NETWORK); - mService.registerGlobalAlert(); - return true; - } - default: { - return false; - } - } - } - } - private void assertSystemReady() { if (!mSystemReady) { throw new IllegalStateException("System not ready"); From f90ad41c071632c1cb57f99c7773b0654e2679a4 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Fri, 28 Feb 2020 03:42:44 +0000 Subject: [PATCH 0721/1150] Fix crash and duplicated ethernet tethering request This change fix two things: 1. Handle ethernet callback in internal thread to avoid crash. IpServer should be created from tethering thread, otherwise mIpNeighborMonitor of IpServer would throw IllegalStateException("start() called from off-thread") 2. Ethernet tethering request may be duplicated if multiple startTethering is called but no stopTethering Bug: 130840861 Bug: 148824036 Test: ON/OFF ethernet tehtering manually atest TetheringTests Change-Id: Ibd3ea6bc6751bd65647ff381f9b0124bc3395c09 Merged-In: I7c5127e96d80d077735010d2e62c7227805ccb10 Merged-In: Ibd3ea6bc6751bd65647ff381f9b0124bc3395c09 (cherry picked from commit 72702b979654234c18045f04270040056a74cf90) --- core/java/android/net/EthernetManager.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index a3899b705c..139f5bebcd 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -28,6 +28,7 @@ import android.os.RemoteException; import java.util.ArrayList; import java.util.Objects; +import java.util.concurrent.Executor; /** * A class representing the IP configuration of the Ethernet network. @@ -248,18 +249,19 @@ public class EthernetManager { * @param callback A callback to be called once the request has been fulfilled. */ @NonNull - public TetheredInterfaceRequest requestTetheredInterface( - @NonNull TetheredInterfaceCallback callback) { + public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, + @NonNull final TetheredInterfaceCallback callback) { Objects.requireNonNull(callback, "Callback must be non-null"); + Objects.requireNonNull(executor, "Executor must be non-null"); final ITetheredInterfaceCallback cbInternal = new ITetheredInterfaceCallback.Stub() { @Override public void onAvailable(String iface) { - callback.onAvailable(iface); + executor.execute(() -> callback.onAvailable(iface)); } @Override public void onUnavailable() { - callback.onUnavailable(); + executor.execute(() -> callback.onUnavailable()); } }; From f94a6010c07f35ef0b2700ee6c377f00ca76b9ba Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 9 Mar 2020 13:56:18 +0900 Subject: [PATCH 0722/1150] Add missing RequiresPermission to EthernetManager The method requires NETWORK_STACK or MAINLINE_NETWORK_STACK permissions, but the annotation was missing. Test: m Fixes: 150877670 Change-Id: I2af74cbcfa642f05f5e7bf85b2a8e8c38595f6ca --- core/java/android/net/EthernetManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 139f5bebcd..83b5f63576 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -248,6 +249,10 @@ public class EthernetManager { * interface, the existing interface will be used. * @param callback A callback to be called once the request has been fulfilled. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) @NonNull public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, @NonNull final TetheredInterfaceCallback callback) { From f5706306fbfc78962ce7dbe104ff45e00c95a1c0 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Wed, 4 Mar 2020 13:36:11 +0000 Subject: [PATCH 0723/1150] Merge NetworkStatsService handler changes. ===== Remove the need of accessing handler in NSS unit test Currently, to wait for handler becomes idle, specific message is used and the test would wait for condition variable to be open when the message is processed. However, this is already done in the HandlerUtils. Thus, there is no need to post such message manually in the handler. Test: atest FrameworksNetTests Bug: 150664039 Change-Id: Iab32b2dbab01634ca159dcb90fc9f929d1fed1a2 ===== Remove setHandler in NetworkStatsService Currently, internal handler is set by setHandler after constructing NSS object. This was introduced in ag/866187 to access the handler in the unit test. However, the design put NSS in a bad situation where all classes that need handler or executor could not be final and need to be dynamically allocated in order to get a valid handler. Thus, since the usage of handler is removed in previous patch, this change eliminate setHandler by initializing the handler in the constructor. Test: atest FrameworksNetTests Bug: 150664039 Change-Id: I794a24d00b0ca9fdc78091e7b9ab7307e0f034b7 ===== Bug: 150664039 Change-Id: If256ed4437ddcbcc72a6f766cff2f4cc512ee3f7 Merged-In: If256ed4437ddcbcc72a6f766cff2f4cc512ee3f7 (cherry picked from commit 2a6439d7e2a3926e10a0b9a4dc730b1a022d8138) --- .../server/net/NetworkStatsService.java | 92 +++++++++---------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ee5a4fe248..4af31b0369 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -306,9 +306,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); - /** Must be set in factory by calling #setHandler. */ - private Handler mHandler; - private Handler.Callback mHandlerCallback; + @NonNull + private final Handler mHandler; private volatile boolean mSystemReady; private long mPersistThreshold = 2 * MB_IN_BYTES; @@ -324,6 +323,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final static int DUMP_STATS_SESSION_COUNT = 20; + @NonNull + private final Dependencies mDeps; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -339,9 +341,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Clock.systemUTC()); } - private static final class NetworkStatsHandler extends Handler { - NetworkStatsHandler(Looper looper, Handler.Callback callback) { - super(looper, callback); + private final class NetworkStatsHandler extends Handler { + NetworkStatsHandler(@NonNull Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case MSG_PERFORM_POLL: { + performPoll(FLAG_PERSIST_ALL); + break; + } + case MSG_PERFORM_POLL_REGISTER_ALERT: { + performPoll(FLAG_PERSIST_NETWORK); + registerGlobalAlert(); + break; + } + } } } @@ -355,14 +372,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), - new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir()); + new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), + new Dependencies()); service.registerLocalService(); - HandlerThread handlerThread = new HandlerThread(TAG); - Handler.Callback callback = new HandlerCallback(service); - handlerThread.start(); - Handler handler = new NetworkStatsHandler(handlerThread.getLooper(), callback); - service.setHandler(handler, callback); return service; } @@ -373,7 +386,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, TelephonyManager teleManager, NetworkStatsSettings settings, NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir) { + File baseDir, @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, "missing INetworkManagementService"); @@ -387,6 +400,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); + mDeps = Objects.requireNonNull(deps, "missing Dependencies"); + + final HandlerThread handlerThread = mDeps.makeHandlerThread(); + handlerThread.start(); + mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + } + + /** + * Dependencies of NetworkStatsService, for injection in tests. + */ + // TODO: Move more stuff into dependencies object. + @VisibleForTesting + public static class Dependencies { + /** + * Create a HandlerThread to use in NetworkStatsService. + */ + @NonNull + public HandlerThread makeHandlerThread() { + return new HandlerThread(TAG); + } } private void registerLocalService() { @@ -394,12 +427,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new NetworkStatsManagerInternalImpl()); } - @VisibleForTesting - void setHandler(Handler handler, Handler.Callback callback) { - mHandler = handler; - mHandlerCallback = callback; - } - public void systemReady() { synchronized (mStatsLock) { mSystemReady = true; @@ -1920,33 +1947,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } - @VisibleForTesting - static class HandlerCallback implements Handler.Callback { - private final NetworkStatsService mService; - - HandlerCallback(NetworkStatsService service) { - this.mService = service; - } - - @Override - public boolean handleMessage(Message msg) { - switch (msg.what) { - case MSG_PERFORM_POLL: { - mService.performPoll(FLAG_PERSIST_ALL); - return true; - } - case MSG_PERFORM_POLL_REGISTER_ALERT: { - mService.performPoll(FLAG_PERSIST_NETWORK); - mService.registerGlobalAlert(); - return true; - } - default: { - return false; - } - } - } - } - private void assertSystemReady() { if (!mSystemReady) { throw new IllegalStateException("System not ready"); From e91080987ff49a750303cc2ea303e7d1ebe9a872 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Mon, 9 Mar 2020 08:40:23 +0000 Subject: [PATCH 0724/1150] Add missing RequiresPermission to EthernetManager The method requires NETWORK_STACK or MAINLINE_NETWORK_STACK permissions, but the annotation was missing. Test: m Fixes: 150877670 Merged-In: I2af74cbcfa642f05f5e7bf85b2a8e8c38595f6ca (cherry picked from commit e45d3ff849695977cb063cc59550c505b220bd6c) Change-Id: Ia215b74df99ae60be2e380917be68a272d658ef4 --- core/java/android/net/EthernetManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 139f5bebcd..83b5f63576 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; @@ -248,6 +249,10 @@ public class EthernetManager { * interface, the existing interface will be used. * @param callback A callback to be called once the request has been fulfilled. */ + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STACK, + android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK + }) @NonNull public TetheredInterfaceRequest requestTetheredInterface(@NonNull final Executor executor, @NonNull final TetheredInterfaceCallback callback) { From 261a430893e131a145ade912503fdc0cb57a9a19 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 11 Feb 2020 23:36:42 -0800 Subject: [PATCH 0725/1150] Relax IPsec resource count restrictions. IPsec resource counts were selected to be conservative, due to unknowns about device capabilities. Since then, it appears that we no longer need such stringent quotas, and this can be relaxed. Test: FrameworksNetTest passing Change-Id: Id53d14e5698e5fcc410868424176b00350c7ae79 --- .../core/java/com/android/server/IpSecService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 98ac4cb712..15cbfb5c65 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -360,10 +360,14 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final class UserRecord { /* Maximum number of each type of resource that a single UID may possess */ - public static final int MAX_NUM_TUNNEL_INTERFACES = 2; - public static final int MAX_NUM_ENCAP_SOCKETS = 2; - public static final int MAX_NUM_TRANSFORMS = 4; - public static final int MAX_NUM_SPIS = 8; + + // Up to 4 active VPNs/IWLAN with potential soft handover. + public static final int MAX_NUM_TUNNEL_INTERFACES = 8; + public static final int MAX_NUM_ENCAP_SOCKETS = 16; + + // SPIs and Transforms are both cheap, and are 1:1 correlated. + public static final int MAX_NUM_TRANSFORMS = 64; + public static final int MAX_NUM_SPIS = 64; /** * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing From 13f2ab82914200c3a2dd62e1618b1adc175293d7 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Tue, 11 Feb 2020 23:49:36 -0800 Subject: [PATCH 0726/1150] Automatically set IPsec tunnel interface as up This change makes IPsec tunnel interfaces automatically get brought up once they are created. Originally this was considered to be an additional safety check, as they would not be start routing traffic until explicitly brought up. However, in the intervening time, the NetworkManagementController now requires the NETWORK_STACK permission to set an interface as up. Additionally, that call is a hidden API, and thus not usable for use cases such as IWLAN. Bug: 149348618 Test: FrameworksNetTests, CtsNetTestCases passing. Change-Id: I55b63a748463a388e1e2991d2d5d6b3023545e60 --- .../java/com/android/server/IpSecService.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 15cbfb5c65..424407a957 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -48,6 +48,7 @@ import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -76,6 +77,7 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * A service to manage multiple clients that want to access the IpSec API. The service is @@ -115,6 +117,9 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; + /* NetworkManager instance */ + private final INetworkManagementService mNetworkManager; + /** * The next non-repeating global ID for tracking resources between users, this service, and * kernel data structures. Accessing this variable is not thread safe, so it is only read or @@ -993,12 +998,13 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { - this(context, IpSecServiceConfiguration.GETSRVINSTANCE); + private IpSecService(Context context, INetworkManagementService networkManager) { + this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE); } - static IpSecService create(Context context) throws InterruptedException { - final IpSecService service = new IpSecService(context); + static IpSecService create(Context context, INetworkManagementService networkManager) + throws InterruptedException { + final IpSecService service = new IpSecService(context, networkManager); service.connectNativeNetdService(); return service; } @@ -1012,9 +1018,11 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, IpSecServiceConfiguration config) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config) { this( context, + networkManager, config, (fd, uid) -> { try { @@ -1028,9 +1036,10 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService( - Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; + mNetworkManager = Objects.requireNonNull(networkManager); mSrvConfig = config; mUidFdTagger = uidFdTagger; } @@ -1309,6 +1318,10 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); + Binder.withCleanCallingIdentity(() -> { + mNetworkManager.setInterfaceUp(intfName); + }); + for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. netd.ipSecAddSecurityPolicy( From 6b65a8484b48c53728e71e07a1652b8db306ebc9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 6 Mar 2020 14:50:48 +0800 Subject: [PATCH 0727/1150] [SP21] Address comments for API council review about aosp/1172143 Test: atest FrameworksNetTests ImsPhoneCallTrackerTest Test: atest TetheringTests NetworkStackTests Test: m doc-comment-check-docs Fix: 148552904 Change-Id: I141393f229e772d2eb9f7c156849e379bd71b845 --- .../app/usage/NetworkStatsManager.java | 48 +++-- .../provider/INetworkStatsProvider.aidl | 6 +- .../INetworkStatsProviderCallback.aidl | 6 +- .../provider/NetworkStatsProvider.java | 195 ++++++++++++++++++ .../server/net/NetworkStatsService.java | 23 +-- 5 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 core/java/android/net/netstats/provider/NetworkStatsProvider.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7d13f050a7..d6e77624a9 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -31,9 +31,8 @@ import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkStack; import android.net.NetworkTemplate; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderWrapper; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -528,34 +527,53 @@ public class NetworkStatsManager { /** * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}. + * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}. * Note that no de-duplication of statistics between providers is performed, so each provider - * must only report network traffic that is not being reported by any other provider. + * must only report network traffic that is not being reported by any other provider. Also note + * that the provider cannot be re-registered after unregistering. * * @param tag a human readable identifier of the custom network stats provider. This is only * used for debugging. - * @param provider the subclass of {@link AbstractNetworkStatsProvider} that needs to be + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be * registered to the system. - * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the - * system or unregister the provider. * @hide */ @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STATS_PROVIDER, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull public void registerNetworkStatsProvider( @NonNull String tag, - @NonNull AbstractNetworkStatsProvider provider) { + @NonNull NetworkStatsProvider provider) { try { - final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); - return new NetworkStatsProviderCallback( - mService.registerNetworkStatsProvider(tag, wrapper)); + if (provider.getProviderCallbackBinder() != null) { + throw new IllegalArgumentException("provider is already registered"); + } + final INetworkStatsProviderCallback cbBinder = + mService.registerNetworkStatsProvider(tag, provider.getProviderBinder()); + provider.setProviderCallbackBinder(cbBinder); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregisters an instance of {@link NetworkStatsProvider}. + * + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be + * unregistered to the system. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) + @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { + try { + provider.getProviderCallbackBinderOrThrow().unregister(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } - // Unreachable code, but compiler doesn't know about it. - return null; } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 55b3d4edb1..4078b24921 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -22,7 +22,7 @@ package android.net.netstats.provider; * @hide */ oneway interface INetworkStatsProvider { - void requestStatsUpdate(int token); - void setLimit(String iface, long quotaBytes); - void setAlert(long quotaBytes); + void onRequestStatsUpdate(int token); + void onSetLimit(String iface, long quotaBytes); + void onSetAlert(long quotaBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 3ea9318f10..bd336dd348 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -24,8 +24,8 @@ import android.net.NetworkStats; * @hide */ oneway interface INetworkStatsProviderCallback { - void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void onAlertReached(); - void onLimitReached(); + void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void notifyAlertReached(); + void notifyLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java new file mode 100644 index 0000000000..7639d2244c --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.NetworkStats; +import android.os.RemoteException; + +/** + * A base class that allows external modules to implement a custom network statistics provider. + * @hide + */ +@SystemApi +public abstract class NetworkStatsProvider { + /** + * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + */ + public static final int QUOTA_UNLIMITED = -1; + + @NonNull private final INetworkStatsProvider mProviderBinder = + new INetworkStatsProvider.Stub() { + + @Override + public void onRequestStatsUpdate(int token) { + NetworkStatsProvider.this.onRequestStatsUpdate(token); + } + + @Override + public void onSetLimit(String iface, long quotaBytes) { + NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + } + + @Override + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); + } + }; + + // The binder given by the service when successfully registering. Only null before registering, + // never null once non-null. + @Nullable + private INetworkStatsProviderCallback mProviderCbBinder; + + /** + * Return the binder invoked by the service and redirect function calls to the overridden + * methods. + * @hide + */ + @NonNull + public INetworkStatsProvider getProviderBinder() { + return mProviderBinder; + } + + /** + * Store the binder that was returned by the service when successfully registering. Note that + * the provider cannot be re-registered. Hence this method can only be called once per provider. + * + * @hide + */ + public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { + if (mProviderCbBinder != null) { + throw new IllegalArgumentException("provider is already registered"); + } + mProviderCbBinder = binder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Or null if the + * provider was never registered. + * + * @hide + */ + @Nullable + public INetworkStatsProviderCallback getProviderCallbackBinder() { + return mProviderCbBinder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Throw an + * {@link IllegalStateException} if the provider is not registered. + * + * @hide + */ + @NonNull + public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { + if (mProviderCbBinder == null) { + throw new IllegalStateException("the provider is not registered"); + } + return mProviderCbBinder; + } + + /** + * Notify the system of new network statistics. + * + * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must + * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} + * being called. Responding later increases the probability stats will be dropped. The + * provider can also call this whenever it wants to reports new stats for any reason. + * Note that the system will not necessarily immediately propagate the statistics to + * reflect the update. + * + * @param token the token under which these stats were gathered. Providers can call this method + * with the current token as often as they want, until the token changes. + * {@see NetworkStatsProvider#onRequestStatsUpdate()} + * @param ifaceStats the {@link NetworkStats} per interface to be reported. + * The provider should not include any traffic that is already counted by + * kernel interface counters. + * @param uidStats the same stats as above, but counts {@link NetworkStats} + * per uid. + */ + public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, + @NonNull NetworkStats uidStats) { + try { + getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetAlert} has been reached. + */ + public void notifyAlertReached() { + try { + getProviderCallbackBinderOrThrow().notifyAlertReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetLimit} has been reached. + */ + public void notifyLimitReached() { + try { + getProviderCallbackBinderOrThrow().notifyLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Called by {@code NetworkStatsService} when it requires to know updated stats. + * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. + * Responding later increases the probability stats will be dropped. Memory allowing, the + * system will try to take stats into account up to one minute after calling + * {@link #onRequestStatsUpdate}. + * + * @param token a positive number identifying the new state of the system under which + * {@link NetworkStats} have to be gathered from now on. When this is called, + * custom implementations of providers MUST tally and report the latest stats with + * the previous token, under which stats were being gathered so far. + */ + public abstract void onRequestStatsUpdate(int token); + + /** + * Called by {@code NetworkStatsService} when setting the interface quota for the specified + * upstream interface. When this is called, the custom implementation should block all egress + * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have + * been reached, and MUST respond to it by calling + * {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + */ + public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + + /** + * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations + * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes + * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should + * not block all egress packets. + * + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. + */ + public abstract void onSetAlert(long quotaBytes); +} diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index c5a48106fb..0ceaa69308 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -103,7 +103,7 @@ import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -558,7 +558,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); } @Override @@ -1376,7 +1376,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + invokeForAllStatsProviderCallbacks( + (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); try { mStatsProviderSem.tryAcquire(registeredCallbackCount, MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); @@ -1551,7 +1552,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1820,12 +1821,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * * @param tag a human readable identifier of the custom network stats provider. * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be - * registered. + * {@link NetworkStatsProvider} to be registered. * - * @return a binder interface of - * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be - * used to report events to the system. + * @return a {@link INetworkStatsProviderCallback} binder + * interface, which can be used to report events to the system. */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { @@ -1931,7 +1930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, @Nullable NetworkStats uidStats) { // TODO: 1. Use token to map ifaces to correct NetworkIdentity. // 2. Store the difference and store it directly to the recorder. @@ -1943,12 +1942,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onAlertReached() throws RemoteException { + public void notifyAlertReached() throws RemoteException { mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); } @Override - public void onLimitReached() { + public void notifyLimitReached() { Log.d(TAG, mTag + ": onLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) .onStatsProviderLimitReached(mTag); From 05b2fc228369c54d3daf7fcc50c29a46d8107487 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 16:12:35 +0800 Subject: [PATCH 0728/1150] [SP23] Address misc API review comment about NetworkStats This change add several javadoc for NetworkStats and its Entry class. Also remove IFACE_ALL constant accordlingly. Test: atest FrameworkNetTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: Id1b8f41be79f847ad73197ff0e18258b6ee8a730 --- core/java/android/net/NetworkStats.java | 45 ++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 2f536ffd8c..10f7dbfc57 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,7 +21,6 @@ import static android.os.Process.CLAT_UID; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -58,9 +57,12 @@ import java.util.function.Predicate; public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; - /** {@link #iface} value when interface details unavailable. */ - @SuppressLint("CompileTimeConstant") + /** + * {@link #iface} value when interface details unavailable. + * @hide + */ @Nullable public static final String IFACE_ALL = null; + /** * Virtual network interface for video telephony. This is for VT data usage counting * purpose. @@ -248,7 +250,13 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; - /** @hide */ + /** + * Basic element of network statistics. Contains the number of packets and number of bytes + * transferred on both directions in a given set of conditions. See + * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}. + * + * @hide + */ @SystemApi public static class Entry { /** @hide */ @@ -319,6 +327,35 @@ public final class NetworkStats implements Parcelable { rxBytes, rxPackets, txBytes, txPackets, operations); } + /** + * Construct a {@link Entry} object by giving statistics of packet and byte transferred on + * both direction, and associated with a set of given conditions. + * + * @param iface interface name of this {@link Entry}. Or null if not specified. + * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is + * for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only + * counting iface stats. + * @param set usage state of this {@link Entry}. Should be one of the following + * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}. + * @param tag tag of this {@link Entry}. + * @param metered metered state of this {@link Entry}. Should be one of the following + * values: {link #METERED_YES}, {link #METERED_NO}. + * @param roaming roaming state of this {@link Entry}. Should be one of the following + * values: {link #ROAMING_YES}, {link #ROAMING_NO}. + * @param defaultNetwork default network status of this {@link Entry}. Should be one + * of the following values: {link #DEFAULT_NETWORK_YES}, + * {link #DEFAULT_NETWORK_NO}. + * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param rxPackets Number of packets received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param operations count of network operations performed for this {@link Entry}. This can + * be used to derive bytes-per-operation. + */ public Entry(@Nullable String iface, int uid, @State int set, int tag, @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { From f27a3cd08f02250b8ae2d4c51b60b12b78337b96 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 19:04:17 +0800 Subject: [PATCH 0729/1150] [SP24] Rename functions that add Entry unconditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record unconditionally, name them insertEntry. setIfaceValues -> insertEntry addEntry -> insertEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: I801ddc49e283a254b9586700c9b597c0adb0d459 --- core/java/android/net/NetworkStats.java | 24 +++++++++---------- .../server/net/NetworkStatsFactory.java | 6 ++--- .../server/net/NetworkStatsService.java | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 10f7dbfc57..0fc74b0894 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -503,7 +503,7 @@ public final class NetworkStats implements Parcelable { NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addEntry(entry); + clone.insertEntry(entry); } return clone; } @@ -530,26 +530,26 @@ public final class NetworkStats implements Parcelable { /** @hide */ @VisibleForTesting - public NetworkStats addIfaceValues( + public NetworkStats insertEntry( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addEntry( + return insertEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addEntry(new Entry( + return insertEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { - return addEntry(new Entry( + public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered, + int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { + return insertEntry(new Entry( iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -559,7 +559,7 @@ public final class NetworkStats implements Parcelable { * object can be recycled across multiple calls. * @hide */ - public NetworkStats addEntry(Entry entry) { + public NetworkStats insertEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -702,7 +702,7 @@ public final class NetworkStats implements Parcelable { entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addEntry(entry); + insertEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -1040,7 +1040,7 @@ public final class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addEntry(entry); + result.insertEntry(entry); } return result; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 22b01bee6c..75ffe35674 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addEntry(entry); + stats.insertEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0ceaa69308..619cdc6612 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -759,7 +759,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; From 7eaf6a2d48f62458c375c713f851f5dfe911ef07 Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 15:00:24 +0800 Subject: [PATCH 0730/1150] Fix typo in aosp/1242602 Test: m -j Bug: 149652079 Change-Id: Ie023c8371785fc239c54eacbf056141c2e9e3444 --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0ceaa69308..aa869afa21 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1796,7 +1796,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // TODO: It is copied from ConnectivitySerivce, consider refactor these check permission + // TODO: It is copied from ConnectivityService, consider refactor these check permission // functions to a proper util. private boolean checkAnyPermissionOf(String... permissions) { for (String permission : permissions) { From d53914cadcdd363eadf7c899062b9d82d7de6d36 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Thu, 12 Mar 2020 09:46:43 +0000 Subject: [PATCH 0731/1150] Add permission check functions to NetworkStatsService This is shameless copied from ConnectivityService and plan to be used in follow-up change. For long term perspective we should have a permission util that contains those util in one place. Test: m -j Change-Id: If70e6e831c0386b604d0151cc0650f68457b6e5f Merged-In: If70e6e831c0386b604d0151cc0650f68457b6e5f Merged-In: I837545b54f36c8f21c878cbb1fd028ff23be6cb8 Bug: 149652079 (cherry picked from commit 4da7af7e7e4a0d3360cd41e98e4d6fa731d21515) --- .../server/net/NetworkStatsService.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4af31b0369..cb3da918f4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -23,6 +23,7 @@ import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkStack.checkNetworkStackPermission; @@ -1793,6 +1794,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // TODO: It is copied from ConnectivitySerivce, consider refactor these check permission + // functions to a proper util. + private boolean checkAnyPermissionOf(String... permissions) { + for (String permission : permissions) { + if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) { + return true; + } + } + return false; + } + + private void enforceAnyPermissionOf(String... permissions) { + if (!checkAnyPermissionOf(permissions)) { + throw new SecurityException("Requires one of the following permissions: " + + String.join(", ", permissions) + "."); + } + } + /** * Registers a custom provider of {@link android.net.NetworkStats} to combine the network * statistics that cannot be seen by the kernel to system. To unregister, invoke the From f9dc64e61215ca8a3ddbf2453b903ce27acc009d Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 15:00:24 +0800 Subject: [PATCH 0732/1150] Fix typo in aosp/1242602 Test: m -j Bug: 149652079 Change-Id: Ie023c8371785fc239c54eacbf056141c2e9e3444 Merged-In: Ie023c8371785fc239c54eacbf056141c2e9e3444 (cherry picked from aosp/1259461) --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index cb3da918f4..45047048cc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1794,7 +1794,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // TODO: It is copied from ConnectivitySerivce, consider refactor these check permission + // TODO: It is copied from ConnectivityService, consider refactor these check permission // functions to a proper util. private boolean checkAnyPermissionOf(String... permissions) { for (String permission : permissions) { From b76186859bddc76aeb2a26988733170537003787 Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Thu, 12 Mar 2020 09:46:48 +0000 Subject: [PATCH 0733/1150] [SP20] Check signature permission when accessing network stats provider Currently, registerNetworkStatsProvider requires the UPDATE_DEVICE_STATS permission. This is a privileged permission so it can be granted to preinstalled apps. Thus, apps like GmsCore, or preinstalled apps will be able to update network stats. This change checks for a new permission that would only allow signature apps to declare that. Also check MAINLINE_NETWORK_STACK permission to allow NetworkStack process to use it. Test: adb shell dumpsys netstats Test: atest FrameworksNetTests Bug: 149652079 Change-Id: Iaecbf10a7610461bd52e315659006c7332c416e6 Merged-In: Iaecbf10a7610461bd52e315659006c7332c416e6 Merged-In: Idfebd0a1988c3dcfd812d87e30f6a2034d6fbf6b (cherry picked from commit e9e8d8f9ff096c1723eba1d74b17bb7cade7f23b) --- core/java/android/app/usage/NetworkStatsManager.java | 5 ++++- .../java/com/android/server/net/NetworkStatsService.java | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 5b98188300..7d13f050a7 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -29,6 +29,7 @@ import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; import android.net.NetworkIdentity; +import android.net.NetworkStack; import android.net.NetworkTemplate; import android.net.netstats.provider.AbstractNetworkStatsProvider; import android.net.netstats.provider.NetworkStatsProviderCallback; @@ -540,7 +541,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS) + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull AbstractNetworkStatsProvider provider) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 45047048cc..a6c2c827fa 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.ACCESS_NETWORK_STATE; +import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.content.Intent.ACTION_SHUTDOWN; @@ -1828,7 +1829,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { - mContext.enforceCallingOrSelfPermission(UPDATE_DEVICE_STATS, TAG); + enforceAnyPermissionOf(NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); Objects.requireNonNull(provider, "provider is null"); Objects.requireNonNull(tag, "tag is null"); try { From a42fd8ab38b40fbea0a06972a82e293a7514ef48 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 6 Mar 2020 14:50:48 +0800 Subject: [PATCH 0734/1150] [SP21] Address comments for API council review about aosp/1172143 Test: atest FrameworksNetTests ImsPhoneCallTrackerTest Test: atest TetheringTests NetworkStackTests Test: m doc-comment-check-docs Fix: 148552904 Change-Id: I141393f229e772d2eb9f7c156849e379bd71b845 Merged-In: I141393f229e772d2eb9f7c156849e379bd71b845 (cherry picked from aosp/1253717) --- .../app/usage/NetworkStatsManager.java | 48 +++-- .../provider/INetworkStatsProvider.aidl | 6 +- .../INetworkStatsProviderCallback.aidl | 6 +- .../provider/NetworkStatsProvider.java | 195 ++++++++++++++++++ .../server/net/NetworkStatsService.java | 23 +-- 5 files changed, 245 insertions(+), 33 deletions(-) create mode 100644 core/java/android/net/netstats/provider/NetworkStatsProvider.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 7d13f050a7..d6e77624a9 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -31,9 +31,8 @@ import android.net.INetworkStatsService; import android.net.NetworkIdentity; import android.net.NetworkStack; import android.net.NetworkTemplate; -import android.net.netstats.provider.AbstractNetworkStatsProvider; -import android.net.netstats.provider.NetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderWrapper; +import android.net.netstats.provider.INetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; import android.os.Handler; import android.os.Looper; @@ -528,34 +527,53 @@ public class NetworkStatsManager { /** * Registers a custom provider of {@link android.net.NetworkStats} to provide network statistics - * to the system. To unregister, invoke {@link NetworkStatsProviderCallback#unregister()}. + * to the system. To unregister, invoke {@link #unregisterNetworkStatsProvider}. * Note that no de-duplication of statistics between providers is performed, so each provider - * must only report network traffic that is not being reported by any other provider. + * must only report network traffic that is not being reported by any other provider. Also note + * that the provider cannot be re-registered after unregistering. * * @param tag a human readable identifier of the custom network stats provider. This is only * used for debugging. - * @param provider the subclass of {@link AbstractNetworkStatsProvider} that needs to be + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be * registered to the system. - * @return a {@link NetworkStatsProviderCallback}, which can be used to report events to the - * system or unregister the provider. * @hide */ @SystemApi @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STATS_PROVIDER, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public NetworkStatsProviderCallback registerNetworkStatsProvider( + @NonNull public void registerNetworkStatsProvider( @NonNull String tag, - @NonNull AbstractNetworkStatsProvider provider) { + @NonNull NetworkStatsProvider provider) { try { - final NetworkStatsProviderWrapper wrapper = new NetworkStatsProviderWrapper(provider); - return new NetworkStatsProviderCallback( - mService.registerNetworkStatsProvider(tag, wrapper)); + if (provider.getProviderCallbackBinder() != null) { + throw new IllegalArgumentException("provider is already registered"); + } + final INetworkStatsProviderCallback cbBinder = + mService.registerNetworkStatsProvider(tag, provider.getProviderBinder()); + provider.setProviderCallbackBinder(cbBinder); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Unregisters an instance of {@link NetworkStatsProvider}. + * + * @param provider the subclass of {@link NetworkStatsProvider} that needs to be + * unregistered to the system. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + android.Manifest.permission.NETWORK_STATS_PROVIDER, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) + @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { + try { + provider.getProviderCallbackBinderOrThrow().unregister(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } - // Unreachable code, but compiler doesn't know about it. - return null; } private static NetworkTemplate createTemplate(int networkType, String subscriberId) { diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 55b3d4edb1..4078b24921 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -22,7 +22,7 @@ package android.net.netstats.provider; * @hide */ oneway interface INetworkStatsProvider { - void requestStatsUpdate(int token); - void setLimit(String iface, long quotaBytes); - void setAlert(long quotaBytes); + void onRequestStatsUpdate(int token); + void onSetLimit(String iface, long quotaBytes); + void onSetAlert(long quotaBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 3ea9318f10..bd336dd348 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -24,8 +24,8 @@ import android.net.NetworkStats; * @hide */ oneway interface INetworkStatsProviderCallback { - void onStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); - void onAlertReached(); - void onLimitReached(); + void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); + void notifyAlertReached(); + void notifyLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java new file mode 100644 index 0000000000..7639d2244c --- /dev/null +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats.provider; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.NetworkStats; +import android.os.RemoteException; + +/** + * A base class that allows external modules to implement a custom network statistics provider. + * @hide + */ +@SystemApi +public abstract class NetworkStatsProvider { + /** + * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + */ + public static final int QUOTA_UNLIMITED = -1; + + @NonNull private final INetworkStatsProvider mProviderBinder = + new INetworkStatsProvider.Stub() { + + @Override + public void onRequestStatsUpdate(int token) { + NetworkStatsProvider.this.onRequestStatsUpdate(token); + } + + @Override + public void onSetLimit(String iface, long quotaBytes) { + NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + } + + @Override + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); + } + }; + + // The binder given by the service when successfully registering. Only null before registering, + // never null once non-null. + @Nullable + private INetworkStatsProviderCallback mProviderCbBinder; + + /** + * Return the binder invoked by the service and redirect function calls to the overridden + * methods. + * @hide + */ + @NonNull + public INetworkStatsProvider getProviderBinder() { + return mProviderBinder; + } + + /** + * Store the binder that was returned by the service when successfully registering. Note that + * the provider cannot be re-registered. Hence this method can only be called once per provider. + * + * @hide + */ + public void setProviderCallbackBinder(@NonNull INetworkStatsProviderCallback binder) { + if (mProviderCbBinder != null) { + throw new IllegalArgumentException("provider is already registered"); + } + mProviderCbBinder = binder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Or null if the + * provider was never registered. + * + * @hide + */ + @Nullable + public INetworkStatsProviderCallback getProviderCallbackBinder() { + return mProviderCbBinder; + } + + /** + * Get the binder that was returned by the service when successfully registering. Throw an + * {@link IllegalStateException} if the provider is not registered. + * + * @hide + */ + @NonNull + public INetworkStatsProviderCallback getProviderCallbackBinderOrThrow() { + if (mProviderCbBinder == null) { + throw new IllegalStateException("the provider is not registered"); + } + return mProviderCbBinder; + } + + /** + * Notify the system of new network statistics. + * + * Send the network statistics recorded since the last call to {@link #notifyStatsUpdated}. Must + * be called as soon as possible after {@link NetworkStatsProvider#onRequestStatsUpdate(int)} + * being called. Responding later increases the probability stats will be dropped. The + * provider can also call this whenever it wants to reports new stats for any reason. + * Note that the system will not necessarily immediately propagate the statistics to + * reflect the update. + * + * @param token the token under which these stats were gathered. Providers can call this method + * with the current token as often as they want, until the token changes. + * {@see NetworkStatsProvider#onRequestStatsUpdate()} + * @param ifaceStats the {@link NetworkStats} per interface to be reported. + * The provider should not include any traffic that is already counted by + * kernel interface counters. + * @param uidStats the same stats as above, but counts {@link NetworkStats} + * per uid. + */ + public void notifyStatsUpdated(int token, @NonNull NetworkStats ifaceStats, + @NonNull NetworkStats uidStats) { + try { + getProviderCallbackBinderOrThrow().notifyStatsUpdated(token, ifaceStats, uidStats); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetAlert} has been reached. + */ + public void notifyAlertReached() { + try { + getProviderCallbackBinderOrThrow().notifyAlertReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@code onSetLimit} has been reached. + */ + public void notifyLimitReached() { + try { + getProviderCallbackBinderOrThrow().notifyLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Called by {@code NetworkStatsService} when it requires to know updated stats. + * The provider MUST respond by calling {@link #notifyStatsUpdated} as soon as possible. + * Responding later increases the probability stats will be dropped. Memory allowing, the + * system will try to take stats into account up to one minute after calling + * {@link #onRequestStatsUpdate}. + * + * @param token a positive number identifying the new state of the system under which + * {@link NetworkStats} have to be gathered from now on. When this is called, + * custom implementations of providers MUST tally and report the latest stats with + * the previous token, under which stats were being gathered so far. + */ + public abstract void onRequestStatsUpdate(int token); + + /** + * Called by {@code NetworkStatsService} when setting the interface quota for the specified + * upstream interface. When this is called, the custom implementation should block all egress + * packets on the {@code iface} associated with the provider when {@code quotaBytes} bytes have + * been reached, and MUST respond to it by calling + * {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + */ + public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + + /** + * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations + * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes + * have been reached. Unlike {@link #onSetLimit(String, long)}, the custom implementation should + * not block all egress packets. + * + * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no alert. + */ + public abstract void onSetAlert(long quotaBytes); +} diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index a6c2c827fa..46e865c7e8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -103,7 +103,7 @@ import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; -import android.net.netstats.provider.NetworkStatsProviderCallback; +import android.net.netstats.provider.NetworkStatsProvider; import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; @@ -558,7 +558,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } catch (RemoteException e) { // ignored; service lives in system_server } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setAlert(mGlobalAlertBytes)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetAlert(mGlobalAlertBytes)); } @Override @@ -1376,7 +1376,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.requestStatsUpdate(0 /* unused */)); + invokeForAllStatsProviderCallbacks( + (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); try { mStatsProviderSem.tryAcquire(registeredCallbackCount, MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); @@ -1551,7 +1552,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.setLimit(iface, quota)); + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1820,12 +1821,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * * @param tag a human readable identifier of the custom network stats provider. * @param provider the {@link INetworkStatsProvider} binder corresponding to the - * {@link android.net.netstats.provider.AbstractNetworkStatsProvider} to be - * registered. + * {@link NetworkStatsProvider} to be registered. * - * @return a binder interface of - * {@link android.net.netstats.provider.NetworkStatsProviderCallback}, which can be - * used to report events to the system. + * @return a {@link INetworkStatsProviderCallback} binder + * interface, which can be used to report events to the system. */ public @NonNull INetworkStatsProviderCallback registerNetworkStatsProvider( @NonNull String tag, @NonNull INetworkStatsProvider provider) { @@ -1931,7 +1930,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onStatsUpdated(int token, @Nullable NetworkStats ifaceStats, + public void notifyStatsUpdated(int token, @Nullable NetworkStats ifaceStats, @Nullable NetworkStats uidStats) { // TODO: 1. Use token to map ifaces to correct NetworkIdentity. // 2. Store the difference and store it directly to the recorder. @@ -1943,12 +1942,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void onAlertReached() throws RemoteException { + public void notifyAlertReached() throws RemoteException { mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); } @Override - public void onLimitReached() { + public void notifyLimitReached() { Log.d(TAG, mTag + ": onLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) .onStatsProviderLimitReached(mTag); From 89c23a62eb69f420b57160d1f6622f6f7b27d1b8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 16:12:35 +0800 Subject: [PATCH 0735/1150] [SP23] Address misc API review comment about NetworkStats This change add several javadoc for NetworkStats and its Entry class. Also remove IFACE_ALL constant accordlingly. Test: atest FrameworkNetTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: Id1b8f41be79f847ad73197ff0e18258b6ee8a730 Merged-In: Id1b8f41be79f847ad73197ff0e18258b6ee8a730 (cherry picked from aosp/1256351) --- core/java/android/net/NetworkStats.java | 45 ++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 2f536ffd8c..10f7dbfc57 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,7 +21,6 @@ import static android.os.Process.CLAT_UID; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -58,9 +57,12 @@ import java.util.function.Predicate; public final class NetworkStats implements Parcelable { private static final String TAG = "NetworkStats"; - /** {@link #iface} value when interface details unavailable. */ - @SuppressLint("CompileTimeConstant") + /** + * {@link #iface} value when interface details unavailable. + * @hide + */ @Nullable public static final String IFACE_ALL = null; + /** * Virtual network interface for video telephony. This is for VT data usage counting * purpose. @@ -248,7 +250,13 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage private long[] operations; - /** @hide */ + /** + * Basic element of network statistics. Contains the number of packets and number of bytes + * transferred on both directions in a given set of conditions. See + * {@link Entry#Entry(String, int, int, int, int, int, int, long, long, long, long, long)}. + * + * @hide + */ @SystemApi public static class Entry { /** @hide */ @@ -319,6 +327,35 @@ public final class NetworkStats implements Parcelable { rxBytes, rxPackets, txBytes, txPackets, operations); } + /** + * Construct a {@link Entry} object by giving statistics of packet and byte transferred on + * both direction, and associated with a set of given conditions. + * + * @param iface interface name of this {@link Entry}. Or null if not specified. + * @param uid uid of this {@link Entry}. {@link #UID_TETHERING} if this {@link Entry} is + * for tethering. Or {@link #UID_ALL} if this {@link NetworkStats} is only + * counting iface stats. + * @param set usage state of this {@link Entry}. Should be one of the following + * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}. + * @param tag tag of this {@link Entry}. + * @param metered metered state of this {@link Entry}. Should be one of the following + * values: {link #METERED_YES}, {link #METERED_NO}. + * @param roaming roaming state of this {@link Entry}. Should be one of the following + * values: {link #ROAMING_YES}, {link #ROAMING_NO}. + * @param defaultNetwork default network status of this {@link Entry}. Should be one + * of the following values: {link #DEFAULT_NETWORK_YES}, + * {link #DEFAULT_NETWORK_NO}. + * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param rxPackets Number of packets received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param operations count of network operations performed for this {@link Entry}. This can + * be used to derive bytes-per-operation. + */ public Entry(@Nullable String iface, int uid, @State int set, int tag, @Meteredness int metered, @Roaming int roaming, @DefaultNetwork int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { From 21b5e7f1b205ca43ad6537f5e3b6efbfc2dde1f7 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 13 Mar 2020 19:04:17 +0800 Subject: [PATCH 0736/1150] [SP24] Rename functions that add Entry unconditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record unconditionally, name them insertEntry. setIfaceValues -> insertEntry addEntry -> insertEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Test: m doc-comment-check-docs Bug: 148895143 Change-Id: I801ddc49e283a254b9586700c9b597c0adb0d459 Merged-In: I801ddc49e283a254b9586700c9b597c0adb0d459 (cherry picked from aosp/1256352) --- core/java/android/net/NetworkStats.java | 24 +++++++++---------- .../server/net/NetworkStatsFactory.java | 6 ++--- .../server/net/NetworkStatsService.java | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 10f7dbfc57..0fc74b0894 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -503,7 +503,7 @@ public final class NetworkStats implements Parcelable { NetworkStats.Entry entry = null; for (int i = 0; i < size; i++) { entry = getValues(i, entry); - clone.addEntry(entry); + clone.insertEntry(entry); } return clone; } @@ -530,26 +530,26 @@ public final class NetworkStats implements Parcelable { /** @hide */ @VisibleForTesting - public NetworkStats addIfaceValues( + public NetworkStats insertEntry( String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { - return addEntry( + return insertEntry( iface, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, 0L); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, long rxBytes, + public NetworkStats insertEntry(String iface, int uid, int set, int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - return addEntry(new Entry( + return insertEntry(new Entry( iface, uid, set, tag, rxBytes, rxPackets, txBytes, txPackets, operations)); } /** @hide */ @VisibleForTesting - public NetworkStats addEntry(String iface, int uid, int set, int tag, int metered, int roaming, - int defaultNetwork, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { - return addEntry(new Entry( + public NetworkStats insertEntry(String iface, int uid, int set, int tag, int metered, + int roaming, int defaultNetwork, long rxBytes, long rxPackets, long txBytes, + long txPackets, long operations) { + return insertEntry(new Entry( iface, uid, set, tag, metered, roaming, defaultNetwork, rxBytes, rxPackets, txBytes, txPackets, operations)); } @@ -559,7 +559,7 @@ public final class NetworkStats implements Parcelable { * object can be recycled across multiple calls. * @hide */ - public NetworkStats addEntry(Entry entry) { + public NetworkStats insertEntry(Entry entry) { if (size >= capacity) { final int newLength = Math.max(size, 10) * 3 / 2; iface = Arrays.copyOf(iface, newLength); @@ -702,7 +702,7 @@ public final class NetworkStats implements Parcelable { entry.roaming, entry.defaultNetwork); if (i == -1) { // only create new entry when positive contribution - addEntry(entry); + insertEntry(entry); } else { rxBytes[i] += entry.rxBytes; rxPackets[i] += entry.rxPackets; @@ -1040,7 +1040,7 @@ public final class NetworkStats implements Parcelable { entry.operations = Math.max(entry.operations, 0); } - result.addEntry(entry); + result.insertEntry(entry); } return result; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 22b01bee6c..75ffe35674 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -229,7 +229,7 @@ public class NetworkStatsFactory { entry.txPackets += reader.nextLong(); } - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -279,7 +279,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - stats.addEntry(entry); + stats.insertEntry(entry); reader.finishLine(); } } catch (NullPointerException|NumberFormatException e) { @@ -439,7 +439,7 @@ public class NetworkStatsFactory { if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { - stats.addEntry(entry); + stats.insertEntry(entry); } reader.finishLine(); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 46e865c7e8..10136b3b8b 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -759,7 +759,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); final NetworkStats stats = new NetworkStats(end - start, 1); - stats.addEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, + stats.insertEntry(new NetworkStats.Entry(IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, entry.rxBytes, entry.rxPackets, entry.txBytes, entry.txPackets, entry.operations)); return stats; From 6300ca0896c409bc7f9acf0005eacc46500ab5cb Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 13:27:28 +0800 Subject: [PATCH 0737/1150] [SP25] Rename functions that add Entry conditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record conditionally, name them addEntry. addValues -> addEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Fix: 148895143 Change-Id: I9495a198cf247e6c79100f7ac1edcea370b071de --- core/java/android/net/NetworkStats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0fc74b0894..9c1fb41ecc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -721,7 +721,7 @@ public final class NetworkStats implements Parcelable { * @param entry the {@link Entry} to add. * @return a new constructed {@link NetworkStats} object that contains the result. */ - public @NonNull NetworkStats addValues(@NonNull Entry entry) { + public @NonNull NetworkStats addEntry(@NonNull Entry entry) { return this.clone().combineValues(entry); } From 4ceb6470bd810e92dad8903aa44054492f309aac Mon Sep 17 00:00:00 2001 From: junyulai Date: Mon, 16 Mar 2020 13:27:28 +0800 Subject: [PATCH 0738/1150] [SP25] Rename functions that add Entry conditionally Currently, in NetworkStats, there are many methods to manipulate the records. However, some methods are similar and ambiguous, such as addEntry, addValues, setValues, addIfaceValues, combineValues and combineAllValues. Thus, properly grouping and renaming methods are necessary. In this change, for methods that add one record conditionally, name them addEntry. addValues -> addEntry Test: atest FrameworksNetTests ImsPhoneCallTrackerTest TetheringTests Fix: 148895143 Change-Id: I9495a198cf247e6c79100f7ac1edcea370b071de Merged-In: I9495a198cf247e6c79100f7ac1edcea370b071de (cherry picked from ag/10700816) --- core/java/android/net/NetworkStats.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 0fc74b0894..9c1fb41ecc 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -721,7 +721,7 @@ public final class NetworkStats implements Parcelable { * @param entry the {@link Entry} to add. * @return a new constructed {@link NetworkStats} object that contains the result. */ - public @NonNull NetworkStats addValues(@NonNull Entry entry) { + public @NonNull NetworkStats addEntry(@NonNull Entry entry) { return this.clone().combineValues(entry); } From 96105f0d217a9cc168b0dda72f0125c1624ff692 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 12 Dec 2019 19:42:59 +0800 Subject: [PATCH 0739/1150] [SM02] Support record mobile network stats by collapsed rat type Previously network stats could be recorded by different rat type. However, the feature was disabled by ag/173504 since rat type frequently flapping between HSPA+ and UMTS. Given that this feature might be useful for collecting metrics, re-implement it based on current architecture and reduce the overhead introduced by frequently flapping by: 1. only react when rat type changes between 2G/3G/4G/5G. 2. reduce the number of records by only recording a subset of rat type that represented for a given network class. 3. enforce 1 second rate limit if flapping too much. Note that the feature is still disabled but will be enabled in follow-up patches. Test: manual test Bug: 129082217 Change-Id: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 --- core/java/android/net/NetworkIdentity.java | 15 ++-- core/java/android/net/NetworkTemplate.java | 40 +++++++++ .../server/net/NetworkStatsService.java | 89 ++++++++++++++++++- 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index c1198aac27..b67ad519b4 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.service.NetworkIdentityProto; +import android.telephony.Annotation.NetworkType; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -42,11 +43,8 @@ public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. - * - * @deprecated we no longer offer to collect statistics on a per-subtype - * basis; this is always disabled. */ - @Deprecated + // TODO: make this flag configurable through settings. See http://b/146415925 public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; @@ -187,13 +185,14 @@ public class NetworkIdentity implements Comparable { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState}, - * assuming that any mobile networks are using the current IMSI. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, + * assuming that any mobile networks are using the current IMSI. The subType if applicable, + * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork) { + boolean defaultNetwork, @NetworkType int subType) { final int type = state.networkInfo.getType(); - final int subType = state.networkInfo.getSubtype(); String subscriberId = null; String networkId = null; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5498f74ba2..6080d16b9d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager; import android.util.BackupUtils; import android.util.Log; @@ -394,6 +395,45 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. + * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. + * + * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + */ + // TODO: 1. Consider move this to TelephonyManager if used by other modules. + // 2. Consider make this configurable. + // 3. Use TelephonyManager APIs when available. + public static int getCollapsedRatType(int ratType) { + switch (ratType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GSM: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_IDEN: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_1xRTT: + return TelephonyManager.NETWORK_TYPE_GSM; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return TelephonyManager.NETWORK_TYPE_UMTS; + case TelephonyManager.NETWORK_TYPE_LTE: + case TelephonyManager.NETWORK_TYPE_IWLAN: + return TelephonyManager.NETWORK_TYPE_LTE; + case TelephonyManager.NETWORK_TYPE_NR: + return TelephonyManager.NETWORK_TYPE_NR; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + } + /** * Check if matches Wi-Fi network template. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 10136b3b8b..7c4624d25c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,8 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; @@ -45,6 +47,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; +import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -64,6 +67,9 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; +import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -109,6 +115,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; @@ -125,6 +132,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; @@ -157,6 +166,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -173,6 +183,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; + private static final int MSG_UPDATE_IFACES = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -280,6 +291,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Last states of all networks sent from ConnectivityService. */ + @GuardedBy("mStatsLock") + @Nullable + private NetworkState[] mLastNetworkStates = null; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -355,6 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } + case MSG_UPDATE_IFACES: { + // If no cached states, ignore. + if (mLastNetworkStates == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + break; + } case MSG_PERFORM_POLL_REGISTER_ALERT: { performPoll(FLAG_PERSIST_NETWORK); registerGlobalAlert(); @@ -407,6 +429,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); } /** @@ -486,6 +509,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); + // TODO: listen to changes from all subscriptions. + // watch for networkType changes + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + } + registerGlobalAlert(); } @@ -506,6 +535,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } + final long currentTime = mClock.millis(); // persist any pending stats @@ -1156,6 +1189,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between Radio Access Technology(RAT) types. + */ + @NonNull + private final NetworkTypeListener mPhoneListener; + + class NetworkTypeListener extends PhoneStateListener { + private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; + + NetworkTypeListener(@NonNull Executor executor) { + super(executor); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (LOGV) { + Log.d(TAG, "subtype changed for mobile: " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mLastCollapsedRatType = collapsedRatType; + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + } + private void updateIfaces( Network[] defaultNetworks, NetworkState[] networkStates, @@ -1177,7 +1242,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { + private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + @NonNull NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1197,13 +1263,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } + mLastNetworkStates = states; + final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final int subType = getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, - isDefault); + isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1264,6 +1333,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + /** + * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get + * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that + * other networks with different transport types do not actually fill this value. + */ + private int getSubTypeForState(@NonNull NetworkState state) { + if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; + + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return 0; + } + + // TODO: return different subType for different subscriptions. + return mPhoneListener.mLastCollapsedRatType; + } + private static NetworkIdentitySet findOrCreateNetworkIdentitySet( ArrayMap map, K key) { NetworkIdentitySet ident = map.get(key); From 82d9f7cbb0e684d2de2911be3a0473c3edbc50df Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 20 Dec 2019 16:35:34 +0800 Subject: [PATCH 0740/1150] [SM04] Support fetching data with NetworkTemplate with subType Add a NetworkTemplate build function that allows user to specify subType. NetworkStats corresponding to the same group would be retrieved. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: Ie2d229be0b6bd239f799989c070475c73a096d71 --- core/java/android/net/NetworkTemplate.java | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 6080d16b9d..cb9463a59d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,10 +34,13 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; @@ -74,6 +77,14 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + /** + * Include all network types when filtering. This is meant to merge in with the + * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. + * + * @hide + */ + public static final int NETWORK_TYPE_ALL = -1; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -118,7 +129,22 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * Template to match cellular networks with the given IMSI and {@code ratType}. + * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + */ + public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, + @NetworkType int ratType) { + if (TextUtils.isEmpty(subscriberId)) { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + + /** + * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ @UnsupportedAppUsage @@ -127,7 +153,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, + * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ @UnsupportedAppUsage @@ -193,6 +219,7 @@ public class NetworkTemplate implements Parcelable { private final int mMetered; private final int mRoaming; private final int mDefaultNetwork; + private final int mSubType; @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { @@ -202,11 +229,11 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork) { + String networkId, int metered, int roaming, int defaultNetwork, int subType) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -214,6 +241,7 @@ public class NetworkTemplate implements Parcelable { mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; + mSubType = subType; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -229,6 +257,7 @@ public class NetworkTemplate implements Parcelable { mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); + mSubType = in.readInt(); } @Override @@ -240,6 +269,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); + dest.writeInt(mSubType); } @Override @@ -272,13 +302,16 @@ public class NetworkTemplate implements Parcelable { builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( mDefaultNetwork)); } + if (mSubType != NETWORK_TYPE_ALL) { + builder.append(", subType=").append(mSubType); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork); + mDefaultNetwork, mSubType); } @Override @@ -290,7 +323,8 @@ public class NetworkTemplate implements Parcelable { && Objects.equals(mNetworkId, other.mNetworkId) && mMetered == other.mMetered && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork; + && mDefaultNetwork == other.mDefaultNetwork + && mSubType == other.mSubType; } return false; } @@ -377,6 +411,11 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { + return mSubType == NETWORK_TYPE_ALL + || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -389,9 +428,13 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { + // Only metered mobile network would be matched regardless of metered filter. + // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. + // TODO: Respect metered filter and remove mMetered condition. return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + && matchesCollapsedRatType(ident); } } @@ -461,7 +504,8 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && matchesCollapsedRatType(ident); } } From 8413d3c1af0f6bdf5a9dbf0ef28c48e99f599a93 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 31 Dec 2019 13:40:15 +0800 Subject: [PATCH 0741/1150] [SM05] Enable record mobile network stats by collapsed rat type Switch on the recording in device side. Metrics will be collected in follow-up patches which can be independently enabled/disabled. This change also fix the fail in NetworkStatsCollectionTest which caused by enabling this feature, where the rounding problem happened when records are distributed into smaller buckets and categorized into more NetworkIdentity. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: If330e85330a4ff713dd420c98d42fa741eabd90a --- core/java/android/net/NetworkIdentity.java | 2 +- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b67ad519b4..2cf3531d2f 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -45,7 +45,7 @@ public class NetworkIdentity implements Comparable { * {@link #SUBTYPE_COMBINED}. */ // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = true; + public static final boolean COMBINE_SUBTYPE_ENABLED = false; public static final int SUBTYPE_COMBINED = -1; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7c4624d25c..ff4407aa12 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1209,7 +1209,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; - if (LOGV) { + if (LOGD) { Log.d(TAG, "subtype changed for mobile: " + mLastCollapsedRatType + " -> " + collapsedRatType); } @@ -1217,7 +1217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler.removeMessages(MSG_UPDATE_IFACES); mLastCollapsedRatType = collapsedRatType; mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } } From 2c31ca121194fdc3867b02d5d46786ae50d5d617 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 12 Dec 2019 19:42:59 +0800 Subject: [PATCH 0742/1150] [SM02] Support record mobile network stats by collapsed rat type Previously network stats could be recorded by different rat type. However, the feature was disabled by ag/173504 since rat type frequently flapping between HSPA+ and UMTS. Given that this feature might be useful for collecting metrics, re-implement it based on current architecture and reduce the overhead introduced by frequently flapping by: 1. only react when rat type changes between 2G/3G/4G/5G. 2. reduce the number of records by only recording a subset of rat type that represented for a given network class. 3. enforce 1 second rate limit if flapping too much. Note that the feature is still disabled but will be enabled in follow-up patches. Test: manual test Bug: 129082217 Change-Id: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 Merged-In: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 (cherry picked from commit 15ab452e7e3f00289fbedbdb86c512ad560dda7e) --- core/java/android/net/NetworkIdentity.java | 15 ++-- core/java/android/net/NetworkTemplate.java | 40 +++++++++ .../server/net/NetworkStatsService.java | 89 ++++++++++++++++++- 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index c1198aac27..b67ad519b4 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.service.NetworkIdentityProto; +import android.telephony.Annotation.NetworkType; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -42,11 +43,8 @@ public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. - * - * @deprecated we no longer offer to collect statistics on a per-subtype - * basis; this is always disabled. */ - @Deprecated + // TODO: make this flag configurable through settings. See http://b/146415925 public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; @@ -187,13 +185,14 @@ public class NetworkIdentity implements Comparable { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState}, - * assuming that any mobile networks are using the current IMSI. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, + * assuming that any mobile networks are using the current IMSI. The subType if applicable, + * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork) { + boolean defaultNetwork, @NetworkType int subType) { final int type = state.networkInfo.getType(); - final int subType = state.networkInfo.getSubtype(); String subscriberId = null; String networkId = null; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5498f74ba2..6080d16b9d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager; import android.util.BackupUtils; import android.util.Log; @@ -394,6 +395,45 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. + * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. + * + * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + */ + // TODO: 1. Consider move this to TelephonyManager if used by other modules. + // 2. Consider make this configurable. + // 3. Use TelephonyManager APIs when available. + public static int getCollapsedRatType(int ratType) { + switch (ratType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GSM: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_IDEN: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_1xRTT: + return TelephonyManager.NETWORK_TYPE_GSM; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return TelephonyManager.NETWORK_TYPE_UMTS; + case TelephonyManager.NETWORK_TYPE_LTE: + case TelephonyManager.NETWORK_TYPE_IWLAN: + return TelephonyManager.NETWORK_TYPE_LTE; + case TelephonyManager.NETWORK_TYPE_NR: + return TelephonyManager.NETWORK_TYPE_NR; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + } + /** * Check if matches Wi-Fi network template. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 10136b3b8b..7c4624d25c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,8 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; @@ -45,6 +47,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; +import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -64,6 +67,9 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; +import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -109,6 +115,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; @@ -125,6 +132,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; @@ -157,6 +166,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -173,6 +183,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; + private static final int MSG_UPDATE_IFACES = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -280,6 +291,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Last states of all networks sent from ConnectivityService. */ + @GuardedBy("mStatsLock") + @Nullable + private NetworkState[] mLastNetworkStates = null; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -355,6 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } + case MSG_UPDATE_IFACES: { + // If no cached states, ignore. + if (mLastNetworkStates == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + break; + } case MSG_PERFORM_POLL_REGISTER_ALERT: { performPoll(FLAG_PERSIST_NETWORK); registerGlobalAlert(); @@ -407,6 +429,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); } /** @@ -486,6 +509,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); + // TODO: listen to changes from all subscriptions. + // watch for networkType changes + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + } + registerGlobalAlert(); } @@ -506,6 +535,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } + final long currentTime = mClock.millis(); // persist any pending stats @@ -1156,6 +1189,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between Radio Access Technology(RAT) types. + */ + @NonNull + private final NetworkTypeListener mPhoneListener; + + class NetworkTypeListener extends PhoneStateListener { + private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; + + NetworkTypeListener(@NonNull Executor executor) { + super(executor); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (LOGV) { + Log.d(TAG, "subtype changed for mobile: " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mLastCollapsedRatType = collapsedRatType; + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + } + private void updateIfaces( Network[] defaultNetworks, NetworkState[] networkStates, @@ -1177,7 +1242,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { + private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + @NonNull NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1197,13 +1263,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } + mLastNetworkStates = states; + final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final int subType = getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, - isDefault); + isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1264,6 +1333,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + /** + * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get + * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that + * other networks with different transport types do not actually fill this value. + */ + private int getSubTypeForState(@NonNull NetworkState state) { + if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; + + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return 0; + } + + // TODO: return different subType for different subscriptions. + return mPhoneListener.mLastCollapsedRatType; + } + private static NetworkIdentitySet findOrCreateNetworkIdentitySet( ArrayMap map, K key) { NetworkIdentitySet ident = map.get(key); From b62cac012f29bf5429733d1532093cbd1471278a Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 20 Dec 2019 16:35:34 +0800 Subject: [PATCH 0743/1150] [SM04] Support fetching data with NetworkTemplate with subType Add a NetworkTemplate build function that allows user to specify subType. NetworkStats corresponding to the same group would be retrieved. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: Ie2d229be0b6bd239f799989c070475c73a096d71 Merged-In: Ie2d229be0b6bd239f799989c070475c73a096d71 (cherry picked from commit e19045cc4ab1f2cd133ce5dc0c3a38e3275417ad) --- core/java/android/net/NetworkTemplate.java | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 6080d16b9d..cb9463a59d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,10 +34,13 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; @@ -74,6 +77,14 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + /** + * Include all network types when filtering. This is meant to merge in with the + * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. + * + * @hide + */ + public static final int NETWORK_TYPE_ALL = -1; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -118,7 +129,22 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * Template to match cellular networks with the given IMSI and {@code ratType}. + * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + */ + public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, + @NetworkType int ratType) { + if (TextUtils.isEmpty(subscriberId)) { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + + /** + * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ @UnsupportedAppUsage @@ -127,7 +153,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, + * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ @UnsupportedAppUsage @@ -193,6 +219,7 @@ public class NetworkTemplate implements Parcelable { private final int mMetered; private final int mRoaming; private final int mDefaultNetwork; + private final int mSubType; @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { @@ -202,11 +229,11 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork) { + String networkId, int metered, int roaming, int defaultNetwork, int subType) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -214,6 +241,7 @@ public class NetworkTemplate implements Parcelable { mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; + mSubType = subType; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -229,6 +257,7 @@ public class NetworkTemplate implements Parcelable { mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); + mSubType = in.readInt(); } @Override @@ -240,6 +269,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); + dest.writeInt(mSubType); } @Override @@ -272,13 +302,16 @@ public class NetworkTemplate implements Parcelable { builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( mDefaultNetwork)); } + if (mSubType != NETWORK_TYPE_ALL) { + builder.append(", subType=").append(mSubType); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork); + mDefaultNetwork, mSubType); } @Override @@ -290,7 +323,8 @@ public class NetworkTemplate implements Parcelable { && Objects.equals(mNetworkId, other.mNetworkId) && mMetered == other.mMetered && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork; + && mDefaultNetwork == other.mDefaultNetwork + && mSubType == other.mSubType; } return false; } @@ -377,6 +411,11 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { + return mSubType == NETWORK_TYPE_ALL + || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -389,9 +428,13 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { + // Only metered mobile network would be matched regardless of metered filter. + // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. + // TODO: Respect metered filter and remove mMetered condition. return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + && matchesCollapsedRatType(ident); } } @@ -461,7 +504,8 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && matchesCollapsedRatType(ident); } } From 3b85859418251660facac984b35d97fbdd47e1fd Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 31 Dec 2019 13:40:15 +0800 Subject: [PATCH 0744/1150] [SM05] Enable record mobile network stats by collapsed rat type Switch on the recording in device side. Metrics will be collected in follow-up patches which can be independently enabled/disabled. This change also fix the fail in NetworkStatsCollectionTest which caused by enabling this feature, where the rounding problem happened when records are distributed into smaller buckets and categorized into more NetworkIdentity. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: If330e85330a4ff713dd420c98d42fa741eabd90a Merged-In: If330e85330a4ff713dd420c98d42fa741eabd90a (cherry picked from commit 2d4fa2c0fae8c2d79a25093d9f732a33c2f91dd4) --- core/java/android/net/NetworkIdentity.java | 2 +- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b67ad519b4..2cf3531d2f 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -45,7 +45,7 @@ public class NetworkIdentity implements Comparable { * {@link #SUBTYPE_COMBINED}. */ // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = true; + public static final boolean COMBINE_SUBTYPE_ENABLED = false; public static final int SUBTYPE_COMBINED = -1; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7c4624d25c..ff4407aa12 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1209,7 +1209,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; - if (LOGV) { + if (LOGD) { Log.d(TAG, "subtype changed for mobile: " + mLastCollapsedRatType + " -> " + collapsedRatType); } @@ -1217,7 +1217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler.removeMessages(MSG_UPDATE_IFACES); mLastCollapsedRatType = collapsedRatType; mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } } From 1227f32c58a839b6e9a0d765fff73bd9e1a84541 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Jan 2020 19:35:59 +0800 Subject: [PATCH 0745/1150] [SM07] Make combine subtype configurable from Settings Note that enabling/disabling would not take effect until device reboot. This will be addressed in follow-up patch. Test: 1. atest NetworkStatsServieTest SettingsBackupTest 2. adb shell settings put global netstats_combine_subtype_enabled 1|0 Bug: 146415925 Change-Id: Ic94da540afa479ed18f1b6fbda4ae3216c37476b --- core/java/android/net/NetworkIdentity.java | 11 +-- .../server/net/NetworkStatsService.java | 69 ++++++++++++------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 2cf3531d2f..0948a4da1a 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -40,13 +40,6 @@ import java.util.Objects; public class NetworkIdentity implements Comparable { private static final String TAG = "NetworkIdentity"; - /** - * When enabled, combine all {@link #mSubType} together under - * {@link #SUBTYPE_COMBINED}. - */ - // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = false; - public static final int SUBTYPE_COMBINED = -1; final int mType; @@ -61,7 +54,7 @@ public class NetworkIdentity implements Comparable { int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork) { mType = type; - mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; + mSubType = subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; @@ -93,7 +86,7 @@ public class NetworkIdentity implements Comparable { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); - if (COMBINE_SUBTYPE_ENABLED) { + if (mSubType == SUBTYPE_COMBINED) { builder.append("COMBINED"); } else { builder.append(mSubType); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ff4407aa12..d8264b3625 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,7 +27,6 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -52,6 +51,7 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; +import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; @@ -240,12 +240,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public long getPollInterval(); - public long getPollDelay(); - public boolean getSampleEnabled(); - public boolean getAugmentEnabled(); + long getPollInterval(); + long getPollDelay(); + boolean getSampleEnabled(); + boolean getAugmentEnabled(); + /** + * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}. + * When disabled, mobile data is broken down by a granular subtype representative of the + * actual subtype. {@see NetworkTemplate#getCollapsedRatType}. + * Enabling this decreases the level of detail but saves performance, disk space and + * amount of data logged. + */ + boolean getCombineSubtypeEnabled(); - public static class Config { + class Config { public final long bucketDuration; public final long rotateAgeMillis; public final long deleteAgeMillis; @@ -257,16 +265,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public Config getDevConfig(); - public Config getXtConfig(); - public Config getUidConfig(); - public Config getUidTagConfig(); + Config getDevConfig(); + Config getXtConfig(); + Config getUidConfig(); + Config getUidTagConfig(); - public long getGlobalAlertBytes(long def); - public long getDevPersistBytes(long def); - public long getXtPersistBytes(long def); - public long getUidPersistBytes(long def); - public long getUidTagPersistBytes(long def); + long getGlobalAlertBytes(long def); + long getDevPersistBytes(long def); + long getXtPersistBytes(long def); + long getUidPersistBytes(long def); + long getUidTagPersistBytes(long def); } private final Object mStatsLock = new Object(); @@ -509,9 +517,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: listen to changes from all subscriptions. + // TODO: 1. listen to changes from all subscriptions. + // 2. listen to settings changed to support dynamically enable/disable. // watch for networkType changes - if (!COMBINE_SUBTYPE_ENABLED) { + if (!mSettings.getCombineSubtypeEnabled()) { mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); } @@ -535,9 +544,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } + mTeleManager.listen(mPhoneListener, LISTEN_NONE); final long currentTime = mClock.millis(); @@ -1265,12 +1272,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastNetworkStates = states; + final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); - final int subType = getSubTypeForState(state); + final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED + : getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, isDefault, subType); @@ -1334,13 +1343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get - * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that - * other networks with different transport types do not actually fill this value. + * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through + * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different + * transport types do not actually fill this value. */ private int getSubTypeForState(@NonNull NetworkState state) { - if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } @@ -1702,6 +1709,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + pw.println("Configs:"); + pw.increaseIndent(); + pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); + pw.println(); + pw.decreaseIndent(); + pw.println("Active interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveIfaces.size(); i++) { @@ -2130,6 +2143,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); } @Override + public boolean getCombineSubtypeEnabled() { + return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false); + } + @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 187a7b1ad85917a03daab13fb504c084b5c3d0d9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 17 Mar 2020 00:16:13 +0900 Subject: [PATCH 0746/1150] Make Ethernet interfaces more testable. This CL adds a setIncludeTestInterfaces method to EthernetManager that, when called, causes the Ethernet service to recognize and manage test interfaces created by TestNetworkManager. Bug: 150644681 Test: Tested by EthernetTetheringTest in same topic Change-Id: I86eef7a93267f800dbfc8eafd307effa76a344ca --- core/java/android/net/EthernetManager.java | 15 +++++++++++++++ core/java/android/net/IEthernetManager.aidl | 1 + 2 files changed, 16 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 83b5f63576..d975017f9c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -199,6 +199,21 @@ public class EthernetManager { } } + /** + * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} + * as Ethernet interfaces. The effects of this method apply to any test interfaces that are + * already present on the system. + * @hide + */ + @TestApi + public void setIncludeTestInterfaces(boolean include) { + try { + mService.setIncludeTestInterfaces(include); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * A request for a tethered interface. */ diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index ccc6e35209..e058e5a70c 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -33,6 +33,7 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } From 3845301fc73b9c67ea5de32f49853ede2fab0d13 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Jan 2020 19:35:59 +0800 Subject: [PATCH 0747/1150] [SM07] Make combine subtype configurable from Settings Note that enabling/disabling would not take effect until device reboot. This will be addressed in follow-up patch. Test: 1. atest NetworkStatsServieTest SettingsBackupTest 2. adb shell settings put global netstats_combine_subtype_enabled 1|0 Bug: 146415925 Change-Id: Ic94da540afa479ed18f1b6fbda4ae3216c37476b Merged-In: Ic94da540afa479ed18f1b6fbda4ae3216c37476b (cherry picked from commit c4f77ac90bf2e48a655ad19b162fe74a23bf3fb0) --- core/java/android/net/NetworkIdentity.java | 11 +-- .../server/net/NetworkStatsService.java | 69 ++++++++++++------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 2cf3531d2f..0948a4da1a 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -40,13 +40,6 @@ import java.util.Objects; public class NetworkIdentity implements Comparable { private static final String TAG = "NetworkIdentity"; - /** - * When enabled, combine all {@link #mSubType} together under - * {@link #SUBTYPE_COMBINED}. - */ - // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = false; - public static final int SUBTYPE_COMBINED = -1; final int mType; @@ -61,7 +54,7 @@ public class NetworkIdentity implements Comparable { int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork) { mType = type; - mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; + mSubType = subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; @@ -93,7 +86,7 @@ public class NetworkIdentity implements Comparable { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); - if (COMBINE_SUBTYPE_ENABLED) { + if (mSubType == SUBTYPE_COMBINED) { builder.append("COMBINED"); } else { builder.append(mSubType); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ff4407aa12..d8264b3625 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,7 +27,6 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -52,6 +51,7 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; +import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; @@ -240,12 +240,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public long getPollInterval(); - public long getPollDelay(); - public boolean getSampleEnabled(); - public boolean getAugmentEnabled(); + long getPollInterval(); + long getPollDelay(); + boolean getSampleEnabled(); + boolean getAugmentEnabled(); + /** + * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}. + * When disabled, mobile data is broken down by a granular subtype representative of the + * actual subtype. {@see NetworkTemplate#getCollapsedRatType}. + * Enabling this decreases the level of detail but saves performance, disk space and + * amount of data logged. + */ + boolean getCombineSubtypeEnabled(); - public static class Config { + class Config { public final long bucketDuration; public final long rotateAgeMillis; public final long deleteAgeMillis; @@ -257,16 +265,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public Config getDevConfig(); - public Config getXtConfig(); - public Config getUidConfig(); - public Config getUidTagConfig(); + Config getDevConfig(); + Config getXtConfig(); + Config getUidConfig(); + Config getUidTagConfig(); - public long getGlobalAlertBytes(long def); - public long getDevPersistBytes(long def); - public long getXtPersistBytes(long def); - public long getUidPersistBytes(long def); - public long getUidTagPersistBytes(long def); + long getGlobalAlertBytes(long def); + long getDevPersistBytes(long def); + long getXtPersistBytes(long def); + long getUidPersistBytes(long def); + long getUidTagPersistBytes(long def); } private final Object mStatsLock = new Object(); @@ -509,9 +517,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: listen to changes from all subscriptions. + // TODO: 1. listen to changes from all subscriptions. + // 2. listen to settings changed to support dynamically enable/disable. // watch for networkType changes - if (!COMBINE_SUBTYPE_ENABLED) { + if (!mSettings.getCombineSubtypeEnabled()) { mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); } @@ -535,9 +544,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } + mTeleManager.listen(mPhoneListener, LISTEN_NONE); final long currentTime = mClock.millis(); @@ -1265,12 +1272,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastNetworkStates = states; + final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); - final int subType = getSubTypeForState(state); + final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED + : getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, isDefault, subType); @@ -1334,13 +1343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get - * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that - * other networks with different transport types do not actually fill this value. + * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through + * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different + * transport types do not actually fill this value. */ private int getSubTypeForState(@NonNull NetworkState state) { - if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } @@ -1702,6 +1709,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + pw.println("Configs:"); + pw.increaseIndent(); + pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); + pw.println(); + pw.decreaseIndent(); + pw.println("Active interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveIfaces.size(); i++) { @@ -2130,6 +2143,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); } @Override + public boolean getCombineSubtypeEnabled() { + return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false); + } + @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 55962ad9cb8a7285a6238eddde7db4ed03297609 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 12 Dec 2019 19:42:59 +0800 Subject: [PATCH 0748/1150] [SM02] Support record mobile network stats by collapsed rat type Previously network stats could be recorded by different rat type. However, the feature was disabled by ag/173504 since rat type frequently flapping between HSPA+ and UMTS. Given that this feature might be useful for collecting metrics, re-implement it based on current architecture and reduce the overhead introduced by frequently flapping by: 1. only react when rat type changes between 2G/3G/4G/5G. 2. reduce the number of records by only recording a subset of rat type that represented for a given network class. 3. enforce 1 second rate limit if flapping too much. Note that the feature is still disabled but will be enabled in follow-up patches. Test: manual test Bug: 129082217 Change-Id: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 Merged-In: Ic6b2f10f2c8b082820e0662eb9cee70d70d28cd6 (cherry picked from commit 96105f0d217a9cc168b0dda72f0125c1624ff692) --- core/java/android/net/NetworkIdentity.java | 15 ++-- core/java/android/net/NetworkTemplate.java | 40 +++++++++ .../server/net/NetworkStatsService.java | 89 ++++++++++++++++++- 3 files changed, 134 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index febc730480..1f7defcc82 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -25,6 +25,7 @@ import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.Build; import android.service.NetworkIdentityProto; +import android.telephony.Annotation.NetworkType; import android.util.Slog; import android.util.proto.ProtoOutputStream; @@ -42,11 +43,8 @@ public class NetworkIdentity implements Comparable { /** * When enabled, combine all {@link #mSubType} together under * {@link #SUBTYPE_COMBINED}. - * - * @deprecated we no longer offer to collect statistics on a per-subtype - * basis; this is always disabled. */ - @Deprecated + // TODO: make this flag configurable through settings. See http://b/146415925 public static final boolean COMBINE_SUBTYPE_ENABLED = true; public static final int SUBTYPE_COMBINED = -1; @@ -187,13 +185,14 @@ public class NetworkIdentity implements Comparable { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState}, - * assuming that any mobile networks are using the current IMSI. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, + * assuming that any mobile networks are using the current IMSI. The subType if applicable, + * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or + * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork) { + boolean defaultNetwork, @NetworkType int subType) { final int type = state.networkInfo.getType(); - final int subType = state.networkInfo.getSubtype(); String subscriberId = null; String networkId = null; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 5498f74ba2..6080d16b9d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.TelephonyManager; import android.util.BackupUtils; import android.util.Log; @@ -394,6 +395,45 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. + * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. + * + * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + */ + // TODO: 1. Consider move this to TelephonyManager if used by other modules. + // 2. Consider make this configurable. + // 3. Use TelephonyManager APIs when available. + public static int getCollapsedRatType(int ratType) { + switch (ratType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GSM: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_IDEN: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_1xRTT: + return TelephonyManager.NETWORK_TYPE_GSM; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return TelephonyManager.NETWORK_TYPE_UMTS; + case TelephonyManager.NETWORK_TYPE_LTE: + case TelephonyManager.NETWORK_TYPE_IWLAN: + return TelephonyManager.NETWORK_TYPE_LTE; + case TelephonyManager.NETWORK_TYPE_NR: + return TelephonyManager.NETWORK_TYPE_NR; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + } + /** * Check if matches Wi-Fi network template. */ diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 88fc0a6b11..efa638ad54 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,6 +27,8 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; +import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; @@ -45,6 +47,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; +import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -64,6 +67,9 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.PhoneStateListener.LISTEN_NONE; +import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; +import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -109,6 +115,7 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkManagementService; @@ -125,6 +132,8 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; import android.telephony.TelephonyManager; import android.text.format.DateUtils; @@ -157,6 +166,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -173,6 +183,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; + private static final int MSG_UPDATE_IFACES = 3; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -280,6 +291,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Last states of all networks sent from ConnectivityService. */ + @GuardedBy("mStatsLock") + @Nullable + private NetworkState[] mLastNetworkStates = null; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -355,6 +371,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } + case MSG_UPDATE_IFACES: { + // If no cached states, ignore. + if (mLastNetworkStates == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + break; + } case MSG_PERFORM_POLL_REGISTER_ALERT: { performPoll(FLAG_PERSIST_NETWORK); registerGlobalAlert(); @@ -407,6 +429,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); + mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); } /** @@ -486,6 +509,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); + // TODO: listen to changes from all subscriptions. + // watch for networkType changes + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + } + registerGlobalAlert(); } @@ -506,6 +535,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); + if (!COMBINE_SUBTYPE_ENABLED) { + mTeleManager.listen(mPhoneListener, LISTEN_NONE); + } + final long currentTime = mClock.millis(); // persist any pending stats @@ -1156,6 +1189,38 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; + /** + * Receiver that watches for {@link TelephonyManager} changes, such as + * transitioning between Radio Access Technology(RAT) types. + */ + @NonNull + private final NetworkTypeListener mPhoneListener; + + class NetworkTypeListener extends PhoneStateListener { + private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; + + NetworkTypeListener(@NonNull Executor executor) { + super(executor); + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (LOGV) { + Log.d(TAG, "subtype changed for mobile: " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mLastCollapsedRatType = collapsedRatType; + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + } + } + private void updateIfaces( Network[] defaultNetworks, NetworkState[] networkStates, @@ -1177,7 +1242,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { + private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + @NonNull NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1197,13 +1263,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } + mLastNetworkStates = states; + final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final int subType = getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, - isDefault); + isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1264,6 +1333,22 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + /** + * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get + * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that + * other networks with different transport types do not actually fill this value. + */ + private int getSubTypeForState(@NonNull NetworkState state) { + if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; + + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + return 0; + } + + // TODO: return different subType for different subscriptions. + return mPhoneListener.mLastCollapsedRatType; + } + private static NetworkIdentitySet findOrCreateNetworkIdentitySet( ArrayMap map, K key) { NetworkIdentitySet ident = map.get(key); From d83a0e0d1ea5e46582c3ab2fcfbdb6d195fc053b Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 20 Dec 2019 16:35:34 +0800 Subject: [PATCH 0749/1150] [SM04] Support fetching data with NetworkTemplate with subType Add a NetworkTemplate build function that allows user to specify subType. NetworkStats corresponding to the same group would be retrieved. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: Ie2d229be0b6bd239f799989c070475c73a096d71 Merged-In: Ie2d229be0b6bd239f799989c070475c73a096d71 (cherry picked from commit 82d9f7cbb0e684d2de2911be3a0473c3edbc50df) --- core/java/android/net/NetworkTemplate.java | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 6080d16b9d..cb9463a59d 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,10 +34,13 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; import android.os.Parcelable; +import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; @@ -74,6 +77,14 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + /** + * Include all network types when filtering. This is meant to merge in with the + * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. + * + * @hide + */ + public static final int NETWORK_TYPE_ALL = -1; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -118,7 +129,22 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks, + * Template to match cellular networks with the given IMSI and {@code ratType}. + * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + */ + public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, + @NetworkType int ratType) { + if (TextUtils.isEmpty(subscriberId)) { + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + } + + /** + * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ @UnsupportedAppUsage @@ -127,7 +153,7 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks, + * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. */ @UnsupportedAppUsage @@ -193,6 +219,7 @@ public class NetworkTemplate implements Parcelable { private final int mMetered; private final int mRoaming; private final int mDefaultNetwork; + private final int mSubType; @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { @@ -202,11 +229,11 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork) { + String networkId, int metered, int roaming, int defaultNetwork, int subType) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -214,6 +241,7 @@ public class NetworkTemplate implements Parcelable { mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; + mSubType = subType; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -229,6 +257,7 @@ public class NetworkTemplate implements Parcelable { mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); + mSubType = in.readInt(); } @Override @@ -240,6 +269,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); + dest.writeInt(mSubType); } @Override @@ -272,13 +302,16 @@ public class NetworkTemplate implements Parcelable { builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( mDefaultNetwork)); } + if (mSubType != NETWORK_TYPE_ALL) { + builder.append(", subType=").append(mSubType); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork); + mDefaultNetwork, mSubType); } @Override @@ -290,7 +323,8 @@ public class NetworkTemplate implements Parcelable { && Objects.equals(mNetworkId, other.mNetworkId) && mMetered == other.mMetered && mRoaming == other.mRoaming - && mDefaultNetwork == other.mDefaultNetwork; + && mDefaultNetwork == other.mDefaultNetwork + && mSubType == other.mSubType; } return false; } @@ -377,6 +411,11 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { + return mSubType == NETWORK_TYPE_ALL + || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); + } + public boolean matchesSubscriberId(String subscriberId) { return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -389,9 +428,13 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { + // Only metered mobile network would be matched regardless of metered filter. + // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. + // TODO: Respect metered filter and remove mMetered condition. return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + && matchesCollapsedRatType(ident); } } @@ -461,7 +504,8 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered); + return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + && matchesCollapsedRatType(ident); } } From b2067520a2736c6b80ea28b46350946c25e1ad4a Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 31 Dec 2019 13:40:15 +0800 Subject: [PATCH 0750/1150] [SM05] Enable record mobile network stats by collapsed rat type Switch on the recording in device side. Metrics will be collected in follow-up patches which can be independently enabled/disabled. This change also fix the fail in NetworkStatsCollectionTest which caused by enabling this feature, where the rounding problem happened when records are distributed into smaller buckets and categorized into more NetworkIdentity. Test: atest FrameworksNetTests Bug: 129082217 Change-Id: If330e85330a4ff713dd420c98d42fa741eabd90a Merged-In: If330e85330a4ff713dd420c98d42fa741eabd90a (cherry picked from commit 8413d3c1af0f6bdf5a9dbf0ef28c48e99f599a93) --- core/java/android/net/NetworkIdentity.java | 2 +- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1f7defcc82..4e33770bf2 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -45,7 +45,7 @@ public class NetworkIdentity implements Comparable { * {@link #SUBTYPE_COMBINED}. */ // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = true; + public static final boolean COMBINE_SUBTYPE_ENABLED = false; public static final int SUBTYPE_COMBINED = -1; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index efa638ad54..8f4c6d02ba 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1209,7 +1209,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; - if (LOGV) { + if (LOGD) { Log.d(TAG, "subtype changed for mobile: " + mLastCollapsedRatType + " -> " + collapsedRatType); } @@ -1217,7 +1217,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler.removeMessages(MSG_UPDATE_IFACES); mLastCollapsedRatType = collapsedRatType; mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS); + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } } From f6f863428eedb74d4e4baa56378e6012ceedb9ca Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Jan 2020 19:35:59 +0800 Subject: [PATCH 0751/1150] [SM07] Make combine subtype configurable from Settings Note that enabling/disabling would not take effect until device reboot. This will be addressed in follow-up patch. Test: 1. atest NetworkStatsServieTest SettingsBackupTest 2. adb shell settings put global netstats_combine_subtype_enabled 1|0 Bug: 146415925 Change-Id: Ic94da540afa479ed18f1b6fbda4ae3216c37476b Merged-In: Ic94da540afa479ed18f1b6fbda4ae3216c37476b (cherry picked from commit 1227f32c58a839b6e9a0d765fff73bd9e1a84541 and fix merge conflict in SettingsBackupTest) --- core/java/android/net/NetworkIdentity.java | 11 +-- .../server/net/NetworkStatsService.java | 69 ++++++++++++------- 2 files changed, 45 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 4e33770bf2..4edbcd0ac8 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -40,13 +40,6 @@ import java.util.Objects; public class NetworkIdentity implements Comparable { private static final String TAG = "NetworkIdentity"; - /** - * When enabled, combine all {@link #mSubType} together under - * {@link #SUBTYPE_COMBINED}. - */ - // TODO: make this flag configurable through settings. See http://b/146415925 - public static final boolean COMBINE_SUBTYPE_ENABLED = false; - public static final int SUBTYPE_COMBINED = -1; final int mType; @@ -61,7 +54,7 @@ public class NetworkIdentity implements Comparable { int type, int subType, String subscriberId, String networkId, boolean roaming, boolean metered, boolean defaultNetwork) { mType = type; - mSubType = COMBINE_SUBTYPE_ENABLED ? SUBTYPE_COMBINED : subType; + mSubType = subType; mSubscriberId = subscriberId; mNetworkId = networkId; mRoaming = roaming; @@ -93,7 +86,7 @@ public class NetworkIdentity implements Comparable { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(getNetworkTypeName(mType)); builder.append(", subType="); - if (COMBINE_SUBTYPE_ENABLED) { + if (mSubType == SUBTYPE_COMBINED) { builder.append("COMBINED"); } else { builder.append(mSubType); diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 8f4c6d02ba..2680858743 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -27,7 +27,6 @@ import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; -import static android.net.NetworkIdentity.COMBINE_SUBTYPE_ENABLED; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -52,6 +51,7 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; +import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; @@ -240,12 +240,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Settings that can be changed externally. */ public interface NetworkStatsSettings { - public long getPollInterval(); - public long getPollDelay(); - public boolean getSampleEnabled(); - public boolean getAugmentEnabled(); + long getPollInterval(); + long getPollDelay(); + boolean getSampleEnabled(); + boolean getAugmentEnabled(); + /** + * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}. + * When disabled, mobile data is broken down by a granular subtype representative of the + * actual subtype. {@see NetworkTemplate#getCollapsedRatType}. + * Enabling this decreases the level of detail but saves performance, disk space and + * amount of data logged. + */ + boolean getCombineSubtypeEnabled(); - public static class Config { + class Config { public final long bucketDuration; public final long rotateAgeMillis; public final long deleteAgeMillis; @@ -257,16 +265,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public Config getDevConfig(); - public Config getXtConfig(); - public Config getUidConfig(); - public Config getUidTagConfig(); + Config getDevConfig(); + Config getXtConfig(); + Config getUidConfig(); + Config getUidTagConfig(); - public long getGlobalAlertBytes(long def); - public long getDevPersistBytes(long def); - public long getXtPersistBytes(long def); - public long getUidPersistBytes(long def); - public long getUidTagPersistBytes(long def); + long getGlobalAlertBytes(long def); + long getDevPersistBytes(long def); + long getXtPersistBytes(long def); + long getUidPersistBytes(long def); + long getUidTagPersistBytes(long def); } private final Object mStatsLock = new Object(); @@ -509,9 +517,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: listen to changes from all subscriptions. + // TODO: 1. listen to changes from all subscriptions. + // 2. listen to settings changed to support dynamically enable/disable. // watch for networkType changes - if (!COMBINE_SUBTYPE_ENABLED) { + if (!mSettings.getCombineSubtypeEnabled()) { mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); } @@ -535,9 +544,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - if (!COMBINE_SUBTYPE_ENABLED) { - mTeleManager.listen(mPhoneListener, LISTEN_NONE); - } + mTeleManager.listen(mPhoneListener, LISTEN_NONE); final long currentTime = mClock.millis(); @@ -1265,12 +1272,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLastNetworkStates = states; + final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { if (state.networkInfo.isConnected()) { final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); - final int subType = getSubTypeForState(state); + final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED + : getSubTypeForState(state); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, isDefault, subType); @@ -1334,13 +1343,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * If combine subtype is not enabled. For networks with {@code TRANSPORT_CELLULAR}, get - * subType that obtained through {@link PhoneStateListener}. Otherwise, return 0 given that - * other networks with different transport types do not actually fill this value. + * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through + * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different + * transport types do not actually fill this value. */ private int getSubTypeForState(@NonNull NetworkState state) { - if (COMBINE_SUBTYPE_ENABLED) return SUBTYPE_COMBINED; - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } @@ -1702,6 +1709,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return; } + pw.println("Configs:"); + pw.increaseIndent(); + pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); + pw.println(); + pw.decreaseIndent(); + pw.println("Active interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveIfaces.size(); i++) { @@ -2130,6 +2143,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); } @Override + public boolean getCombineSubtypeEnabled() { + return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false); + } + @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), From 3eacb9682e89de608316e4090822a66ab6193361 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 19 Mar 2020 11:46:55 +0000 Subject: [PATCH 0752/1150] Make Ethernet interfaces more testable. This CL adds a setIncludeTestInterfaces method to EthernetManager that, when called, causes the Ethernet service to recognize and manage test interfaces created by TestNetworkManager. Bug: 150644681 Test: Tested by EthernetTetheringTest in same topic Change-Id: I86eef7a93267f800dbfc8eafd307effa76a344ca Merged-In: I86eef7a93267f800dbfc8eafd307effa76a344ca (cherry picked from commit 3410fb0aa92bbd4f9d7dc031e89f6f528ff34245) --- core/java/android/net/EthernetManager.java | 15 +++++++++++++++ core/java/android/net/IEthernetManager.aidl | 1 + 2 files changed, 16 insertions(+) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 83b5f63576..d975017f9c 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -199,6 +199,21 @@ public class EthernetManager { } } + /** + * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} + * as Ethernet interfaces. The effects of this method apply to any test interfaces that are + * already present on the system. + * @hide + */ + @TestApi + public void setIncludeTestInterfaces(boolean include) { + try { + mService.setIncludeTestInterfaces(include); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * A request for a tethered interface. */ diff --git a/core/java/android/net/IEthernetManager.aidl b/core/java/android/net/IEthernetManager.aidl index ccc6e35209..e058e5a70c 100644 --- a/core/java/android/net/IEthernetManager.aidl +++ b/core/java/android/net/IEthernetManager.aidl @@ -33,6 +33,7 @@ interface IEthernetManager boolean isAvailable(String iface); void addListener(in IEthernetServiceListener listener); void removeListener(in IEthernetServiceListener listener); + void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); } From 782c7307aa15c5052a81e024838f25f2b7f8a251 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 11 Feb 2020 14:59:38 +0800 Subject: [PATCH 0753/1150] [SM06] Collect mobile NetworkStats metrics by collapsed rat type Test: adb shell cmd stats pull-source 10000~10003 adb shell dumpsys netstats --uid Bug: 129082217 Change-Id: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 --- core/java/android/net/NetworkTemplate.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cb9463a59d..eba7ff3483 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -52,6 +53,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -477,6 +480,32 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Return all supported collapsed RAT types that could be returned by + * {@link #getCollapsedRatType(int)}. + */ + @NonNull + public static final int[] getAllCollapsedRatTypes() { + final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); + final HashSet collapsedRatTypes = new HashSet<>(); + for (final int ratType : ratTypes) { + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); + } + // Ensure that unknown type is returned. + collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); + return toIntArray(collapsedRatTypes); + } + + @NonNull + private static int[] toIntArray(@NonNull Collection list) { + final int[] array = new int[list.size()]; + int i = 0; + for (final Integer item : list) { + array[i++] = item; + } + return array; + } + /** * Check if matches Wi-Fi network template. */ From ebda17c88452be0566a17422a96332aa8ac955aa Mon Sep 17 00:00:00 2001 From: Automerger Merge Worker Date: Wed, 25 Mar 2020 00:49:05 +0000 Subject: [PATCH 0754/1150] Relax IPsec resource count restrictions. IPsec resource counts were selected to be conservative, due to unknowns about device capabilities. Since then, it appears that we no longer need such stringent quotas, and this can be relaxed. Bug: 152368091 Test: FrameworksNetTest passing Change-Id: Id53d14e5698e5fcc410868424176b00350c7ae79 Merged-In: Id53d14e5698e5fcc410868424176b00350c7ae79 (cherry picked from commit 224699fc0b485dd75e6157a88f66a53d64e5a6fd) --- .../core/java/com/android/server/IpSecService.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 9540f43364..599485b11c 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -359,10 +359,14 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final class UserRecord { /* Maximum number of each type of resource that a single UID may possess */ - public static final int MAX_NUM_TUNNEL_INTERFACES = 2; - public static final int MAX_NUM_ENCAP_SOCKETS = 2; - public static final int MAX_NUM_TRANSFORMS = 4; - public static final int MAX_NUM_SPIS = 8; + + // Up to 4 active VPNs/IWLAN with potential soft handover. + public static final int MAX_NUM_TUNNEL_INTERFACES = 8; + public static final int MAX_NUM_ENCAP_SOCKETS = 16; + + // SPIs and Transforms are both cheap, and are 1:1 correlated. + public static final int MAX_NUM_TRANSFORMS = 64; + public static final int MAX_NUM_SPIS = 64; /** * Store each of the OwnedResource types in an (thinly wrapped) sparse array for indexing From d497ed73f0d68405cf4b9ec79128c4603524ac55 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Wed, 25 Mar 2020 05:50:51 +0000 Subject: [PATCH 0755/1150] Automatically set IPsec tunnel interface as up This change makes IPsec tunnel interfaces automatically get brought up once they are created. Originally this was considered to be an additional safety check, as they would not be start routing traffic until explicitly brought up. However, in the intervening time, the NetworkManagementController now requires the NETWORK_STACK permission to set an interface as up. Additionally, that call is a hidden API, and thus not usable for use cases such as IWLAN. Bug: 149348618 Test: FrameworksNetTests, CtsNetTestCases passing. Change-Id: I55b63a748463a388e1e2991d2d5d6b3023545e60 Merged-In: I55b63a748463a388e1e2991d2d5d6b3023545e60 (cherry picked from commit 7c5704d177a903034ae1b6ae4800cc3b8457977a) --- .../java/com/android/server/IpSecService.java | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 599485b11c..905c489e1d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -46,6 +46,7 @@ import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; +import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -114,6 +115,9 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; + /* NetworkManager instance */ + private final INetworkManagementService mNetworkManager; + /** * The next non-repeating global ID for tracking resources between users, this service, and * kernel data structures. Accessing this variable is not thread safe, so it is only read or @@ -992,12 +996,13 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { - this(context, IpSecServiceConfiguration.GETSRVINSTANCE); + private IpSecService(Context context, INetworkManagementService networkManager) { + this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE); } - static IpSecService create(Context context) throws InterruptedException { - final IpSecService service = new IpSecService(context); + static IpSecService create(Context context, INetworkManagementService networkManager) + throws InterruptedException { + final IpSecService service = new IpSecService(context, networkManager); service.connectNativeNetdService(); return service; } @@ -1011,9 +1016,11 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, IpSecServiceConfiguration config) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config) { this( context, + networkManager, config, (fd, uid) -> { try { @@ -1027,9 +1034,10 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService( - Context context, IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { + public IpSecService(Context context, INetworkManagementService networkManager, + IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { mContext = context; + mNetworkManager = Objects.requireNonNull(networkManager); mSrvConfig = config; mUidFdTagger = uidFdTagger; } @@ -1308,6 +1316,10 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); + Binder.withCleanCallingIdentity(() -> { + mNetworkManager.setInterfaceUp(intfName); + }); + for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. netd.ipSecAddSecurityPolicy( From 85d2df81607d270d8737ae3f02417ac4658bbc52 Mon Sep 17 00:00:00 2001 From: Daulet Zhanguzin Date: Thu, 26 Mar 2020 12:30:39 +0000 Subject: [PATCH 0756/1150] Replace com.android.internal.util.Preconditions.checkNotNull with java.util.Objects.requireNonNull Bug: 126528330 Bug: 149348618 Test: Treehugger Change-Id: Idb1b6ba41af3b52f3376b1157259af3c30328c4e Merged-In: Idb1b6ba41af3b52f3376b1157259af3c30328c4e --- .../java/com/android/server/IpSecService.java | 18 ++++++++---------- .../android/server/NativeDaemonConnector.java | 3 ++- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 424407a957..905c489e1d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -25,8 +25,6 @@ import static android.system.OsConstants.EINVAL; import static android.system.OsConstants.IPPROTO_UDP; import static android.system.OsConstants.SOCK_DGRAM; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; @@ -575,7 +573,7 @@ public class IpSecService extends IIpSecService.Stub { } void put(int key, RefcountedResource obj) { - checkNotNull(obj, "Null resources cannot be added"); + Objects.requireNonNull(obj, "Null resources cannot be added"); mArray.put(key, obj); } @@ -1114,7 +1112,7 @@ public class IpSecService extends IIpSecService.Stub { if (requestedSpi > 0 && requestedSpi < 256) { throw new IllegalArgumentException("ESP SPI must not be in the range of 0-255."); } - checkNotNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); + Objects.requireNonNull(binder, "Null Binder passed to allocateSecurityParameterIndex"); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); @@ -1231,7 +1229,7 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException( "Specified port number must be a valid non-reserved UDP port"); } - checkNotNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); + Objects.requireNonNull(binder, "Null Binder passed to openUdpEncapsulationSocket"); int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); @@ -1291,8 +1289,8 @@ public class IpSecService extends IIpSecService.Stub { String localAddr, String remoteAddr, Network underlyingNetwork, IBinder binder, String callingPackage) { enforceTunnelFeatureAndPermissions(callingPackage); - checkNotNull(binder, "Null Binder passed to createTunnelInterface"); - checkNotNull(underlyingNetwork, "No underlying network was specified"); + Objects.requireNonNull(binder, "Null Binder passed to createTunnelInterface"); + Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); checkInetAddress(localAddr); checkInetAddress(remoteAddr); @@ -1573,7 +1571,7 @@ public class IpSecService extends IIpSecService.Stub { "IPsec Tunnel Mode requires PackageManager.FEATURE_IPSEC_TUNNELS"); } - checkNotNull(callingPackage, "Null calling package cannot create IpSec tunnels"); + Objects.requireNonNull(callingPackage, "Null calling package cannot create IpSec tunnels"); // OP_MANAGE_IPSEC_TUNNELS will return MODE_ERRORED by default, including for the system // server. If the appop is not granted, require that the caller has the MANAGE_IPSEC_TUNNELS @@ -1642,12 +1640,12 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized IpSecTransformResponse createTransform( IpSecConfig c, IBinder binder, String callingPackage) throws RemoteException { - checkNotNull(c); + Objects.requireNonNull(c); if (c.getMode() == IpSecTransform.MODE_TUNNEL) { enforceTunnelFeatureAndPermissions(callingPackage); } checkIpSecConfig(c); - checkNotNull(binder, "Null Binder passed to createTransform"); + Objects.requireNonNull(binder, "Null Binder passed to createTransform"); final int resourceId = mNextResourceId++; UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java index ad02aad6e4..eac767f735 100644 --- a/services/core/java/com/android/server/NativeDaemonConnector.java +++ b/services/core/java/com/android/server/NativeDaemonConnector.java @@ -46,6 +46,7 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.LinkedList; +import java.util.Objects; /** * Generic connector class for interfacing with a native daemon which uses the @@ -126,7 +127,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public void setWarnIfHeld(Object warnIfHeld) { Preconditions.checkState(mWarnIfHeld == null); - mWarnIfHeld = Preconditions.checkNotNull(warnIfHeld); + mWarnIfHeld = Objects.requireNonNull(warnIfHeld); } @Override From 60539ad8bca47ced5ea8e784794f41454f03056a Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 11 Feb 2020 14:59:38 +0800 Subject: [PATCH 0757/1150] [SM06] Collect mobile NetworkStats metrics by collapsed rat type Test: adb shell cmd stats pull-source 10000~10003 adb shell dumpsys netstats --uid Bug: 129082217 Change-Id: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 Merged-In: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 (cherry picked from commit c82dfeb4225e1a8a17eedc969a90f921e0bf845c) --- core/java/android/net/NetworkTemplate.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cb9463a59d..eba7ff3483 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -52,6 +53,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -477,6 +480,32 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Return all supported collapsed RAT types that could be returned by + * {@link #getCollapsedRatType(int)}. + */ + @NonNull + public static final int[] getAllCollapsedRatTypes() { + final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); + final HashSet collapsedRatTypes = new HashSet<>(); + for (final int ratType : ratTypes) { + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); + } + // Ensure that unknown type is returned. + collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); + return toIntArray(collapsedRatTypes); + } + + @NonNull + private static int[] toIntArray(@NonNull Collection list) { + final int[] array = new int[list.size()]; + int i = 0; + for (final Integer item : list) { + array[i++] = item; + } + return array; + } + /** * Check if matches Wi-Fi network template. */ From 110e2b8da4efdd9cccecf1089cc2e62ff9097f30 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 31 Mar 2020 14:56:01 +0800 Subject: [PATCH 0758/1150] [SP26.2] add a method in NetworkStats that removes empty entries In current design, entries with zeros are preserved after addition/subtraction. These entries are not very useful and lead to difficulty of verifying the result of addition/subtraction. However, change the behavior in the original NetworkStats is considered risky in current stage. Thus, this change provide a function that could remove these empty entries in tests. Test: atest FrameworksNetTests Bug: 152827872 Bug: 150644692 Change-Id: I40a76935d55712b8083ee1e17e137a8a4ef5e029 --- core/java/android/net/NetworkStats.java | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9c1fb41ecc..b7fb280efd 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1195,18 +1195,24 @@ public final class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * This mutates the original structure in place. * @hide */ public void removeUids(int[] uids) { - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - if (!ArrayUtils.contains(uids, uid[i])) { - maybeCopyEntry(nextOutputEntry, i); - nextOutputEntry++; - } - } + filter(e -> !ArrayUtils.contains(uids, e.uid)); + } - size = nextOutputEntry; + /** + * Remove all rows that match one of specified UIDs. + * @return the result object. + * @hide + */ + @NonNull + public NetworkStats removeEmptyEntries() { + final NetworkStats ret = this.clone(); + ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0 + || e.operations != 0); + return ret; } /** From 3c94b3b16243134bb89418ffde12e4b39fe1fc30 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 2 Apr 2020 18:36:24 +0000 Subject: [PATCH 0759/1150] [SP26.2] add a method in NetworkStats that removes empty entries In current design, entries with zeros are preserved after addition/subtraction. These entries are not very useful and lead to difficulty of verifying the result of addition/subtraction. However, change the behavior in the original NetworkStats is considered risky in current stage. Thus, this change provide a function that could remove these empty entries in tests. Test: atest FrameworksNetTests Bug: 152827872 Bug: 150644692 Change-Id: I40a76935d55712b8083ee1e17e137a8a4ef5e029 Merged-In: I40a76935d55712b8083ee1e17e137a8a4ef5e029 (cherry picked from commit 6c7bef3064dbe949b7b213036b8e70c125ddd343) --- core/java/android/net/NetworkStats.java | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 9c1fb41ecc..b7fb280efd 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1195,18 +1195,24 @@ public final class NetworkStats implements Parcelable { /** * Remove all rows that match one of specified UIDs. + * This mutates the original structure in place. * @hide */ public void removeUids(int[] uids) { - int nextOutputEntry = 0; - for (int i = 0; i < size; i++) { - if (!ArrayUtils.contains(uids, uid[i])) { - maybeCopyEntry(nextOutputEntry, i); - nextOutputEntry++; - } - } + filter(e -> !ArrayUtils.contains(uids, e.uid)); + } - size = nextOutputEntry; + /** + * Remove all rows that match one of specified UIDs. + * @return the result object. + * @hide + */ + @NonNull + public NetworkStats removeEmptyEntries() { + final NetworkStats ret = this.clone(); + ret.filter(e -> e.rxBytes != 0 || e.rxPackets != 0 || e.txBytes != 0 || e.txPackets != 0 + || e.operations != 0); + return ret; } /** From 90ae726ee1ad0cce6e9cbeefcf8897bc4382b976 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:48:50 +0800 Subject: [PATCH 0760/1150] [SM09] Add helper class to monitor RAT type change per sub In current design, Rat type change in NSS is only for default subscription. This is only correct for single sim project. However, it does not correct for multi-sim scenarios such as CBRS or DSDS, given that all data usage will be attributed to the Rat type of default sub. Thus, add a helper class to monitor subscription change event, and register/unregister dynamically for Rat type change for every subscription. Note that unit test of the helper class will be addressed in follow-up patch. Test: m -j Bug: 146415925 Change-Id: I0055f6b55c209a073ce997fc7a144477f9db7069 --- .../net/NetworkStatsSubscriptionsMonitor.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 0000000000..0bdf3f22ee --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; + +/** + * Helper class that watches for events that are triggered per subscription. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +public class NetworkStatsSubscriptionsMonitor extends + SubscriptionManager.OnSubscriptionsChangedListener { + + /** + * Interface that this monitor uses to delegate event handling to NetworkStatsService. + */ + public interface Delegate { + /** + * Notify that the collapsed RAT type has been changed for any subscription. The method + * will also be triggered for any existing sub when start and stop monitoring. + * + * @param subscriberId IMSI of the subscription. + * @param collapsedRatType collapsed RAT type. + * @see android.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} changes for each subscription, to + * monitor the transitioning between Radio Access Technology(RAT) types for each sub. + */ + @NonNull + private final CopyOnWriteArrayList mRatListeners = + new CopyOnWriteArrayList<>(); + + @NonNull + private final SubscriptionManager mSubscriptionManager; + @NonNull + private final TelephonyManager mTeleManager; + + @NonNull + private final Executor mExecutor; + + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, + @NonNull Delegate delegate) { + super(); + mSubscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mExecutor = executor; + mDelegate = delegate; + } + + @Override + public void onSubscriptionsChanged() { + // Collect active subId list, hidden subId such as opportunistic subscriptions are + // also needed to track CBRS. + final List newSubs = getActiveSubIdList(mSubscriptionManager); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + handleRemoveRatTypeListener(listener); + } + } + + @NonNull + private List getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { + final ArrayList ret = new ArrayList<>(); + final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); + for (int id : ids) ret.add(id); + return ret; + } + + /** + * Get a collapsed RatType for the given subscriberId. + * + * @param subscriberId the target subscriberId + * @return collapsed RatType for the given subscriberId + */ + public int getRatTypeForSubscriberId(@NonNull String subscriberId) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + /** + * Start monitoring events that triggered per subscription. + */ + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); + } + + /** + * Unregister subscription changes and all listeners for each subscription. + */ + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + handleRemoveRatTypeListener(listener); + } + } + + private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { + mTeleManager.createForSubscriptionId(listener.mSubId) + .listen(listener, PhoneStateListener.LISTEN_NONE); + mRatListeners.remove(listener); + + // Removal of subscriptions doesn't generate RAT changed event, fire it for every + // RatTypeListener. + mDelegate.onCollapsedRatTypeChanged( + listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + static class RatTypeListener extends PhoneStateListener { + // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. + @NonNull + private final int mSubId; + + // IMSI to identifying the corresponding network from {@link NetworkState}. + // See {@link TelephonyManager#getSubscriberId}. + @NonNull + private final String mSubscriberId; + + private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + @NonNull + private final NetworkStatsSubscriptionsMonitor mMonitor; + + RatTypeListener(@NonNull Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (NetworkStatsService.LOGD) { + Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + mLastCollapsedRatType = collapsedRatType; + mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); + } + } +} From d217223e3f3a3e09e4c1d1614b4a027213ad061c Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:48:50 +0800 Subject: [PATCH 0761/1150] [SM09] Add helper class to monitor RAT type change per sub In current design, Rat type change in NSS is only for default subscription. This is only correct for single sim project. However, it does not correct for multi-sim scenarios such as CBRS or DSDS, given that all data usage will be attributed to the Rat type of default sub. Thus, add a helper class to monitor subscription change event, and register/unregister dynamically for Rat type change for every subscription. Note that unit test of the helper class will be addressed in follow-up patch. Test: m -j Bug: 146415925 Change-Id: I0055f6b55c209a073ce997fc7a144477f9db7069 Merged-In: I0055f6b55c209a073ce997fc7a144477f9db7069 (cherry picked from commit 306de26c138ec135846f2a74a952464cf00dce54) --- .../net/NetworkStatsSubscriptionsMonitor.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 0000000000..0bdf3f22ee --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; + +/** + * Helper class that watches for events that are triggered per subscription. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +public class NetworkStatsSubscriptionsMonitor extends + SubscriptionManager.OnSubscriptionsChangedListener { + + /** + * Interface that this monitor uses to delegate event handling to NetworkStatsService. + */ + public interface Delegate { + /** + * Notify that the collapsed RAT type has been changed for any subscription. The method + * will also be triggered for any existing sub when start and stop monitoring. + * + * @param subscriberId IMSI of the subscription. + * @param collapsedRatType collapsed RAT type. + * @see android.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} changes for each subscription, to + * monitor the transitioning between Radio Access Technology(RAT) types for each sub. + */ + @NonNull + private final CopyOnWriteArrayList mRatListeners = + new CopyOnWriteArrayList<>(); + + @NonNull + private final SubscriptionManager mSubscriptionManager; + @NonNull + private final TelephonyManager mTeleManager; + + @NonNull + private final Executor mExecutor; + + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, + @NonNull Delegate delegate) { + super(); + mSubscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mExecutor = executor; + mDelegate = delegate; + } + + @Override + public void onSubscriptionsChanged() { + // Collect active subId list, hidden subId such as opportunistic subscriptions are + // also needed to track CBRS. + final List newSubs = getActiveSubIdList(mSubscriptionManager); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + handleRemoveRatTypeListener(listener); + } + } + + @NonNull + private List getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { + final ArrayList ret = new ArrayList<>(); + final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); + for (int id : ids) ret.add(id); + return ret; + } + + /** + * Get a collapsed RatType for the given subscriberId. + * + * @param subscriberId the target subscriberId + * @return collapsed RatType for the given subscriberId + */ + public int getRatTypeForSubscriberId(@NonNull String subscriberId) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + /** + * Start monitoring events that triggered per subscription. + */ + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); + } + + /** + * Unregister subscription changes and all listeners for each subscription. + */ + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + handleRemoveRatTypeListener(listener); + } + } + + private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { + mTeleManager.createForSubscriptionId(listener.mSubId) + .listen(listener, PhoneStateListener.LISTEN_NONE); + mRatListeners.remove(listener); + + // Removal of subscriptions doesn't generate RAT changed event, fire it for every + // RatTypeListener. + mDelegate.onCollapsedRatTypeChanged( + listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + static class RatTypeListener extends PhoneStateListener { + // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. + @NonNull + private final int mSubId; + + // IMSI to identifying the corresponding network from {@link NetworkState}. + // See {@link TelephonyManager#getSubscriberId}. + @NonNull + private final String mSubscriberId; + + private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + @NonNull + private final NetworkStatsSubscriptionsMonitor mMonitor; + + RatTypeListener(@NonNull Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (NetworkStatsService.LOGD) { + Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + mLastCollapsedRatType = collapsedRatType; + mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); + } + } +} From 20dc3e71c2db351c9f5b1651d00d2955c30c896d Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:48:50 +0800 Subject: [PATCH 0762/1150] [SM09] Add helper class to monitor RAT type change per sub In current design, Rat type change in NSS is only for default subscription. This is only correct for single sim project. However, it does not correct for multi-sim scenarios such as CBRS or DSDS, given that all data usage will be attributed to the Rat type of default sub. Thus, add a helper class to monitor subscription change event, and register/unregister dynamically for Rat type change for every subscription. Note that unit test of the helper class will be addressed in follow-up patch. Test: m -j Bug: 146415925 Change-Id: I0055f6b55c209a073ce997fc7a144477f9db7069 Merged-In: I0055f6b55c209a073ce997fc7a144477f9db7069 (cherry picked from ag/10977156 and fixed conflict) --- .../net/NetworkStatsSubscriptionsMonitor.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java new file mode 100644 index 0000000000..16a63d5436 --- /dev/null +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import static android.net.NetworkTemplate.getCollapsedRatType; + +import android.annotation.NonNull; +import android.content.Context; +import android.telephony.Annotation; +import android.telephony.PhoneStateListener; +import android.telephony.ServiceState; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.text.TextUtils; +import android.util.Log; + +import com.android.internal.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.Executor; + +/** + * Helper class that watches for events that are triggered per subscription. + */ +// TODO (b/152176562): Write tests to verify subscription changes generate corresponding +// register/unregister calls. +public class NetworkStatsSubscriptionsMonitor extends + SubscriptionManager.OnSubscriptionsChangedListener { + + /** + * Interface that this monitor uses to delegate event handling to NetworkStatsService. + */ + public interface Delegate { + /** + * Notify that the collapsed RAT type has been changed for any subscription. The method + * will also be triggered for any existing sub when start and stop monitoring. + * + * @param subscriberId IMSI of the subscription. + * @param collapsedRatType collapsed RAT type. + * @see android.net.NetworkTemplate#getCollapsedRatType(int). + */ + void onCollapsedRatTypeChanged(@NonNull String subscriberId, + @Annotation.NetworkType int collapsedRatType); + } + private final Delegate mDelegate; + + /** + * Receivers that watches for {@link ServiceState} changes for each subscription, to + * monitor the transitioning between Radio Access Technology(RAT) types for each sub. + */ + @NonNull + private final CopyOnWriteArrayList mRatListeners = + new CopyOnWriteArrayList<>(); + + @NonNull + private final SubscriptionManager mSubscriptionManager; + @NonNull + private final TelephonyManager mTeleManager; + + @NonNull + private final Executor mExecutor; + + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, + @NonNull Delegate delegate) { + super(); + mSubscriptionManager = (SubscriptionManager) context.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); + mExecutor = executor; + mDelegate = delegate; + } + + @Override + public void onSubscriptionsChanged() { + // Collect active subId list, hidden subId such as opportunistic subscriptions are + // also needed to track CBRS. + final List newSubs = getActiveSubIdList(mSubscriptionManager); + + for (final int subId : newSubs) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> it.mSubId == subId); + if (match != null) continue; + + // Create listener for every newly added sub. Also store subscriberId into it to + // prevent binder call to telephony when querying RAT. + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (TextUtils.isEmpty(subscriberId)) { + Log.wtf(NetworkStatsService.TAG, + "Empty subscriberId for newly added sub: " + subId); + } + final RatTypeListener listener = + new RatTypeListener(mExecutor, this, subId, subscriberId); + mRatListeners.add(listener); + + // Register listener to the telephony manager that associated with specific sub. + mTeleManager.createForSubscriptionId(subId) + .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + } + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + // If the new list contains the subId of the listener, keeps it. + final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); + if (match != null) continue; + + handleRemoveRatTypeListener(listener); + } + } + + @NonNull + private List getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { + final ArrayList ret = new ArrayList<>(); + final int[] ids = subscriptionManager.getActiveAndHiddenSubscriptionIdList(); + for (int id : ids) ret.add(id); + return ret; + } + + /** + * Get a collapsed RatType for the given subscriberId. + * + * @param subscriberId the target subscriberId + * @return collapsed RatType for the given subscriberId + */ + public int getRatTypeForSubscriberId(@NonNull String subscriberId) { + final RatTypeListener match = CollectionUtils.find(mRatListeners, + it -> TextUtils.equals(subscriberId, it.mSubscriberId)); + return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + + /** + * Start monitoring events that triggered per subscription. + */ + public void start() { + mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor, this); + } + + /** + * Unregister subscription changes and all listeners for each subscription. + */ + public void stop() { + mSubscriptionManager.removeOnSubscriptionsChangedListener(this); + + for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { + handleRemoveRatTypeListener(listener); + } + } + + private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { + mTeleManager.createForSubscriptionId(listener.mSubId) + .listen(listener, PhoneStateListener.LISTEN_NONE); + mRatListeners.remove(listener); + + // Removal of subscriptions doesn't generate RAT changed event, fire it for every + // RatTypeListener. + mDelegate.onCollapsedRatTypeChanged( + listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); + } + + static class RatTypeListener extends PhoneStateListener { + // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. + @NonNull + private final int mSubId; + + // IMSI to identifying the corresponding network from {@link NetworkState}. + // See {@link TelephonyManager#getSubscriberId}. + @NonNull + private final String mSubscriberId; + + private volatile int mLastCollapsedRatType = TelephonyManager.NETWORK_TYPE_UNKNOWN; + @NonNull + private final NetworkStatsSubscriptionsMonitor mMonitor; + + RatTypeListener(@NonNull Executor executor, + @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + @NonNull String subscriberId) { + super(executor); + mSubId = subId; + mSubscriberId = subscriberId; + mMonitor = monitor; + } + + @Override + public void onServiceStateChanged(@NonNull ServiceState ss) { + final int networkType = ss.getDataNetworkType(); + final int collapsedRatType = getCollapsedRatType(networkType); + if (collapsedRatType == mLastCollapsedRatType) return; + + if (NetworkStatsService.LOGD) { + Log.d(NetworkStatsService.TAG, "subtype changed for sub(" + mSubId + "): " + + mLastCollapsedRatType + " -> " + collapsedRatType); + } + mLastCollapsedRatType = collapsedRatType; + mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); + } + } +} From 61dcf1f41f7df37fecb86d0474ef8f9ae6b69afc Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:58:00 +0800 Subject: [PATCH 0763/1150] [SM10] Adopt helper class to monitor RAT type change per sub Test: atest NetworkStatsServiceTest Bug: 146415925 Change-Id: I45c3aa9046b316c8cd0943543d620a22e4afefd1 --- .../server/net/NetworkStatsService.java | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..f7d0d4ee16 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -46,7 +46,6 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -67,9 +66,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -133,9 +129,7 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -206,7 +200,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; - private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -352,6 +345,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final Dependencies mDeps; + @NonNull + private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -401,8 +397,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), + final NetworkStatsService service = new NetworkStatsService(context, networkManager, + alarmManager, wakeLock, getDefaultClock(), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -416,16 +412,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, - TelephonyManager teleManager, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { + NetworkStatsSettings settings, NetworkStatsFactory factory, + NetworkStatsObservers statsObservers, File systemDir, File baseDir, + @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, - "missing INetworkManagementService"); + "missing INetworkManagementService"); mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); mClock = Objects.requireNonNull(clock, "missing Clock"); mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager"); mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); mStatsFactory = Objects.requireNonNull(factory, "missing factory"); mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); @@ -437,7 +432,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); + mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, + new HandlerExecutor(mHandler), this); } /** @@ -453,6 +449,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public HandlerThread makeHandlerThread() { return new HandlerThread(TAG); } + + /** + * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change + * event in NetworkStatsService. + */ + @NonNull + public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, + @NonNull Executor executor, @NonNull NetworkStatsService service) { + // TODO: Update RatType passively in NSS, instead of querying into the monitor + // when forceUpdateIface. + return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> + service.handleOnCollapsedRatTypeChanged()); + } } private void registerLocalService() { @@ -517,11 +526,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: 1. listen to changes from all subscriptions. - // 2. listen to settings changed to support dynamically enable/disable. + // TODO: listen to settings changed to support dynamically enable/disable. // watch for networkType changes if (!mSettings.getCombineSubtypeEnabled()) { - mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + mNetworkStatsSubscriptionsMonitor.start(); } registerGlobalAlert(); @@ -544,7 +552,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!mSettings.getCombineSubtypeEnabled()) { + mNetworkStatsSubscriptionsMonitor.stop(); + } final long currentTime = mClock.millis(); @@ -1197,35 +1207,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between Radio Access Technology(RAT) types. + * Handle collapsed RAT type changed event. */ - @NonNull - private final NetworkTypeListener mPhoneListener; - - class NetworkTypeListener extends PhoneStateListener { - private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; - - NetworkTypeListener(@NonNull Executor executor) { - super(executor); - } - - @Override - public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (LOGD) { - Log.d(TAG, "subtype changed for mobile: " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); - mLastCollapsedRatType = collapsedRatType; - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); - } + @VisibleForTesting + public void handleOnCollapsedRatTypeChanged() { + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } private void updateIfaces( @@ -1352,8 +1341,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return 0; } - // TODO: return different subType for different subscriptions. - return mPhoneListener.mLastCollapsedRatType; + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From 8bc2a49fd5901aa384e5f0962dabee0d13e89ee0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 10 Apr 2020 13:54:43 -0600 Subject: [PATCH 0764/1150] Narrow access to getDataLayerSnapshotForUid(). This method is used in TrafficStats to obtain the snapshot for the calling UID, so narrow it to only return data for that specific case. We might be tempted to throw an exception or adjust the method signature, but apps are using the raw AIDL in the greylist, so we return them an empty NetworkStats if they ask about other UIDs. Bug: 119672472 Test: manual Change-Id: I3064630039f1d8473d6425dd663f17813a4ae3a1 --- .../core/java/com/android/server/net/NetworkStatsService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..c3a1a883e5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -16,7 +16,6 @@ package com.android.server.net; -import static android.Manifest.permission.ACCESS_NETWORK_STATE; import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; @@ -845,7 +844,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDataLayerSnapshotForUid(int uid) throws RemoteException { if (Binder.getCallingUid() != uid) { - mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG); + Log.w(TAG, "Snapshots only available for calling UID"); + return new NetworkStats(SystemClock.elapsedRealtime(), 0); } // TODO: switch to data layer stats once kernel exports From 97d9567cb6d055936b247db36763302077b1802c Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:58:00 +0800 Subject: [PATCH 0765/1150] [SM10] Adopt helper class to monitor RAT type change per sub Test: atest NetworkStatsServiceTest Bug: 146415925 Change-Id: I45c3aa9046b316c8cd0943543d620a22e4afefd1 Merged-In: I45c3aa9046b316c8cd0943543d620a22e4afefd1 (cherry picked from commit 219faff07bdc58c14fe58fc525e86383db1f8167) --- .../server/net/NetworkStatsService.java | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..f7d0d4ee16 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -46,7 +46,6 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -67,9 +66,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -133,9 +129,7 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -206,7 +200,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; - private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -352,6 +345,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final Dependencies mDeps; + @NonNull + private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -401,8 +397,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), + final NetworkStatsService service = new NetworkStatsService(context, networkManager, + alarmManager, wakeLock, getDefaultClock(), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -416,16 +412,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, - TelephonyManager teleManager, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { + NetworkStatsSettings settings, NetworkStatsFactory factory, + NetworkStatsObservers statsObservers, File systemDir, File baseDir, + @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, - "missing INetworkManagementService"); + "missing INetworkManagementService"); mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); mClock = Objects.requireNonNull(clock, "missing Clock"); mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager"); mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); mStatsFactory = Objects.requireNonNull(factory, "missing factory"); mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); @@ -437,7 +432,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); + mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, + new HandlerExecutor(mHandler), this); } /** @@ -453,6 +449,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public HandlerThread makeHandlerThread() { return new HandlerThread(TAG); } + + /** + * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change + * event in NetworkStatsService. + */ + @NonNull + public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, + @NonNull Executor executor, @NonNull NetworkStatsService service) { + // TODO: Update RatType passively in NSS, instead of querying into the monitor + // when forceUpdateIface. + return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> + service.handleOnCollapsedRatTypeChanged()); + } } private void registerLocalService() { @@ -517,11 +526,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: 1. listen to changes from all subscriptions. - // 2. listen to settings changed to support dynamically enable/disable. + // TODO: listen to settings changed to support dynamically enable/disable. // watch for networkType changes if (!mSettings.getCombineSubtypeEnabled()) { - mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + mNetworkStatsSubscriptionsMonitor.start(); } registerGlobalAlert(); @@ -544,7 +552,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!mSettings.getCombineSubtypeEnabled()) { + mNetworkStatsSubscriptionsMonitor.stop(); + } final long currentTime = mClock.millis(); @@ -1197,35 +1207,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between Radio Access Technology(RAT) types. + * Handle collapsed RAT type changed event. */ - @NonNull - private final NetworkTypeListener mPhoneListener; - - class NetworkTypeListener extends PhoneStateListener { - private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; - - NetworkTypeListener(@NonNull Executor executor) { - super(executor); - } - - @Override - public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (LOGD) { - Log.d(TAG, "subtype changed for mobile: " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); - mLastCollapsedRatType = collapsedRatType; - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); - } + @VisibleForTesting + public void handleOnCollapsedRatTypeChanged() { + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } private void updateIfaces( @@ -1352,8 +1341,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return 0; } - // TODO: return different subType for different subscriptions. - return mPhoneListener.mLastCollapsedRatType; + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From e3cff5ba69d7b3c77901cb9de0b1925f129dbd34 Mon Sep 17 00:00:00 2001 From: Chenbo Feng Date: Mon, 17 Jun 2019 16:22:28 -0700 Subject: [PATCH 0766/1150] Enforce permission check in getUidStats function The NetworkStatsService.getUidStats() currently doesn't have any permission check to make sure unpriviledged apps cannot read the stats of a different uid. It will protentially have security problem since apps with ACCESS_NETWORK_STATS permission can directly calling into NetworkStatsService and bypass the check in TrafficStats. Move the uid check from TrafficStats to NetworkStatsService to fix the problem. Bug: 129151407 Test: atest AppSecurityTests#testAppFailAccessPrivateData_full Test: atest AppSecurityTests#testAppFailAccessPrivateData_instant Test: atest android.app.usage.cts.NetworkUsageStatsTest Test: atest NetworkStatsBinderTest Change-Id: Iae85676cfe5f114da69ec278afc2c904bc907234 --- core/java/android/net/TrafficStats.java | 60 +++++-------------- .../server/net/NetworkStatsService.java | 5 ++ 2 files changed, 21 insertions(+), 44 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 8108cf08d5..e7bba69dbb 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -775,17 +775,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxBytes(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_TX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -808,17 +801,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxBytes(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_BYTES); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_RX_BYTES); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -841,17 +827,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidTxPackets(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_TX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -874,17 +853,10 @@ public class TrafficStats { * @see android.content.pm.ApplicationInfo#uid */ public static long getUidRxPackets(int uid) { - // This isn't actually enforcing any security; it just returns the - // unsupported value. The real filtering is done at the kernel level. - final int callingUid = android.os.Process.myUid(); - if (callingUid == android.os.Process.SYSTEM_UID || callingUid == uid) { - try { - return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } else { - return UNSUPPORTED; + try { + return getStatsService().getUidStats(uid, TYPE_RX_PACKETS); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d8264b3625..003e7fc837 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -49,6 +49,7 @@ import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.net.TrafficStats.UNSUPPORTED; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; @@ -1021,6 +1022,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getUidStats(int uid, int type) { + final int callingUid = Binder.getCallingUid(); + if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { + return UNSUPPORTED; + } return nativeGetUidStat(uid, type, checkBpfStatsEnable()); } From 350b80ef71a84ad4f64171fa95af1b7eac34118b Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 28 Apr 2020 22:15:56 +0800 Subject: [PATCH 0767/1150] Filter debug entries for each vpn NetworkStats calculation needs to filter out debug entries to prevent over counting. While NetworkStatsFactory migrates data usage over a VPN to the TUN network, NetworkStatsFactory does not filter out debug entries per vpn which will cause debug entries left and cause exception. Bug: 152678151 Test: atest com.android.server.net.NetworkStatsFactoryTest and verify no exception Change-Id: I3525edc385b07858b48c7add2d331c4b5a2e84ad --- .../java/com/android/server/net/NetworkStatsFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 75ffe35674..3dac106418 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -385,11 +385,10 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); } - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - // Update mTunAnd464xlatAdjustedStats with migrated delta. mTunAnd464xlatAdjustedStats.combineAllValues(delta); mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); From 2e1eda79f3a0a53a693985b9d3601e12f23a568c Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 28 Apr 2020 22:15:56 +0800 Subject: [PATCH 0768/1150] Filter debug entries for each vpn NetworkStats calculation needs to filter out debug entries to prevent over counting. While NetworkStatsFactory migrates data usage over a VPN to the TUN network, NetworkStatsFactory does not filter out debug entries per vpn which will cause debug entries left and cause exception. Bug: 152678151 Test: atest com.android.server.net.NetworkStatsFactoryTest and verify no exception Change-Id: I3525edc385b07858b48c7add2d331c4b5a2e84ad Merged-In: I3525edc385b07858b48c7add2d331c4b5a2e84ad --- .../java/com/android/server/net/NetworkStatsFactory.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 75ffe35674..3dac106418 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -385,11 +385,10 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + // Filter out debug entries as that may lead to over counting. + delta.filterDebugEntries(); } - // Filter out debug entries as that may lead to over counting. - delta.filterDebugEntries(); - // Update mTunAnd464xlatAdjustedStats with migrated delta. mTunAnd464xlatAdjustedStats.combineAllValues(delta); mTunAnd464xlatAdjustedStats.setElapsedRealtime(uidDetailStats.getElapsedRealtime()); From e77cc5a7b1ef167ec41b3d9cacefacdaef12bd71 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 29 Apr 2020 18:25:32 +0800 Subject: [PATCH 0769/1150] Use CopyOnWriteArrayList to store list of NetworkStatsProviderCb In NetworkStatsService, mStatsLock will be held when iterating through the provider list. This is to protect the list from concurrent broadcast that triggered by NetworkPolicyManagerService. This is not good since the binder call is oneway, it does not make sense to block every access to the providers. This change also remove unuse variable and reduce verbose log. Test: atest FrameworksNetTests TetheringTests Bug: 150418178 Change-Id: If74e9f2ea597a0d5ae4668c3358bc687f342bbb5 --- .../server/net/NetworkStatsService.java | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 2680858743..76f7df5579 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -123,7 +123,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -166,6 +165,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -230,12 +230,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; - /** - * Virtual network interface for video telephony. This is for VT data usage counting purpose. - */ - // TODO: Remove this after no one is using it. - public static final String VT_INTERFACE = NetworkStats.IFACE_VT; - /** * Settings that can be changed externally. */ @@ -308,8 +302,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DropBoxNonMonotonicObserver(); private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final RemoteCallbackList mStatsProviderCbList = - new RemoteCallbackList<>(); + private final CopyOnWriteArrayList mStatsProviderCbList = + new CopyOnWriteArrayList<>(); /** Semaphore used to wait for stats provider to respond to request stats update. */ private final Semaphore mStatsProviderSem = new Semaphore(0, true); @@ -1463,10 +1457,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. + // time to allow providers report-in given that normally binder call should be fast. Note + // that size of list might be changed because addition/removing at the same time. For + // addition, the stats of the missed provider can only be collected in next poll; + // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS + // once that happened. // TODO: request with a valid token. Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); + final int registeredCallbackCount = mStatsProviderCbList.size(); mStatsProviderSem.drainPermits(); invokeForAllStatsProviderCallbacks( (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); @@ -1643,7 +1641,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); + if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1934,7 +1932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( tag, provider, mStatsProviderSem, mAlertObserver, mStatsProviderCbList); - mStatsProviderCbList.register(callback); + mStatsProviderCbList.add(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); return callback; @@ -1958,20 +1956,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void invokeForAllStatsProviderCallbacks( @NonNull ThrowingConsumer task) { - synchronized (mStatsLock) { - final int length = mStatsProviderCbList.beginBroadcast(); + for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { try { - for (int i = 0; i < length; i++) { - final NetworkStatsProviderCallbackImpl cb = - mStatsProviderCbList.getBroadcastItem(i); - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } finally { - mStatsProviderCbList.finishBroadcast(); + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); } } } @@ -1983,7 +1972,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final INetworkStatsProvider mProvider; @NonNull private final Semaphore mSemaphore; @NonNull final INetworkManagementEventObserver mAlertObserver; - @NonNull final RemoteCallbackList mStatsProviderCbList; + @NonNull final CopyOnWriteArrayList mStatsProviderCbList; @NonNull private final Object mProviderStatsLock = new Object(); @@ -1997,7 +1986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, @NonNull INetworkManagementEventObserver alertObserver, - @NonNull RemoteCallbackList cbList) + @NonNull CopyOnWriteArrayList cbList) throws RemoteException { mTag = tag; mProvider = provider; @@ -2054,13 +2043,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void binderDied() { Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } @Override public void unregister() { Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } } From d9d1a9f98a40e3b473ab0749fe1510470850a64e Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 4 Mar 2020 12:58:00 +0800 Subject: [PATCH 0770/1150] [SM10] Adopt helper class to monitor RAT type change per sub Test: atest NetworkStatsServiceTest Bug: 146415925 Change-Id: I45c3aa9046b316c8cd0943543d620a22e4afefd1 Merged-In: I45c3aa9046b316c8cd0943543d620a22e4afefd1 (cherry picked from commit 61dcf1f41f7df37fecb86d0474ef8f9ae6b69afc) --- .../server/net/NetworkStatsService.java | 86 ++++++++----------- 1 file changed, 37 insertions(+), 49 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 2680858743..34e8f62324 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -46,7 +46,6 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.NetworkTemplate.getCollapsedRatType; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.os.Trace.TRACE_TAG_NETWORK; @@ -67,9 +66,6 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; -import static android.telephony.PhoneStateListener.LISTEN_NONE; -import static android.telephony.PhoneStateListener.LISTEN_SERVICE_STATE; -import static android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -133,9 +129,7 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.SubscriptionPlan; -import android.telephony.TelephonyManager; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -206,7 +200,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; - private final TelephonyManager mTeleManager; private final NetworkStatsSettings mSettings; private final NetworkStatsObservers mStatsObservers; @@ -352,6 +345,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final Dependencies mDeps; + @NonNull + private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -401,8 +397,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, - wakeLock, getDefaultClock(), context.getSystemService(TelephonyManager.class), + final NetworkStatsService service = new NetworkStatsService(context, networkManager, + alarmManager, wakeLock, getDefaultClock(), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -416,16 +412,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting NetworkStatsService(Context context, INetworkManagementService networkManager, AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, - TelephonyManager teleManager, NetworkStatsSettings settings, - NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, - File baseDir, @NonNull Dependencies deps) { + NetworkStatsSettings settings, NetworkStatsFactory factory, + NetworkStatsObservers statsObservers, File systemDir, File baseDir, + @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); mNetworkManager = Objects.requireNonNull(networkManager, - "missing INetworkManagementService"); + "missing INetworkManagementService"); mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); mClock = Objects.requireNonNull(clock, "missing Clock"); mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); - mTeleManager = Objects.requireNonNull(teleManager, "missing TelephonyManager"); mWakeLock = Objects.requireNonNull(wakeLock, "missing WakeLock"); mStatsFactory = Objects.requireNonNull(factory, "missing factory"); mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); @@ -437,7 +432,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final HandlerThread handlerThread = mDeps.makeHandlerThread(); handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); - mPhoneListener = new NetworkTypeListener(new HandlerExecutor(mHandler)); + mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, + new HandlerExecutor(mHandler), this); } /** @@ -453,6 +449,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public HandlerThread makeHandlerThread() { return new HandlerThread(TAG); } + + /** + * Create a {@link NetworkStatsSubscriptionsMonitor}, can be used to monitor RAT change + * event in NetworkStatsService. + */ + @NonNull + public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, + @NonNull Executor executor, @NonNull NetworkStatsService service) { + // TODO: Update RatType passively in NSS, instead of querying into the monitor + // when forceUpdateIface. + return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> + service.handleOnCollapsedRatTypeChanged()); + } } private void registerLocalService() { @@ -517,11 +526,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: 1. listen to changes from all subscriptions. - // 2. listen to settings changed to support dynamically enable/disable. + // TODO: listen to settings changed to support dynamically enable/disable. // watch for networkType changes if (!mSettings.getCombineSubtypeEnabled()) { - mTeleManager.listen(mPhoneListener, LISTEN_SERVICE_STATE); + mNetworkStatsSubscriptionsMonitor.start(); } registerGlobalAlert(); @@ -544,7 +552,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.unregisterReceiver(mUserReceiver); mContext.unregisterReceiver(mShutdownReceiver); - mTeleManager.listen(mPhoneListener, LISTEN_NONE); + if (!mSettings.getCombineSubtypeEnabled()) { + mNetworkStatsSubscriptionsMonitor.stop(); + } final long currentTime = mClock.millis(); @@ -1197,35 +1207,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; /** - * Receiver that watches for {@link TelephonyManager} changes, such as - * transitioning between Radio Access Technology(RAT) types. + * Handle collapsed RAT type changed event. */ - @NonNull - private final NetworkTypeListener mPhoneListener; - - class NetworkTypeListener extends PhoneStateListener { - private volatile int mLastCollapsedRatType = NETWORK_TYPE_UNKNOWN; - - NetworkTypeListener(@NonNull Executor executor) { - super(executor); - } - - @Override - public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); - final int collapsedRatType = getCollapsedRatType(networkType); - if (collapsedRatType == mLastCollapsedRatType) return; - - if (LOGD) { - Log.d(TAG, "subtype changed for mobile: " - + mLastCollapsedRatType + " -> " + collapsedRatType); - } - // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); - mLastCollapsedRatType = collapsedRatType; - mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); - } + @VisibleForTesting + public void handleOnCollapsedRatTypeChanged() { + // Protect service from frequently updating. Remove pending messages if any. + mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.sendMessageDelayed( + mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); } private void updateIfaces( @@ -1352,8 +1341,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return 0; } - // TODO: return different subType for different subscriptions. - return mPhoneListener.mLastCollapsedRatType; + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From d1028a599531c6e4597f6a541c9e58f561ae1159 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Wed, 6 May 2020 15:35:54 +0800 Subject: [PATCH 0771/1150] Broadcast ACTION_NETWORK_STATS_UPDATED in NetworkStatsHandler There is a corner case which may cause the deadlock: When NetworkStatsService tried to broadcast the intent, NetworkStatsService was waiting for a lock which was hold by ActivityManagerService. In the same time, ActivityManagerService was waiting for ActiveService#startServiceInnerLocked() to get a lock which was hold by ConnectivityService. ConnectivityService was waiting for a lock which was hold by BatteryStatsImpl. BatteryStatsImpl was waiting for a lock which was hold by NetworkStatsService, and the lock was locked by NetworkStatsService when NetworkStatsService tried to broadcast the intent. To prevent deadlock when broadcasting the intent in performPollLocked(), move the intent broadcasting from performPollLocked() to NetworkStatsHandler. Bug: 150418178 Bug: 155155473 Test: 1. Create the second user and see if the device will do factory reset or not. 2. Factory reset manually and see if there is a deadlock. Change-Id: Icf88d3e7a38562ab15187f6c71bc8fb0486d37c0 --- .../android/server/net/NetworkStatsService.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 34e8f62324..e21a01d204 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -178,6 +178,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; private static final int MSG_UPDATE_IFACES = 3; + // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent + // deadlock. + private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -386,6 +389,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerGlobalAlert(); break; } + case MSG_BROADCAST_NETWORK_STATS_UPDATED: { + final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); + updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, + READ_NETWORK_USAGE_HISTORY); + break; + } } } } @@ -1508,10 +1518,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // finally, dispatch updated event to any listeners - final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); - updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, - READ_NETWORK_USAGE_HISTORY); + mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); Trace.traceEnd(TRACE_TAG_NETWORK); } From ac2db1662c774c56c8633b208c1e5a1050886aec Mon Sep 17 00:00:00 2001 From: Lucas Lin Date: Thu, 7 May 2020 10:12:30 +0000 Subject: [PATCH 0772/1150] Broadcast ACTION_NETWORK_STATS_UPDATED in NetworkStatsHandler There is a corner case which may cause the deadlock: When NetworkStatsService tried to broadcast the intent, NetworkStatsService was waiting for a lock which was hold by ActivityManagerService. In the same time, ActivityManagerService was waiting for ActiveService#startServiceInnerLocked() to get a lock which was hold by ConnectivityService. ConnectivityService was waiting for a lock which was hold by BatteryStatsImpl. BatteryStatsImpl was waiting for a lock which was hold by NetworkStatsService, and the lock was locked by NetworkStatsService when NetworkStatsService tried to broadcast the intent. To prevent deadlock when broadcasting the intent in performPollLocked(), move the intent broadcasting from performPollLocked() to NetworkStatsHandler. Bug: 150418178 Bug: 155155473 Test: 1. Create the second user and see if the device will do factory reset or not. 2. Factory reset manually and see if there is a deadlock. Change-Id: I80569cb4388beb3fd6cbf64a7885bccee8b1c53c Merged-In: Icf88d3e7a38562ab15187f6c71bc8fb0486d37c0 (cherry picked from commit 3f8ab0350450202910ea702799570c538e96d5cd) --- .../android/server/net/NetworkStatsService.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 1951fc071d..adf017633c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -178,6 +178,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; private static final int MSG_UPDATE_IFACES = 3; + // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent + // deadlock. + private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -386,6 +389,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { registerGlobalAlert(); break; } + case MSG_BROADCAST_NETWORK_STATS_UPDATED: { + final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); + updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, + READ_NETWORK_USAGE_HISTORY); + break; + } } } } @@ -1513,10 +1523,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // finally, dispatch updated event to any listeners - final Intent updatedIntent = new Intent(ACTION_NETWORK_STATS_UPDATED); - updatedIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); - mContext.sendBroadcastAsUser(updatedIntent, UserHandle.ALL, - READ_NETWORK_USAGE_HISTORY); + mHandler.sendMessage(mHandler.obtainMessage(MSG_BROADCAST_NETWORK_STATS_UPDATED)); Trace.traceEnd(TRACE_TAG_NETWORK); } From 6a1701dba8dc1e5cf3859a928d7f89a0523dee16 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 3 Oct 2019 11:09:00 -0700 Subject: [PATCH 0773/1150] Use TransformRecord to get SPI instead of SpiRecord IpSecService.applyTunnelModeTransform() currently does not take an SpiRecord instance, yet implicitly requires that the SpiRecord instance is still alive based on the stored SpiRecord resourceId in the TransformRecord's IpSecConfig. This check is unnecessary, as the SpiRecord has been subsumed into the TransformRecord, and the kernel resources are kept alive whether or not the SpiRecord is still held by the user. This allows users of the IpSecManager API to allocate short-lived SPIs during the creation of an IpSecTransform, without having to keep track of both of them (even though the SPI is no longer usable). The TransformRecord.getSpiRecord() call is already used in multiple other places in the same method. Bug: 142072071 Test: New tests added, passing. Change-Id: I1959f3080946267243564459ff4207647922566e Merged-In: I1959f3080946267243564459ff4207647922566e (cherry picked from commit 1678614ca751a1574609150901278573fd3824fd) --- services/core/java/com/android/server/IpSecService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 905c489e1d..6402e07bdd 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1776,7 +1776,7 @@ public class IpSecService extends IIpSecService.Stub { socketRecord = userRecord.mEncapSocketRecords.getResourceOrThrow(c.getEncapSocketResourceId()); } - SpiRecord spiRecord = userRecord.mSpiRecords.getResourceOrThrow(c.getSpiResourceId()); + SpiRecord spiRecord = transformInfo.getSpiRecord(); int mark = (direction == IpSecManager.DIRECTION_OUT) @@ -1809,7 +1809,7 @@ public class IpSecService extends IIpSecService.Stub { // Set outbound SPI only. We want inbound to use any valid SA (old, new) on rekeys, // but want to guarantee outbound packets are sent over the new SA. - spi = transformInfo.getSpiRecord().getSpi(); + spi = spiRecord.getSpi(); } // Always update the policy with the relevant XFRM_IF_ID From 5b1f5ccfaa878dbc4112ec969e0f8415235460da Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Tue, 12 May 2020 11:06:23 +0000 Subject: [PATCH 0774/1150] Use CopyOnWriteArrayList to store list of NetworkStatsProviderCb In NetworkStatsService, mStatsLock will be held when iterating through the provider list. This is to protect the list from concurrent broadcast that triggered by NetworkPolicyManagerService. This is not good since the binder call is oneway, it does not make sense to block every access to the providers. This change also remove unuse variable and reduce verbose log. Test: atest FrameworksNetTests TetheringTests Bug: 150418178 Change-Id: If74e9f2ea597a0d5ae4668c3358bc687f342bbb5 Merged-In: If74e9f2ea597a0d5ae4668c3358bc687f342bbb5 (cherry picked from commit 5d8f96c6967d5b1a42ba374521078e75a9e6f187) --- .../server/net/NetworkStatsService.java | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index adf017633c..dcbdfdf7a2 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -119,7 +119,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; -import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; @@ -160,6 +159,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; @@ -226,12 +226,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String PREFIX_UID = "uid"; private static final String PREFIX_UID_TAG = "uid_tag"; - /** - * Virtual network interface for video telephony. This is for VT data usage counting purpose. - */ - // TODO: Remove this after no one is using it. - public static final String VT_INTERFACE = NetworkStats.IFACE_VT; - /** * Settings that can be changed externally. */ @@ -304,8 +298,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DropBoxNonMonotonicObserver(); private static final int MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS = 100; - private final RemoteCallbackList mStatsProviderCbList = - new RemoteCallbackList<>(); + private final CopyOnWriteArrayList mStatsProviderCbList = + new CopyOnWriteArrayList<>(); /** Semaphore used to wait for stats provider to respond to request stats update. */ private final Semaphore mStatsProviderSem = new Semaphore(0, true); @@ -1466,10 +1460,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. + // time to allow providers report-in given that normally binder call should be fast. Note + // that size of list might be changed because addition/removing at the same time. For + // addition, the stats of the missed provider can only be collected in next poll; + // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS + // once that happened. // TODO: request with a valid token. Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.getRegisteredCallbackCount(); + final int registeredCallbackCount = mStatsProviderCbList.size(); mStatsProviderSem.drainPermits(); invokeForAllStatsProviderCallbacks( (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); @@ -1643,7 +1641,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); + if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); } } @@ -1934,7 +1932,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( tag, provider, mStatsProviderSem, mAlertObserver, mStatsProviderCbList); - mStatsProviderCbList.register(callback); + mStatsProviderCbList.add(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); return callback; @@ -1958,20 +1956,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void invokeForAllStatsProviderCallbacks( @NonNull ThrowingConsumer task) { - synchronized (mStatsLock) { - final int length = mStatsProviderCbList.beginBroadcast(); + for (final NetworkStatsProviderCallbackImpl cb : mStatsProviderCbList) { try { - for (int i = 0; i < length; i++) { - final NetworkStatsProviderCallbackImpl cb = - mStatsProviderCbList.getBroadcastItem(i); - try { - task.accept(cb); - } catch (RemoteException e) { - Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); - } - } - } finally { - mStatsProviderCbList.finishBroadcast(); + task.accept(cb); + } catch (RemoteException e) { + Log.e(TAG, "Fail to broadcast to provider: " + cb.mTag, e); } } } @@ -1983,7 +1972,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final INetworkStatsProvider mProvider; @NonNull private final Semaphore mSemaphore; @NonNull final INetworkManagementEventObserver mAlertObserver; - @NonNull final RemoteCallbackList mStatsProviderCbList; + @NonNull final CopyOnWriteArrayList mStatsProviderCbList; @NonNull private final Object mProviderStatsLock = new Object(); @@ -1997,7 +1986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, @NonNull INetworkManagementEventObserver alertObserver, - @NonNull RemoteCallbackList cbList) + @NonNull CopyOnWriteArrayList cbList) throws RemoteException { mTag = tag; mProvider = provider; @@ -2054,13 +2043,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void binderDied() { Log.d(TAG, mTag + ": binderDied"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } @Override public void unregister() { Log.d(TAG, mTag + ": unregister"); - mStatsProviderCbList.unregister(this); + mStatsProviderCbList.remove(this); } } From bb4f409b5067c4518538c01390ff00c062411e0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Mon, 23 Dec 2019 14:37:31 -0800 Subject: [PATCH 0775/1150] NetworkStatsService - xt_qtaguid non-ebpf - account stacked interface stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I297fcad0a83bd8c32c0fa6c6a77d83b42cd8c428 --- .../server/net/NetworkStatsService.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5d1cc2a5c2..823717c7d2 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1306,21 +1306,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Traffic occurring on stacked interfaces is usually clatd. - // UID stats are always counted on the stacked interface and never - // on the base interface, because the packets on the base interface - // do not actually match application sockets until they are translated. // - // Interface stats are more complicated. Packets subject to BPF offload - // never appear on the base interface and only appear on the stacked - // interface, so to ensure those packets increment interface stats, interface - // stats from stacked interfaces must be collected. + // UID stats are always counted on the stacked interface and never on the base + // interface, because the packets on the base interface do not actually match + // application sockets (they're not IPv4) and thus the app uid is not known. + // For receive this is obvious: packets must be translated from IPv6 to IPv4 + // before the application socket can be found. + // For transmit: either they go through the clat daemon which by virtue of going + // through userspace strips the original socket association during the IPv4 to + // IPv6 translation process, or they are offloaded by eBPF, which doesn't: + // However, on an ebpf device the accounting is done in cgroup ebpf hooks, + // which don't trigger again post ebpf translation. + // (as such stats accounted to the clat uid are ignored) + // + // Interface stats are more complicated. + // + // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus + // *all* statistics are collected by iptables on the stacked v4-* interface. + // + // Additionally for ingress all packets bound for the clat IPv6 address are dropped + // in ip6tables raw prerouting and thus even non-offloaded packets are only + // accounted for on the stacked interface. + // + // For egress, packets subject to eBPF offload never appear on the base interface + // and only appear on the stacked interface. Thus to ensure packets increment + // interface stats, we must collate data from stacked interfaces. For xt_qtaguid + // (or non eBPF offloaded) TX they would appear on both, however egress interface + // accounting is explicitly bypassed for traffic from the clat uid. + // final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { - if (mUseBpfTrafficStats) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - } + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From 7b69833232b45f09f57ac1f48e5b158ac847790b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 00:58:07 +0000 Subject: [PATCH 0776/1150] NetworkStatsService - xt_qtaguid non-ebpf - account stacked interface stats MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I297fcad0a83bd8c32c0fa6c6a77d83b42cd8c428 Merged-In: I297fcad0a83bd8c32c0fa6c6a77d83b42cd8c428 --- .../server/net/NetworkStatsService.java | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index dcbdfdf7a2..cf5a412321 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1311,21 +1311,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Traffic occurring on stacked interfaces is usually clatd. - // UID stats are always counted on the stacked interface and never - // on the base interface, because the packets on the base interface - // do not actually match application sockets until they are translated. // - // Interface stats are more complicated. Packets subject to BPF offload - // never appear on the base interface and only appear on the stacked - // interface, so to ensure those packets increment interface stats, interface - // stats from stacked interfaces must be collected. + // UID stats are always counted on the stacked interface and never on the base + // interface, because the packets on the base interface do not actually match + // application sockets (they're not IPv4) and thus the app uid is not known. + // For receive this is obvious: packets must be translated from IPv6 to IPv4 + // before the application socket can be found. + // For transmit: either they go through the clat daemon which by virtue of going + // through userspace strips the original socket association during the IPv4 to + // IPv6 translation process, or they are offloaded by eBPF, which doesn't: + // However, on an ebpf device the accounting is done in cgroup ebpf hooks, + // which don't trigger again post ebpf translation. + // (as such stats accounted to the clat uid are ignored) + // + // Interface stats are more complicated. + // + // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus + // *all* statistics are collected by iptables on the stacked v4-* interface. + // + // Additionally for ingress all packets bound for the clat IPv6 address are dropped + // in ip6tables raw prerouting and thus even non-offloaded packets are only + // accounted for on the stacked interface. + // + // For egress, packets subject to eBPF offload never appear on the base interface + // and only appear on the stacked interface. Thus to ensure packets increment + // interface stats, we must collate data from stacked interfaces. For xt_qtaguid + // (or non eBPF offloaded) TX they would appear on both, however egress interface + // accounting is explicitly bypassed for traffic from the clat uid. + // final List stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { - if (mUseBpfTrafficStats) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - } + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); From 7b964ba2c04479158b85b351d3291782e19af147 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 Dec 2019 02:50:35 -0800 Subject: [PATCH 0777/1150] NetworkStats - no need for xt_qtaguid clat bw fixups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is due to the previous addition of the ip6tables raw PREROUTING drop rules for incoming ipv6 clat traffic pre-translation to ipv4. Since we no longer double account, we no longer need these fixups. Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: Ia171b7797cdc99367064d0649bf1293c71579941 --- core/java/android/net/NetworkStats.java | 64 ++++++++++--------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b7fb280efd..3141320a16 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1047,22 +1047,22 @@ public final class NetworkStats implements Parcelable { } /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * Calculate and apply adjustments to captured statistics for 464xlat traffic. * - *

            This mutates both base and stacked traffic stats, to account respectively for - * double-counted traffic and IPv4/IPv6 header size difference. + *

            This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. * - *

            For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, - * every rx 464xlat packet needs to be subtracted from the root UID on the base interface - * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto - * clat uid should be ignored. + *

            UID stats, which are only accounted on the stacked interface, need to be increased + * by 20 bytes/packet to account for translation overhead. * - * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the - * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still - * needs to be ignored. + *

            The potential additional overhead of 8 bytes/packet for ip fragments is ignored. + * + *

            Interface stats need to sum traffic on both stacked and base interface because: + * - eBPF offloaded packets appear only on the stacked interface + * - Non-offloaded ingress packets appear only on the stacked interface + * (due to iptables raw PREROUTING drop rules) + * - Non-offloaded egress packets appear only on the stacked interface + * (due to ignoring traffic from clat daemon by uid match) + * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} @@ -1074,46 +1074,34 @@ public final class NetworkStats implements Parcelable { */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - // For recycling Entry entry = null; - Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < stackedTraffic.size; i++) { entry = stackedTraffic.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = stackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base - // interface. As for eBPF, the per uid stats is collected by different hook, the rx - // packets on base interface will not be counted. - adjust.iface = baseIface; - if (!useBpfStats) { - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; - } - adjustments.combineValues(adjust); + if (entry == null) continue; + if (entry.iface == null) continue; + if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). + // + // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor + // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. + // + // While the ebpf code path does try to simulate proper post segmentation packet + // counts, we have nothing of the sort of xt_qtaguid stats. entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked - // v4 interface, so it needs to be removed to avoid double-counting. + // Theoretically there should be no traffic accounted to the clat daemon's uid: + // see ebpf program 'netd.c's early returns + // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting + // TODO: remove this - should definitely be safe once ebpf only. baseTraffic.removeUids(new int[] {CLAT_UID}); - baseTraffic.combineAllValues(adjustments); } /** From 7c8b7b14ea357a1fe8cb4afae815aa50c8a6431a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:06:28 -0700 Subject: [PATCH 0778/1150] NetworkStats: apply464xlatAdjustments - remove useBpfStats parameter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I0121a4ac7ee824adc5930bab786d550b2f00b05b --- core/java/android/net/NetworkStats.java | 7 +++---- .../com/android/server/net/NetworkStatsFactory.java | 10 ++++------ .../com/android/server/net/NetworkStatsService.java | 5 ++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 3141320a16..ea0889276c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1069,11 +1069,10 @@ public final class NetworkStats implements Parcelable { * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @param useBpfStats True if eBPF is in use. * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { + NetworkStats stackedTraffic, Map stackedIfaces) { // For recycling Entry entry = null; for (int i = 0; i < stackedTraffic.size; i++) { @@ -1113,8 +1112,8 @@ public final class NetworkStats implements Parcelable { * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @hide */ - public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { - apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); + public void apply464xlatAdjustments(Map stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3dac106418..86ad0b3086 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -152,12 +152,10 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, - useBpfStats); + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } public NetworkStatsFactory() { @@ -380,7 +378,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 823717c7d2..ba538e1cd8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1877,14 +1877,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, - mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats, mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); uidSnapshot.combineAllValues(providerStats); uidSnapshot.combineAllValues(mUidOperations); From d03416842c26a5fbeeca041aa6e6498b93147c7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:33:52 -0700 Subject: [PATCH 0779/1150] NetworkStats: apply464xlatAdjustments - don't remove CLAT_UID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should no longer be needed after all the cleanups. Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I289d935f84b616ed857ef4c5a7427d57c282d00c --- core/java/android/net/NetworkStats.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ea0889276c..34e48eb44f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.Process.CLAT_UID; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1095,12 +1093,6 @@ public final class NetworkStats implements Parcelable { entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - - // Theoretically there should be no traffic accounted to the clat daemon's uid: - // see ebpf program 'netd.c's early returns - // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting - // TODO: remove this - should definitely be safe once ebpf only. - baseTraffic.removeUids(new int[] {CLAT_UID}); } /** From cbc6c27d2037260b8f698dbde740af8f4f5e461e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 24 Dec 2019 02:50:35 -0800 Subject: [PATCH 0780/1150] NetworkStats - no need for xt_qtaguid clat bw fixups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is due to the previous addition of the ip6tables raw PREROUTING drop rules for incoming ipv6 clat traffic pre-translation to ipv4. Since we no longer double account, we no longer need these fixups. Test: atest bpf_module_test clatd_test libbpf_android_test libnetdbpf_test netd_integration_test netd_unit_test netdutils_test Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: Ia171b7797cdc99367064d0649bf1293c71579941 Merged-In: Ia171b7797cdc99367064d0649bf1293c71579941 --- core/java/android/net/NetworkStats.java | 64 ++++++++++--------------- 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b7fb280efd..3141320a16 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1047,22 +1047,22 @@ public final class NetworkStats implements Parcelable { } /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * Calculate and apply adjustments to captured statistics for 464xlat traffic. * - *

            This mutates both base and stacked traffic stats, to account respectively for - * double-counted traffic and IPv4/IPv6 header size difference. + *

            This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. * - *

            For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, - * every rx 464xlat packet needs to be subtracted from the root UID on the base interface - * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto - * clat uid should be ignored. + *

            UID stats, which are only accounted on the stacked interface, need to be increased + * by 20 bytes/packet to account for translation overhead. * - * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the - * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still - * needs to be ignored. + *

            The potential additional overhead of 8 bytes/packet for ip fragments is ignored. + * + *

            Interface stats need to sum traffic on both stacked and base interface because: + * - eBPF offloaded packets appear only on the stacked interface + * - Non-offloaded ingress packets appear only on the stacked interface + * (due to iptables raw PREROUTING drop rules) + * - Non-offloaded egress packets appear only on the stacked interface + * (due to ignoring traffic from clat daemon by uid match) + * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) * *

            This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} @@ -1074,46 +1074,34 @@ public final class NetworkStats implements Parcelable { */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - // For recycling Entry entry = null; - Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < stackedTraffic.size; i++) { entry = stackedTraffic.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = stackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base - // interface. As for eBPF, the per uid stats is collected by different hook, the rx - // packets on base interface will not be counted. - adjust.iface = baseIface; - if (!useBpfStats) { - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; - } - adjustments.combineValues(adjust); + if (entry == null) continue; + if (entry.iface == null) continue; + if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). + // + // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor + // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. + // + // While the ebpf code path does try to simulate proper post segmentation packet + // counts, we have nothing of the sort of xt_qtaguid stats. entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked - // v4 interface, so it needs to be removed to avoid double-counting. + // Theoretically there should be no traffic accounted to the clat daemon's uid: + // see ebpf program 'netd.c's early returns + // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting + // TODO: remove this - should definitely be safe once ebpf only. baseTraffic.removeUids(new int[] {CLAT_UID}); - baseTraffic.combineAllValues(adjustments); } /** From c9d2d396386522e1a070495cf8556fccfcd5bef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:06:28 -0700 Subject: [PATCH 0781/1150] NetworkStats: apply464xlatAdjustments - remove useBpfStats parameter. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I0121a4ac7ee824adc5930bab786d550b2f00b05b Merged-In: I0121a4ac7ee824adc5930bab786d550b2f00b05b --- core/java/android/net/NetworkStats.java | 7 +++---- .../com/android/server/net/NetworkStatsFactory.java | 10 ++++------ .../com/android/server/net/NetworkStatsService.java | 5 ++--- 3 files changed, 9 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 3141320a16..ea0889276c 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -1069,11 +1069,10 @@ public final class NetworkStats implements Parcelable { * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @param useBpfStats True if eBPF is in use. * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map stackedIfaces, boolean useBpfStats) { + NetworkStats stackedTraffic, Map stackedIfaces) { // For recycling Entry entry = null; for (int i = 0; i < stackedTraffic.size; i++) { @@ -1113,8 +1112,8 @@ public final class NetworkStats implements Parcelable { * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @hide */ - public void apply464xlatAdjustments(Map stackedIfaces, boolean useBpfStats) { - apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); + public void apply464xlatAdjustments(Map stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3dac106418..86ad0b3086 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -152,12 +152,10 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, - useBpfStats); + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } public NetworkStatsFactory() { @@ -380,7 +378,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index cf5a412321..ba9f486092 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1882,14 +1882,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, - mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats, mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); uidSnapshot.combineAllValues(providerStats); uidSnapshot.combineAllValues(mUidOperations); From 212334b7b9dd274eb46b1212816d787d4fc0130c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Thu, 28 May 2020 01:33:52 -0700 Subject: [PATCH 0782/1150] NetworkStats: apply464xlatAdjustments - don't remove CLAT_UID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should no longer be needed after all the cleanups. Test: atest NetworkStatsTest NetworkStatsFactoryTest Bug: 150738490 Signed-off-by: Maciej Żenczykowski Change-Id: I289d935f84b616ed857ef4c5a7427d57c282d00c Merged-In: I289d935f84b616ed857ef4c5a7427d57c282d00c --- core/java/android/net/NetworkStats.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index ea0889276c..34e48eb44f 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.Process.CLAT_UID; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1095,12 +1093,6 @@ public final class NetworkStats implements Parcelable { entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - - // Theoretically there should be no traffic accounted to the clat daemon's uid: - // see ebpf program 'netd.c's early returns - // and iptables '-m owner --uid-owner clat -j RETURN' rules prior to accounting - // TODO: remove this - should definitely be safe once ebpf only. - baseTraffic.removeUids(new int[] {CLAT_UID}); } /** From 7acca65e50dc73698ff736bf3a6ea66298ffb74f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Apr 2020 18:07:42 +0800 Subject: [PATCH 0783/1150] Add unit test for NetworkStatsSubscriptionsMonitor Bug: 154080205 Test: atest FrameworksNetTests:com.android.server.net.NetworkStatsSubscriptionsMonitorTest Change-Id: I4ef3f1ab2e5ea1322133edd80db3ccd0022e9c91 --- .../server/net/NetworkStatsSubscriptionsMonitor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 0bdf3f22ee..a0ab5eae73 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -28,6 +28,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; @@ -38,8 +39,6 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ -// TODO (b/152176562): Write tests to verify subscription changes generate corresponding -// register/unregister calls. public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { @@ -207,5 +206,10 @@ public class NetworkStatsSubscriptionsMonitor extends mLastCollapsedRatType = collapsedRatType; mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); } + + @VisibleForTesting + public int getSubId() { + return mSubId; + } } } From 03e98293ed7ba54e31a018efa724c1ee061a79db Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Apr 2020 18:07:42 +0800 Subject: [PATCH 0784/1150] Add unit test for NetworkStatsSubscriptionsMonitor Bug: 154080205 Test: atest FrameworksNetTests:com.android.server.net.NetworkStatsSubscriptionsMonitorTest (copy from ag/11788484 but getActiveAndHiddenSubscriptionIdList() since it's renamed in internal) Change-Id: Ia162f36efe96d90b2f6f70190d9fa855bba34484 Merged-In: I4ef3f1ab2e5ea1322133edd80db3ccd0022e9c91 --- .../server/net/NetworkStatsSubscriptionsMonitor.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 16a63d5436..dc3c30a18a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -28,6 +28,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; @@ -38,8 +39,6 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ -// TODO (b/152176562): Write tests to verify subscription changes generate corresponding -// register/unregister calls. public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { @@ -207,5 +206,10 @@ public class NetworkStatsSubscriptionsMonitor extends mLastCollapsedRatType = collapsedRatType; mMonitor.mDelegate.onCollapsedRatTypeChanged(mSubscriberId, mLastCollapsedRatType); } + + @VisibleForTesting + public int getSubId() { + return mSubId; + } } } From 46f32c01aa2847367ddf70f22a59a79abcf8d808 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 20 May 2020 15:21:28 +0800 Subject: [PATCH 0785/1150] Dynamically enable/disable watch for RAT type changes Add ContentObserver to observe the status of NETSTATS_COMBINE_SUBTYPE_ENABLED to determine that NetworkStatsSubscriptionsMonitor start or stop monitoring data usage per RAT type changes. Bug: 154080515 Test: atest NetworkStatsServiceTest#testDynamicWatchForNetworkRatTypeChanges Change-Id: I272d589633c9186b45753228b05aa0b40b7c7b89 --- .../server/net/NetworkStatsService.java | 42 ++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ba538e1cd8..6e01592c51 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -87,6 +87,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; @@ -103,6 +104,7 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.net.Uri; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; @@ -213,6 +215,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; + private final ContentObserver mContentObserver; + private final ContentResolver mContentResolver; + @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -438,6 +443,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandler = new NetworkStatsHandler(handlerThread.getLooper()); mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, new HandlerExecutor(mHandler), this); + mContentResolver = mContext.getContentResolver(); + mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, + mNetworkStatsSubscriptionsMonitor); } /** @@ -466,6 +474,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } + + /** + * Create a ContentObserver instance which is used to observe settings changes, + * and dispatch onChange events on handler thread. + */ + public @NonNull ContentObserver makeContentObserver(@NonNull Handler handler, + @NonNull NetworkStatsSettings settings, + @NonNull NetworkStatsSubscriptionsMonitor monitor) { + return new ContentObserver(handler) { + @Override + public void onChange(boolean selfChange, @NonNull Uri uri) { + if (!settings.getCombineSubtypeEnabled()) { + monitor.start(); + } else { + monitor.stop(); + } + } + }; + } } private void registerLocalService() { @@ -530,11 +557,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, mSettings.getPollInterval(), pollIntent); - // TODO: listen to settings changed to support dynamically enable/disable. - // watch for networkType changes - if (!mSettings.getCombineSubtypeEnabled()) { - mNetworkStatsSubscriptionsMonitor.start(); - } + mContentResolver.registerContentObserver(Settings.Global + .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED), + false /* notifyForDescendants */, mContentObserver); + + // Post a runnable on handler thread to call onChange(). It's for getting current value of + // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes. + mHandler.post(() -> mContentObserver.onChange(false, Settings.Global + .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED))); registerGlobalAlert(); } @@ -560,6 +590,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mNetworkStatsSubscriptionsMonitor.stop(); } + mContentResolver.unregisterContentObserver(mContentObserver); + final long currentTime = mClock.millis(); // persist any pending stats From 8ef2a47c500bd4b889352e9a63ca884f8b67cf9d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 17 Jun 2020 18:25:35 +0800 Subject: [PATCH 0786/1150] Address comments from aosp/1298476 This patch addresses the followings, - Pass Looper to NetworkStatsSubscriptionsMonitor constructor - Replace Looper with TestLooper in unit test - Assert fail if result of condition check is not expected. Bug: 154080205 Test: atest FrameworksNetTests:com.android.server.net.NetworkStatsServiceTest atest FrameworksNetTests:com.android.server.net.NetworkStatsSubscriptionsMonitorTest Change-Id: Ibcaba2b38af80cc0ec9a4e428a3b3a1538bc4325 --- .../java/com/android/server/net/NetworkStatsService.java | 9 +++++---- .../server/net/NetworkStatsSubscriptionsMonitor.java | 7 ++++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 6e01592c51..fd8ac061bb 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -442,7 +442,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, - new HandlerExecutor(mHandler), this); + mHandler.getLooper(), new HandlerExecutor(mHandler), this); mContentResolver = mContext.getContentResolver(); mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); @@ -468,11 +468,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @NonNull public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, - @NonNull Executor executor, @NonNull NetworkStatsService service) { + @NonNull Looper looper, @NonNull Executor executor, + @NonNull NetworkStatsService service) { // TODO: Update RatType passively in NSS, instead of querying into the monitor // when forceUpdateIface. - return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> - service.handleOnCollapsedRatTypeChanged()); + return new NetworkStatsSubscriptionsMonitor(context, looper, executor, + (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } /** diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index dc3c30a18a..7711c6a21d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -20,6 +20,7 @@ import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; +import android.os.Looper; import android.telephony.Annotation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; @@ -75,9 +76,9 @@ public class NetworkStatsSubscriptionsMonitor extends @NonNull private final Executor mExecutor; - NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, - @NonNull Delegate delegate) { - super(); + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Looper looper, + @NonNull Executor executor, @NonNull Delegate delegate) { + super(looper); mSubscriptionManager = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); From a38ff0a96e11d48a6ad6cba0815c9ad5b49a6e8d Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Fri, 19 Jun 2020 19:48:07 -0700 Subject: [PATCH 0787/1150] Update docs for methods that require subscriberId In Android 10 additional restrictions were required to access the subscriberId. The NetworkStatsManager has several methods that accept a subscriberId of the mobile network for which usage should be queried. This commit updates the docs for these methods to reference the new access restrictions and offer null as an option to obtain the usage for all mobile networks. Fixes: 157871064 Test: m docs Change-Id: I95c730c9418fced6312eb3ba4e0d69e6299f3ded --- .../app/usage/NetworkStatsManager.java | 43 +++++++++++++++++-- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index d6e77624a9..fc8248e101 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -41,6 +41,7 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import android.telephony.TelephonyManager; import android.util.DataUnit; import android.util.Log; @@ -198,6 +199,12 @@ public class NetworkStatsManager { * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -231,6 +238,12 @@ public class NetworkStatsManager { * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -268,6 +281,12 @@ public class NetworkStatsManager { * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -301,7 +320,7 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid. * - * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) + * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException { @@ -319,7 +338,7 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid and tag. * - * #see queryDetailsForUidTagState(int, String, long, long, int, int, int) + * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag) throws SecurityException { @@ -344,6 +363,12 @@ public class NetworkStatsManager { * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -398,6 +423,12 @@ public class NetworkStatsManager { * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} * etc. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -455,7 +486,7 @@ public class NetworkStatsManager { /** * Registers to receive notifications about data usage on specified networks. * - * #see registerUsageCallback(int, String[], long, UsageCallback, Handler) + * @see #registerUsageCallback(int, String, long, UsageCallback, Handler) */ public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, UsageCallback callback) { @@ -472,6 +503,12 @@ public class NetworkStatsManager { * @param networkType Type of network to monitor. Either {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when registering for the mobile network type to receive + * notifications for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. * @param thresholdBytes Threshold in bytes to be notified on. * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. From 6bdfba28ab299dadffa650fd7b859fe70da40da6 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Thu, 2 Jul 2020 10:52:18 +0000 Subject: [PATCH 0788/1150] ITetheredInterfaceCallback is a oneway interface This is sent from the system server, and the system server doesn't like being blocked by apps. Change-Id: I603be3038831974baf1dc392ff0d062e9db91b63 Test: atest CtsTetheringTest Bug: 160389275 --- core/java/android/net/ITetheredInterfaceCallback.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl index e3d075988c..14aa0237f2 100644 --- a/core/java/android/net/ITetheredInterfaceCallback.aidl +++ b/core/java/android/net/ITetheredInterfaceCallback.aidl @@ -17,7 +17,7 @@ package android.net; /** @hide */ -interface ITetheredInterfaceCallback { +oneway interface ITetheredInterfaceCallback { void onAvailable(in String iface); void onUnavailable(); } \ No newline at end of file From c37e3d08b1e9009da9e91354b7a7c531904ce888 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 18 Oct 2019 18:42:19 +0800 Subject: [PATCH 0789/1150] Remove ProxyInfo(String) and update callers to use ProxyInfo(Uri) Update all callers to use ProxyInfo(Uri) and remove ProxyInfo(String). Bug: 160557668 Test: build pass atest FrameworksNetTests Change-Id: I4c980764c8839c48acf03208bb68cd53eb910121 --- services/core/java/com/android/server/net/IpConfigStore.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index e3e02e32ad..f0bf5c0975 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -24,6 +24,7 @@ import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; +import android.net.Uri; import android.util.ArrayMap; import android.util.Log; import android.util.SparseArray; @@ -372,7 +373,7 @@ public class IpConfigStore { config.httpProxy = proxyInfo; break; case PAC: - ProxyInfo proxyPacProperties = new ProxyInfo(pacFileUrl); + ProxyInfo proxyPacProperties = new ProxyInfo(Uri.parse(pacFileUrl)); config.proxySettings = proxySettings; config.httpProxy = proxyPacProperties; break; From eaa76fbd45731e06a5397892b61cc5f6b5ad30cd Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 8 Jul 2020 18:48:00 +0800 Subject: [PATCH 0790/1150] Attribute data usage to 5G for 5G non-standalone mode Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Bug: 160727498 Change-Id: I563df14500caeb3602b381479afaf5163ad8e6a1 --- .../net/NetworkStatsSubscriptionsMonitor.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 7711c6a21d..dc64393bbf 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Looper; import android.telephony.Annotation; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -196,7 +197,19 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); + // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony + // would report RAT = 5G_NR. + // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and + // network allocates a secondary 5G cell so telephony reports RAT = LTE along with + // NR state as connected. In such case, attributes the data usage to NR. + // See b/160727498. + final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE + || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) + && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + + final int networkType = + (is5GNsa ? TelephonyManager.NETWORK_TYPE_NR : ss.getDataNetworkType()); + final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From cdf050d08f0a533a01fa7fb1d254dfc03bfdd78a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 10 Jul 2020 03:40:35 +0000 Subject: [PATCH 0791/1150] Revert "Attribute data usage to 5G for 5G non-standalone mode" This reverts commit eaa76fbd45731e06a5397892b61cc5f6b5ad30cd. Reason for revert: Revert and wait for the design is settled down. Change-Id: I10fdfc37d6456678de1886698cd6ad08bf8aa810 --- .../net/NetworkStatsSubscriptionsMonitor.java | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index dc64393bbf..7711c6a21d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -22,7 +22,6 @@ import android.annotation.NonNull; import android.content.Context; import android.os.Looper; import android.telephony.Annotation; -import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -197,19 +196,7 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony - // would report RAT = 5G_NR. - // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and - // network allocates a secondary 5G cell so telephony reports RAT = LTE along with - // NR state as connected. In such case, attributes the data usage to NR. - // See b/160727498. - final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE - || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) - && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; - - final int networkType = - (is5GNsa ? TelephonyManager.NETWORK_TYPE_NR : ss.getDataNetworkType()); - + final int networkType = ss.getDataNetworkType(); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From 37c58e61b4f6818bcf678d7c8ade802aebac8a10 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 16 Jul 2020 13:48:09 +0800 Subject: [PATCH 0792/1150] Attribute data usage to virtual RAT type for 5G non-standalone mode Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Bug: 160727498 Change-Id: I8753e68140c0993773017c9a49bd8a666a364071 --- core/java/android/net/NetworkTemplate.java | 12 ++++++++++++ .../net/NetworkStatsSubscriptionsMonitor.java | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index eba7ff3483..7234eb1d81 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable { * @hide */ public static final int NETWORK_TYPE_ALL = -1; + /** + * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is + * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along + * with NR state as connected. This should not be overlapped with any of the + * {@code TelephonyManager.NETWORK_TYPE_*} constants. + * + * @hide + */ + public static final int NETWORK_TYPE_5G_NSA = -2; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -475,6 +484,9 @@ public class NetworkTemplate implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_NR: return TelephonyManager.NETWORK_TYPE_NR; + // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + case NetworkTemplate.NETWORK_TYPE_5G_NSA: + return NetworkTemplate.NETWORK_TYPE_5G_NSA; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index db553ee795..0575ac6315 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -16,12 +16,14 @@ package com.android.server.net; +import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; import android.os.Looper; import android.telephony.Annotation; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -196,7 +198,18 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); + // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony + // would report RAT = 5G_NR. + // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and + // network allocates a secondary 5G cell so telephony reports RAT = LTE along with + // NR state as connected. In such case, attributes the data usage to NR. + // See b/160727498. + final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE + || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) + && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + + final int networkType = + (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType()); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From 4f635a08502d27df924906b3eff883b3be29e5ab Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 16 Jul 2020 13:48:09 +0800 Subject: [PATCH 0793/1150] Attribute data usage to virtual RAT type for 5G non-standalone mode Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Bug: 160727498 Change-Id: I8753e68140c0993773017c9a49bd8a666a364071 Merged-In: I8753e68140c0993773017c9a49bd8a666a364071 (cherry-picked from ag/12167624) --- core/java/android/net/NetworkTemplate.java | 12 ++++++++++++ .../net/NetworkStatsSubscriptionsMonitor.java | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index eba7ff3483..7234eb1d81 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -87,6 +87,15 @@ public class NetworkTemplate implements Parcelable { * @hide */ public static final int NETWORK_TYPE_ALL = -1; + /** + * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is + * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along + * with NR state as connected. This should not be overlapped with any of the + * {@code TelephonyManager.NETWORK_TYPE_*} constants. + * + * @hide + */ + public static final int NETWORK_TYPE_5G_NSA = -2; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -475,6 +484,9 @@ public class NetworkTemplate implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_NR: return TelephonyManager.NETWORK_TYPE_NR; + // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + case NetworkTemplate.NETWORK_TYPE_5G_NSA: + return NetworkTemplate.NETWORK_TYPE_5G_NSA; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index a0ab5eae73..cb1c7e4fd0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -16,11 +16,13 @@ package com.android.server.net; +import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; import android.telephony.Annotation; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -195,7 +197,18 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); + // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony + // would report RAT = 5G_NR. + // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and + // network allocates a secondary 5G cell so telephony reports RAT = LTE along with + // NR state as connected. In such case, attributes the data usage to NR. + // See b/160727498. + final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE + || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) + && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + + final int networkType = + (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType()); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From 6595b08d8da8aabe640ef4dddde4a500b231f356 Mon Sep 17 00:00:00 2001 From: Peter Wang Date: Mon, 16 Mar 2020 04:45:23 -0700 Subject: [PATCH 0794/1150] [Telephony Mainline] Rename getActiveAndHiddenSubscriptionIdList and guard with permission Bug: 150878235 Fix: 150878235 Test: Build Change-Id: I7f3b1f5170e032336d9b39b322c49e2b92573586 Merged-In: I7f3b1f5170e032336d9b39b322c49e2b92573586 --- .../android/server/net/NetworkStatsSubscriptionsMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 7711c6a21d..db553ee795 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -125,7 +125,7 @@ public class NetworkStatsSubscriptionsMonitor extends @NonNull private List getActiveSubIdList(@NonNull SubscriptionManager subscriptionManager) { final ArrayList ret = new ArrayList<>(); - final int[] ids = subscriptionManager.getActiveAndHiddenSubscriptionIdList(); + final int[] ids = subscriptionManager.getCompleteActiveSubscriptionIdList(); for (int id : ids) ret.add(id); return ret; } From 7fd64dee0f5558232ea0b3df268f06e6b3a1bd4f Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 16 Jul 2020 13:48:09 +0800 Subject: [PATCH 0795/1150] Attribute data usage to virtual RAT type for 5G non-standalone mode Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Bug: 160727498 Change-Id: I8753e68140c0993773017c9a49bd8a666a364071 Merged-In: I8753e68140c0993773017c9a49bd8a666a364071 (cherry-picked from ag/12167624) --- core/java/android/net/NetworkTemplate.java | 12 ++++++++++++ .../net/NetworkStatsSubscriptionsMonitor.java | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cb9463a59d..4b806e714f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -84,6 +84,15 @@ public class NetworkTemplate implements Parcelable { * @hide */ public static final int NETWORK_TYPE_ALL = -1; + /** + * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is + * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along + * with NR state as connected. This should not be overlapped with any of the + * {@code TelephonyManager.NETWORK_TYPE_*} constants. + * + * @hide + */ + public static final int NETWORK_TYPE_5G_NSA = -2; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -472,6 +481,9 @@ public class NetworkTemplate implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_NR: return TelephonyManager.NETWORK_TYPE_NR; + // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + case NetworkTemplate.NETWORK_TYPE_5G_NSA: + return NetworkTemplate.NETWORK_TYPE_5G_NSA; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 7711c6a21d..5f2c4a38b4 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -16,12 +16,14 @@ package com.android.server.net; +import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; import android.os.Looper; import android.telephony.Annotation; +import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.SubscriptionManager; @@ -196,7 +198,18 @@ public class NetworkStatsSubscriptionsMonitor extends @Override public void onServiceStateChanged(@NonNull ServiceState ss) { - final int networkType = ss.getDataNetworkType(); + // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony + // would report RAT = 5G_NR. + // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and + // network allocates a secondary 5G cell so telephony reports RAT = LTE along with + // NR state as connected. In such case, attributes the data usage to NR. + // See b/160727498. + final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE + || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) + && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + + final int networkType = + (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType()); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From f4e77ac570c1a571378da92410ec99ab73c32c12 Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Tue, 21 Jul 2020 14:18:23 +0530 Subject: [PATCH 0796/1150] Gracefully handle integer overflows. Avoid recording negative data by doing integer-based math as much as possible, but switch to double-based math if we detect that we'd end up causing an overflow. Test : - Builds, Boots - High data throughput scenarios - NetworkStatsHistoryTest, NetworkStatsCollectionTest, NetworkStatsTest Bug: 119527458 Change-Id: I55d4aa649bea3ae201ad513074ff2b71cb918dad --- .../java/android/net/NetworkStatsHistory.java | 36 ++++++++++----- .../server/net/NetworkStatsCollection.java | 46 +++++-------------- 2 files changed, 36 insertions(+), 46 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index c82c288222..897b67cbaf 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -26,6 +26,7 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; +import static android.net.NetworkUtils.multiplySafeByRational; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; @@ -364,11 +365,12 @@ public class NetworkStatsHistory implements Parcelable { if (overlap <= 0) continue; // integer math each time is faster than floating point - final long fracRxBytes = rxBytes * overlap / duration; - final long fracRxPackets = rxPackets * overlap / duration; - final long fracTxBytes = txBytes * overlap / duration; - final long fracTxPackets = txPackets * overlap / duration; - final long fracOperations = operations * overlap / duration; + final long fracRxBytes = multiplySafeByRational(rxBytes, overlap, duration); + final long fracRxPackets = multiplySafeByRational(rxPackets, overlap, duration); + final long fracTxBytes = multiplySafeByRational(txBytes, overlap, duration); + final long fracTxPackets = multiplySafeByRational(txPackets, overlap, duration); + final long fracOperations = multiplySafeByRational(operations, overlap, duration); + addLong(activeTime, i, overlap); addLong(this.rxBytes, i, fracRxBytes); rxBytes -= fracRxBytes; @@ -568,12 +570,24 @@ public class NetworkStatsHistory implements Parcelable { if (overlap <= 0) continue; // integer math each time is faster than floating point - if (activeTime != null) entry.activeTime += activeTime[i] * overlap / bucketSpan; - if (rxBytes != null) entry.rxBytes += rxBytes[i] * overlap / bucketSpan; - if (rxPackets != null) entry.rxPackets += rxPackets[i] * overlap / bucketSpan; - if (txBytes != null) entry.txBytes += txBytes[i] * overlap / bucketSpan; - if (txPackets != null) entry.txPackets += txPackets[i] * overlap / bucketSpan; - if (operations != null) entry.operations += operations[i] * overlap / bucketSpan; + if (activeTime != null) { + entry.activeTime += multiplySafeByRational(activeTime[i], overlap, bucketSpan); + } + if (rxBytes != null) { + entry.rxBytes += multiplySafeByRational(rxBytes[i], overlap, bucketSpan); + } + if (rxPackets != null) { + entry.rxPackets += multiplySafeByRational(rxPackets[i], overlap, bucketSpan); + } + if (txBytes != null) { + entry.txBytes += multiplySafeByRational(txBytes[i], overlap, bucketSpan); + } + if (txPackets != null) { + entry.txPackets += multiplySafeByRational(txPackets[i], overlap, bucketSpan); + } + if (operations != null) { + entry.operations += multiplySafeByRational(operations[i], overlap, bucketSpan); + } } return entry; } diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index ab525237db..ba3cea768c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -28,6 +28,7 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; +import static android.net.NetworkUtils.multiplySafeByRational; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.TAG; @@ -185,35 +186,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } - /** - * Safely multiple a value by a rational. - *

            - * Internally it uses integer-based math whenever possible, but switches - * over to double-based math if values would overflow. - */ - @VisibleForTesting - public static long multiplySafe(long value, long num, long den) { - if (den == 0) den = 1; - long x = value; - long y = num; - - // Logic shamelessly borrowed from Math.multiplyExact() - long r = x * y; - long ax = Math.abs(x); - long ay = Math.abs(y); - if (((ax | ay) >>> 31 != 0)) { - // Some bits greater than 2^31 that might cause overflow - // Check the result using the divide operator - // and check for the special case of Long.MIN_VALUE * -1 - if (((y != 0) && (r / y != x)) || - (x == Long.MIN_VALUE && y == -1)) { - // Use double math to avoid overflowing - return (long) (((double) num / den) * value); - } - } - return r / den; - } - public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { return getRelevantUids(accessLevel, Binder.getCallingUid()); } @@ -311,11 +283,13 @@ public class NetworkStatsCollection implements FileRotator.Reader { } final long rawBytes = entry.rxBytes + entry.txBytes; - final long rawRxBytes = entry.rxBytes; - final long rawTxBytes = entry.txBytes; + final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; + final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; final long targetBytes = augmentPlan.getDataUsageBytes(); - final long targetRxBytes = multiplySafe(targetBytes, rawRxBytes, rawBytes); - final long targetTxBytes = multiplySafe(targetBytes, rawTxBytes, rawBytes); + + final long targetRxBytes = multiplySafeByRational(targetBytes, rawRxBytes, rawBytes); + final long targetTxBytes = multiplySafeByRational(targetBytes, rawTxBytes, rawBytes); + // Scale all matching buckets to reach anchor target final long beforeTotal = combined.getTotalBytes(); @@ -323,8 +297,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { combined.getValues(i, entry); if (entry.bucketStart >= augmentStart && entry.bucketStart + entry.bucketDuration <= augmentEnd) { - entry.rxBytes = multiplySafe(targetRxBytes, entry.rxBytes, rawRxBytes); - entry.txBytes = multiplySafe(targetTxBytes, entry.txBytes, rawTxBytes); + entry.rxBytes = multiplySafeByRational( + targetRxBytes, entry.rxBytes, rawRxBytes); + entry.txBytes = multiplySafeByRational( + targetTxBytes, entry.txBytes, rawTxBytes); // We purposefully clear out packet counters to indicate // that this data has been augmented. entry.rxPackets = 0; From 3dc92d5243b1b5d55e6ccae5a02d96ee8afc573e Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 28 Jul 2020 13:53:09 +0800 Subject: [PATCH 0797/1150] Update language to comply with Android's inclusive language guidance See https://source.android.com/setup/contribute/respectful-code for reference. Bug: 161896447 Test: m Change-Id: I6c3c03c0c2d1302af6d5245486823c13a3432900 --- .../core/java/com/android/server/net/NetworkStatsFactory.java | 4 ++-- .../java/com/android/server/net/NetworkStatsRecorder.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 86ad0b3086..e9868fde30 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -59,7 +59,7 @@ public class NetworkStatsFactory { private static final String TAG = "NetworkStatsFactory"; private static final boolean USE_NATIVE_PARSING = true; - private static final boolean SANITY_CHECK_NATIVE = false; + private static final boolean VALIDATE_NATIVE_STATS = false; /** Path to {@code /proc/net/xt_qtaguid/iface_stat_all}. */ private final File mStatsXtIfaceAll; @@ -347,7 +347,7 @@ public class NetworkStatsFactory { INTERFACES_ALL, TAG_ALL, mUseBpfStats) != 0) { throw new IOException("Failed to parse network stats"); } - if (SANITY_CHECK_NATIVE) { + if (VALIDATE_NATIVE_STATS) { final NetworkStats javaStats = javaReadNetworkStatsDetail(mStatsXtUid, UID_ALL, INTERFACES_ALL, TAG_ALL); assertEquals(javaStats, stats); diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index a94a2f79ab..66eda1fc2d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -227,7 +227,7 @@ public class NetworkStatsRecorder { for (int i = 0; i < delta.size(); i++) { entry = delta.getValues(i, entry); - // As a last-ditch sanity check, report any negative values and + // As a last-ditch check, report any negative values and // clamp them so recording below doesn't croak. if (entry.isNegative()) { if (mObserver != null) { From 55b277c912300e4dded55ee1dd7982bbdb0020dd Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 29 Jul 2020 12:05:04 +0800 Subject: [PATCH 0798/1150] Update language to comply with Android's inclusive language guidance See https://source.android.com/setup/contribute/respectful-code for reference. Test: m ; atest TetheringTests Bug: 161896447 Change-Id: Idc58697c72fb00896bee00185fefc50c1a24dd35 --- .../Tethering/src/android/net/util/TetheringMessageBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java index 1b763ce920..29c0a817b6 100644 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java @@ -19,7 +19,7 @@ package android.net.util; * This class defines Message.what base addresses for various state machine. */ public class TetheringMessageBase { - public static final int BASE_MASTER = 0; + public static final int BASE_MAIN_SM = 0; public static final int BASE_IPSERVER = 100; } From c040064a230e82df19c18f771443a9ff3d8c9fef Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 29 Jul 2020 12:05:04 +0800 Subject: [PATCH 0799/1150] Update language to comply with Android's inclusive language guidance See https://source.android.com/setup/contribute/respectful-code for reference. Test: m ; atest TetheringTests Bug: 161896447 Change-Id: Idc58697c72fb00896bee00185fefc50c1a24dd35 Merged-In: Idc58697c72fb00896bee00185fefc50c1a24dd35 --- .../Tethering/src/android/net/util/TetheringMessageBase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java index 1b763ce920..29c0a817b6 100644 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java @@ -19,7 +19,7 @@ package android.net.util; * This class defines Message.what base addresses for various state machine. */ public class TetheringMessageBase { - public static final int BASE_MASTER = 0; + public static final int BASE_MAIN_SM = 0; public static final int BASE_IPSERVER = 100; } From 20452935f96a5463bd32482bf3dea813ca63d98c Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 12 Aug 2020 12:23:59 +0800 Subject: [PATCH 0800/1150] Update language to comply with Android's inclusive language guidance See https://source.android.com/setup/contribute/respectful-code for reference. Bug: 161896447 Test: m ; atest FrameworkNetTests Change-Id: Ib6b4c9526992c31e05e82be80e2b9b86bc0b57ef --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 6402e07bdd..b2f0c8376d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1477,7 +1477,7 @@ public class IpSecService extends IIpSecService.Stub { } /** - * Checks an IpSecConfig parcel to ensure that the contents are sane and throws an + * Checks an IpSecConfig parcel to ensure that the contents are valid and throws an * IllegalArgumentException if they are not. */ private void checkIpSecConfig(IpSecConfig config) { From a66d7c4361dfed2d1d13564c99be17d436d9b377 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 7 Aug 2020 23:27:08 +0800 Subject: [PATCH 0801/1150] Add 5G NSA to collapsed RAT types list Currently, getAllCollapsedRatTypes is used to retrieve all RAT types which will be recorded into NetworkStatsService. However, there is a missing part that 5G NSA virtual RAT type is not added into this list. This makes callers such as statsd do not aware of 5G NSA RAT type and missed to collect data usage of it. Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Test: adb shell cmd stats pull-source 10082 Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Test: atest UidAtomTests#testMobileBytesTransfer \ UidAtomTests#testMobileBytesTransferByFgBg \ UidAtomTests#testDataUsageBytesTransfer Bug: 163021464 Change-Id: I0faeda20f0506a48ac1131b234c5fc40d95dfbe0 --- core/java/android/net/NetworkTemplate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 7234eb1d81..cd26079a7b 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -503,6 +503,10 @@ public class NetworkTemplate implements Parcelable { for (final int ratType : ratTypes) { collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); } + // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and + // it is not in TelephonyManager#NETWORK_TYPE_* constants. + // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); From fda084bdc96ef0ccd89adcc941644ad17e9d9d91 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 7 Aug 2020 23:27:08 +0800 Subject: [PATCH 0802/1150] Add 5G NSA to collapsed RAT types list Currently, getAllCollapsedRatTypes is used to retrieve all RAT types which will be recorded into NetworkStatsService. However, there is a missing part that 5G NSA virtual RAT type is not added into this list. This makes callers such as statsd do not aware of 5G NSA RAT type and missed to collect data usage of it. Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Test: adb shell cmd stats pull-source 10082 Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Test: atest UidAtomTests#testMobileBytesTransfer \ UidAtomTests#testMobileBytesTransferByFgBg \ UidAtomTests#testDataUsageBytesTransfer Bug: 163021464 Change-Id: I0faeda20f0506a48ac1131b234c5fc40d95dfbe0 Merged-In: I0faeda20f0506a48ac1131b234c5fc40d95dfbe0 --- core/java/android/net/NetworkTemplate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 7234eb1d81..cd26079a7b 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -503,6 +503,10 @@ public class NetworkTemplate implements Parcelable { for (final int ratType : ratTypes) { collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); } + // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and + // it is not in TelephonyManager#NETWORK_TYPE_* constants. + // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); From 064b6915aa2b44ada2e3986674a1e3c5aaed9955 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 11 Feb 2020 14:59:38 +0800 Subject: [PATCH 0803/1150] Add getAllCollapsedRatTypes to NetworkTemplate This is a partial cherry-pick of ag/10293594 Test: TH Bug: 129082217 Merged-In: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 Change-Id: I726e74f5c63a6ed456cb13ea259b58c7a33bec76 --- core/java/android/net/NetworkTemplate.java | 29 ++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 4b806e714f..7234eb1d81 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -34,6 +34,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; import android.os.Parcel; @@ -52,6 +53,8 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -489,6 +492,32 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Return all supported collapsed RAT types that could be returned by + * {@link #getCollapsedRatType(int)}. + */ + @NonNull + public static final int[] getAllCollapsedRatTypes() { + final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); + final HashSet collapsedRatTypes = new HashSet<>(); + for (final int ratType : ratTypes) { + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); + } + // Ensure that unknown type is returned. + collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); + return toIntArray(collapsedRatTypes); + } + + @NonNull + private static int[] toIntArray(@NonNull Collection list) { + final int[] array = new int[list.size()]; + int i = 0; + for (final Integer item : list) { + array[i++] = item; + } + return array; + } + /** * Check if matches Wi-Fi network template. */ From 084485bcb94fdd12d9ec23e75e652a9ba60ea3ae Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 7 Aug 2020 23:27:08 +0800 Subject: [PATCH 0804/1150] Add 5G NSA to collapsed RAT types list Currently, getAllCollapsedRatTypes is used to retrieve all RAT types which will be recorded into NetworkStatsService. However, there is a missing part that 5G NSA virtual RAT type is not added into this list. This makes callers such as statsd do not aware of 5G NSA RAT type and missed to collect data usage of it. Test: atest NetworkStatsSubscriptionsMonitorTest#test5g Test: adb shell cmd stats pull-source 10082 Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Test: atest UidAtomTests#testMobileBytesTransfer \ UidAtomTests#testMobileBytesTransferByFgBg \ UidAtomTests#testDataUsageBytesTransfer Bug: 163021464 Change-Id: I0faeda20f0506a48ac1131b234c5fc40d95dfbe0 Merged-In: I0faeda20f0506a48ac1131b234c5fc40d95dfbe0 (cherry-picked from ag/12355984) --- core/java/android/net/NetworkTemplate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 7234eb1d81..cd26079a7b 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -503,6 +503,10 @@ public class NetworkTemplate implements Parcelable { for (final int ratType : ratTypes) { collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); } + // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and + // it is not in TelephonyManager#NETWORK_TYPE_* constants. + // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); From 58e431877134f33a7e967730c016f1f6663c17ef Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 11 Aug 2020 08:43:33 -0700 Subject: [PATCH 0805/1150] WifiP2pManager: Plumb package name to service Will be used for prioritization of different ifaces in HDM. Bug: 162344695 Test: atest com.android.server.wifi Change-Id: Iac1447390f7329768b9c307b08d28ebbd4ea3b90 --- wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl index bfdd45d9f9..fd89d3b048 100644 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface IWifiP2pManager { - Messenger getMessenger(in IBinder binder); + Messenger getMessenger(in IBinder binder, in String packageName); Messenger getP2pStateMachineMessenger(); oneway void close(in IBinder binder); void setMiracastMode(int mode); From 0e7e72fea63efe729ea584ac9ed0391ea35f1667 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 18 Aug 2020 18:50:13 +0800 Subject: [PATCH 0806/1150] Skip RAT type listener registration if IMSI is not available Currently, if SIM is inserted but IMSI is not available, such as SIM PIN locked state. Information of such SIM will still be available but IMSI is not. Which makes NetworkStatsSubscriptionMonitor failed to store IMSI locally for later RAT type query. Hence, NETWORK_TYPE_UNKNOWN is always returned for such SIM. Skip the registration until the IMSI is available. This is safe since there will be another onSubscriptionsChanged event when that happens. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Change-Id: I408379b3c432d9e62e0837d6b4f6551cc7838e29 --- .../net/NetworkStatsSubscriptionsMonitor.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 0575ac6315..d202a2a607 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -100,11 +100,16 @@ public class NetworkStatsSubscriptionsMonitor extends if (match != null) continue; // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. + // prevent binder call to telephony when querying RAT. If the subscriberId is empty + // for any reason, such as SIM PIN locked, skip registration. + // SubscriberId will be unavailable again if 1. modem crashed 2. reboot + // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized + // with active sub list once all subscriberIds are ready. final String subscriberId = mTeleManager.getSubscriberId(subId); if (TextUtils.isEmpty(subscriberId)) { - Log.wtf(NetworkStatsService.TAG, - "Empty subscriberId for newly added sub: " + subId); + Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " + + subId + ", skip listener registration"); + continue; } final RatTypeListener listener = new RatTypeListener(mExecutor, this, subId, subscriberId); @@ -113,6 +118,7 @@ public class NetworkStatsSubscriptionsMonitor extends // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(subId) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { @@ -165,6 +171,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) .listen(listener, PhoneStateListener.LISTEN_NONE); + Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); // Removal of subscriptions doesn't generate RAT changed event, fire it for every From 11dfa11c890041f93b7e6bd0e2264cd8c61d66bf Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 18 Aug 2020 18:50:13 +0800 Subject: [PATCH 0807/1150] Skip RAT type listener registration if IMSI is not available Currently, if SIM is inserted but IMSI is not available, such as SIM PIN locked state. Information of such SIM will still be available but IMSI is not. Which makes NetworkStatsSubscriptionMonitor failed to store IMSI locally for later RAT type query. Hence, NETWORK_TYPE_UNKNOWN is always returned for such SIM. Skip the registration until the IMSI is available. This is safe since there will be another onSubscriptionsChanged event when that happens. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Merged-In: I408379b3c432d9e62e0837d6b4f6551cc7838e29 Change-Id: I408379b3c432d9e62e0837d6b4f6551cc7838e29 (cherry-picked from ag/12400327) --- .../net/NetworkStatsSubscriptionsMonitor.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index cb1c7e4fd0..1c79332e98 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -99,11 +99,16 @@ public class NetworkStatsSubscriptionsMonitor extends if (match != null) continue; // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. + // prevent binder call to telephony when querying RAT. If the subscriberId is empty + // for any reason, such as SIM PIN locked, skip registration. + // SubscriberId will be unavailable again if 1. modem crashed 2. reboot + // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized + // with active sub list once all subscriberIds are ready. final String subscriberId = mTeleManager.getSubscriberId(subId); if (TextUtils.isEmpty(subscriberId)) { - Log.wtf(NetworkStatsService.TAG, - "Empty subscriberId for newly added sub: " + subId); + Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " + + subId + ", skip listener registration"); + continue; } final RatTypeListener listener = new RatTypeListener(mExecutor, this, subId, subscriberId); @@ -112,6 +117,7 @@ public class NetworkStatsSubscriptionsMonitor extends // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(subId) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { @@ -164,6 +170,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) .listen(listener, PhoneStateListener.LISTEN_NONE); + Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); // Removal of subscriptions doesn't generate RAT changed event, fire it for every From a13af8b80d9e8ba43e5c0688566b3f763befad4d Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 18 Aug 2020 18:50:13 +0800 Subject: [PATCH 0808/1150] Skip RAT type listener registration if IMSI is not available Currently, if SIM is inserted but IMSI is not available, such as SIM PIN locked state. Information of such SIM will still be available but IMSI is not. Which makes NetworkStatsSubscriptionMonitor failed to store IMSI locally for later RAT type query. Hence, NETWORK_TYPE_UNKNOWN is always returned for such SIM. Skip the registration until the IMSI is available. This is safe since there will be another onSubscriptionsChanged event when that happens. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Merged-In: I408379b3c432d9e62e0837d6b4f6551cc7838e29 Change-Id: I408379b3c432d9e62e0837d6b4f6551cc7838e29 (cherry-picked from ag/12400327) --- .../net/NetworkStatsSubscriptionsMonitor.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 0575ac6315..d202a2a607 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -100,11 +100,16 @@ public class NetworkStatsSubscriptionsMonitor extends if (match != null) continue; // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. + // prevent binder call to telephony when querying RAT. If the subscriberId is empty + // for any reason, such as SIM PIN locked, skip registration. + // SubscriberId will be unavailable again if 1. modem crashed 2. reboot + // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized + // with active sub list once all subscriberIds are ready. final String subscriberId = mTeleManager.getSubscriberId(subId); if (TextUtils.isEmpty(subscriberId)) { - Log.wtf(NetworkStatsService.TAG, - "Empty subscriberId for newly added sub: " + subId); + Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " + + subId + ", skip listener registration"); + continue; } final RatTypeListener listener = new RatTypeListener(mExecutor, this, subId, subscriberId); @@ -113,6 +118,7 @@ public class NetworkStatsSubscriptionsMonitor extends // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(subId) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { @@ -165,6 +171,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) .listen(listener, PhoneStateListener.LISTEN_NONE); + Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); // Removal of subscriptions doesn't generate RAT changed event, fire it for every From 11385d9d0c3d7cf6038544fd16f6013497d58052 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Aug 2020 16:07:22 +0900 Subject: [PATCH 0809/1150] Move module utils to the module package. Test: builds Change-Id: If5d1e4a58fb2d6d9544e6d01995dabe445cf1f25 (cherry picked from commit 046bf639eb7728504be35e30e3dd49af3d029728) --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 4a1820a8e5..d907505481 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; -import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; From e33b576596a8fff01cb03f99318942fb2ff3a0ed Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Thu, 1 Oct 2020 20:12:46 +0000 Subject: [PATCH 0810/1150] Revert "Move module utils to the module package." Revert "Move util classes to their destination package" Revert "Move PacketReader and FdEventReader" Revert "Move static utils to a module package" Revert "Move static utils to a module package" Revert submission 12698912-move_packetreader Reason for revert: Broke presubmit on git_master, b/169861635 Reverted Changes: If5d1e4a58:Move module utils to the module package. I44ffaad3d:Move PacketReader and FdEventReader I93e9cfd96:Move util classes to their destination package Ia84d64130:Move static utils to a module package Iaac2810c7:Move static utils to a module package Change-Id: Ibbe59075cd7bc4c38e0707ea6ae3b3703b40986f --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index d907505481..4a1820a8e5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -25,6 +25,7 @@ import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; +import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -41,7 +42,6 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; -import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; From 1d34ee5cf79a1480f6fd1af9427c1554a2895203 Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Fri, 25 Sep 2020 11:35:45 +0100 Subject: [PATCH 0811/1150] Refactoring: Use explicit methods for checking DO/PO Do not use USES_POLICY_PROFILE_OWNER / USES_POLICY_DEVICE_OWNER. Instead, use explicit methods for checking if the caller is the Device Owner or Profile Owner. USES_POLICY_PROFILE_OWNER is confusing since internally in the DevicePolicyManagerService, it implied a Device Owner is also a Profile Owner, which is not always what the caller expected. This is the first phase of the refactoring, removing external calles' dependency on these constants. The next phase will remove them internally completely in favour of an implementation that accesses mOwners directly. There are no functional changes in this CL. Bug: 163028934 Test: atest FrameworksServicesTests:DevicePolicyManagerTest Change-Id: I57c8465d190a3b4b130d57fd622cc93eaeb9c717 --- .../java/com/android/server/net/NetworkStatsAccess.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 7c1c1c7ce4..5a8fbf3d26 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -24,7 +24,6 @@ import static android.net.TrafficStats.UID_TETHERING; import android.Manifest; import android.annotation.IntDef; import android.app.AppOpsManager; -import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; @@ -111,8 +110,7 @@ public final class NetworkStatsAccess { boolean hasCarrierPrivileges = tm != null && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; - boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); if (hasCarrierPrivileges || isDeviceOwner || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { // Carrier-privileged apps and device owners, and the system can access data usage for @@ -126,8 +124,9 @@ public final class NetworkStatsAccess { return NetworkStatsAccess.Level.DEVICESUMMARY; } - boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. + boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid) + || dpmi.isActiveDeviceOwner(callingUid)); if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile. From 63fd0c40f091243e78d6ad794190f81a8f8caf56 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 20 Aug 2020 18:23:57 +0800 Subject: [PATCH 0812/1150] Support dynamically update IMSI Currently, NetworkStatsSubscriptionsMonitor will skip the listener registration until the IMSI is available to deal with SIM PIN locked case. However, this solution can only handle the case that IMSI changes from/to null. And it also relies on the assumption that IMSI never changes for a subId. Thus, support dynamically update IMSI to handle IMSI changes more robustly. This patch also address leftover comments at ag/12400327. Test: enable SIM PIN and manually test Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdUnavailable Test: atest NetworkStatsSubscriptionsMonitorTest#testSubscriberIdChanged Test: ./out/host/linux-x86/bin/statsd_testdrive 10082 Bug: 160941101 Change-Id: I625a5b10ee4806f6fee99c2d9d6c5e7977ff785e --- .../net/NetworkStatsSubscriptionsMonitor.java | 51 +++++++++++-------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index d202a2a607..5646c752fc 100644 --- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; +import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; @@ -94,39 +95,41 @@ public class NetworkStatsSubscriptionsMonitor extends // also needed to track CBRS. final List newSubs = getActiveSubIdList(mSubscriptionManager); - for (final int subId : newSubs) { - final RatTypeListener match = CollectionUtils.find(mRatListeners, - it -> it.mSubId == subId); - if (match != null) continue; + // IMSI is needed for every newly added sub. Listener stores subscriberId into it to + // prevent binder call to telephony when querying RAT. Keep listener registration with empty + // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported + // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. + final List> filteredNewSubs = + CollectionUtils.mapNotNull(newSubs, subId -> { + final String subscriberId = mTeleManager.getSubscriberId(subId); + return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId); + }); - // Create listener for every newly added sub. Also store subscriberId into it to - // prevent binder call to telephony when querying RAT. If the subscriberId is empty - // for any reason, such as SIM PIN locked, skip registration. - // SubscriberId will be unavailable again if 1. modem crashed 2. reboot - // 3. re-insert SIM. If that happens, the listeners will be eventually synchronized - // with active sub list once all subscriberIds are ready. - final String subscriberId = mTeleManager.getSubscriberId(subId); - if (TextUtils.isEmpty(subscriberId)) { - Log.d(NetworkStatsService.TAG, "Empty subscriberId for newly added sub " - + subId + ", skip listener registration"); + for (final Pair sub : filteredNewSubs) { + // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be + // suddenly change regardless of subId, such as switch IMSI feature in modem side. + // If that happens, register new listener with new IMSI and remove old one later. + if (CollectionUtils.find(mRatListeners, + it -> it.equalsKey(sub.first, sub.second)) != null) { continue; } + final RatTypeListener listener = - new RatTypeListener(mExecutor, this, subId, subscriberId); + new RatTypeListener(mExecutor, this, sub.first, sub.second); mRatListeners.add(listener); // Register listener to the telephony manager that associated with specific sub. - mTeleManager.createForSubscriptionId(subId) + mTeleManager.createForSubscriptionId(sub.first) .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); - Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + subId); + Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); } for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { - // If the new list contains the subId of the listener, keeps it. - final Integer match = CollectionUtils.find(newSubs, it -> it == listener.mSubId); - if (match != null) continue; - - handleRemoveRatTypeListener(listener); + // If there is no subId and IMSI matched the listener, removes it. + if (CollectionUtils.find(filteredNewSubs, + it -> listener.equalsKey(it.first, it.second)) == null) { + handleRemoveRatTypeListener(listener); + } } } @@ -232,5 +235,9 @@ public class NetworkStatsSubscriptionsMonitor extends public int getSubId() { return mSubId; } + + boolean equalsKey(int subId, @NonNull String subscriberId) { + return mSubId == subId && TextUtils.equals(mSubscriberId, subscriberId); + } } } From 9f6d73c3ccc28aee84e1e9afbdfac8273a3e72a9 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 7 Oct 2020 18:29:20 +0900 Subject: [PATCH 0813/1150] Allow the network stack to read network stats history Bug: 168984229 Test: testNetworkStatsProvider Change-Id: Ibb6342b0f263c874bb1f7ab4031a639778bad37e --- .../com/android/server/net/NetworkStatsAccess.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 5a8fbf3d26..7cdc4cc747 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -27,6 +27,7 @@ import android.app.AppOpsManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -110,11 +111,12 @@ public final class NetworkStatsAccess { boolean hasCarrierPrivileges = tm != null && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; - boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); + final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); + final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner - || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { - // Carrier-privileged apps and device owners, and the system can access data usage for - // all apps on the device. + || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { + // Carrier-privileged apps and device owners, and the system (including the + // network stack) can access data usage for all apps on the device. return NetworkStatsAccess.Level.DEVICE; } From 516366088d331f66256457c6181f14f4ac7b1f10 Mon Sep 17 00:00:00 2001 From: Roman Kalukiewicz Date: Wed, 14 Oct 2020 15:59:06 -0700 Subject: [PATCH 0814/1150] Add @Nullable annotation to the parameter of Object.equals() methods. Those annotations could be inferred by some tools (like Kotlin), but the https://checkerframework.org/ doesn't check inherited annotations complaining about all equals() invocations that get nullable argument. The change was generated by running find . -name \*.java | xargs sed -i 's/public boolean equals(Object /public boolean equals(@Nullable Object /' in the frameworks/base directory and by automatically adding and formatting required imports if needed. No manual edits. Bug: 170883422 Test: Annotation change only. Should have not impact. Exempt-From-Owner-Approval: Mechanical change not specific to any component. Change-Id: I5eedb571c9d78862115dfdc5dae1cf2a35343580 --- core/java/android/net/DataUsageRequest.java | 3 ++- core/java/android/net/IpSecTransform.java | 3 ++- core/java/android/net/NetworkIdentity.java | 3 ++- core/java/android/net/NetworkStats.java | 2 +- core/java/android/net/NetworkTemplate.java | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index 0ac8f7e794..b06d515b3a 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.Nullable; import android.net.NetworkTemplate; import android.os.Parcel; import android.os.Parcelable; @@ -95,7 +96,7 @@ public final class DataUsageRequest implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof DataUsageRequest == false) return false; DataUsageRequest that = (DataUsageRequest) obj; return that.requestId == this.requestId diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 44a0a4f3e1..fa1497dcbc 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -21,6 +21,7 @@ import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; @@ -153,7 +154,7 @@ public final class IpSecTransform implements AutoCloseable { /** * Standard equals. */ - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (this == other) return true; if (!(other instanceof IpSecTransform)) return false; final IpSecTransform rhs = (IpSecTransform) other; diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 0948a4da1a..9c1038846d 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeMobile; +import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -69,7 +70,7 @@ public class NetworkIdentity implements Comparable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 34e48eb44f..cbee010246 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -411,7 +411,7 @@ public final class NetworkStats implements Parcelable { /** @hide */ @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cd26079a7b..a95ba12f65 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -327,7 +327,7 @@ public class NetworkTemplate implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof NetworkTemplate) { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule From 5c02efcf5b1812201a5079dc2f0daf8ab1655e06 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 5 Aug 2020 12:16:20 -0700 Subject: [PATCH 0815/1150] Add new mandatory IPsec algorithms This CL adds new mandatory IPsec algorithms and allows OEM to enable them on old devices using resource overlay Bug: 161716062 Test: FrameworksNetTests:IpSecAlgorithmTest Change-Id: Ib827b05ea27dbe61b14ad236e858f825293ed994 --- core/java/android/net/IpSecAlgorithm.java | 188 +++++++++++++++++++++- 1 file changed, 181 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 38d9883f00..61b2a59f52 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; import android.annotation.StringDef; +import android.content.res.Resources; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -27,6 +28,12 @@ import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; /** * This class represents a single algorithm that can be used by an {@link IpSecTransform}. @@ -51,6 +58,29 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String CRYPT_AES_CBC = "cbc(aes)"; + /** + * AES-CTR Encryption/Ciphering Algorithm. + * + *

            Valid lengths for keying material are {160, 224, 288}. + * + *

            As per RFC3686 (Section + * 5.1), keying material consists of a 128, 192, or 256 bit AES key followed by a 32-bit + * nonce. RFC compliance requires that the nonce must be unique per security association. + * + *

            This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + *

            @see {@link #getSupportedAlgorithms()} + * + * @hide + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String CRYPT_AES_CTR = "rfc3686(ctr(aes))"; + /** * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in * new applications and is provided for legacy compatibility with 3gpp infrastructure. @@ -98,6 +128,27 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String AUTH_HMAC_SHA512 = "hmac(sha512)"; + /** + * AES-XCBC Authentication/Integrity Algorithm. + * + *

            Keys for this algorithm must be 128 bits in length. + * + *

            The only valid truncation length is 96 bits. + * + *

            This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + *

            @see {@link #getSupportedAlgorithms()} + * + * @hide + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_AES_XCBC = "xcbc(aes)"; + /** * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. * @@ -111,19 +162,69 @@ public final class IpSecAlgorithm implements Parcelable { */ public static final String AUTH_CRYPT_AES_GCM = "rfc4106(gcm(aes))"; + /** + * ChaCha20-Poly1305 Authentication/Integrity + Encryption/Ciphering Algorithm. + * + *

            Keys for this algorithm must be 288 bits in length. + * + *

            As per RFC7634 (Section 2), + * keying material consists of a 256 bit key followed by a 32-bit salt. The salt is fixed per + * security association. + * + *

            The only valid ICV (truncation) length is 128 bits. + * + *

            This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + *

            @see {@link #getSupportedAlgorithms()} + * + * @hide + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_CRYPT_CHACHA20_POLY1305 = "rfc7539esp(chacha20,poly1305)"; + /** @hide */ @StringDef({ CRYPT_AES_CBC, + CRYPT_AES_CTR, AUTH_HMAC_MD5, AUTH_HMAC_SHA1, AUTH_HMAC_SHA256, AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, - AUTH_CRYPT_AES_GCM + AUTH_AES_XCBC, + AUTH_CRYPT_AES_GCM, + AUTH_CRYPT_CHACHA20_POLY1305 }) @Retention(RetentionPolicy.SOURCE) public @interface AlgorithmName {} + /** @hide */ + @VisibleForTesting + public static final Map ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>(); + + static { + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, Build.VERSION_CODES.P); + + // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + } + + private static final Set ENABLED_ALGOS = + Collections.unmodifiableSet(loadAlgos(Resources.getSystem())); + private final String mName; private final byte[] mKey; private final int mTruncLenBits; @@ -137,6 +238,7 @@ public final class IpSecAlgorithm implements Parcelable { * * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. + * @throws IllegalArgumentException if algorithm or key length is invalid. */ public IpSecAlgorithm(@NonNull @AlgorithmName String algorithm, @NonNull byte[] key) { this(algorithm, key, 0); @@ -152,6 +254,7 @@ public final class IpSecAlgorithm implements Parcelable { * @param algorithm name of the algorithm. * @param key key padded to a multiple of 8 bits. * @param truncLenBits number of bits of output hash to use. + * @throws IllegalArgumentException if algorithm, key length or truncation length is invalid. */ public IpSecAlgorithm( @NonNull @AlgorithmName String algorithm, @NonNull byte[] key, int truncLenBits) { @@ -206,13 +309,61 @@ public final class IpSecAlgorithm implements Parcelable { } }; - private static void checkValidOrThrow(String name, int keyLen, int truncLen) { - boolean isValidLen = true; - boolean isValidTruncLen = true; + /** + * Returns supported IPsec algorithms for the current device. + * + *

            Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is + * supported before using it. + * + * @hide + */ + @NonNull + public static Set getSupportedAlgorithms() { + return ENABLED_ALGOS; + } - switch(name) { + /** @hide */ + @VisibleForTesting + public static Set loadAlgos(Resources systemResources) { + final Set enabledAlgos = new HashSet<>(); + + // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in + // the resource are not allowed. + final String[] resourceAlgos = systemResources.getStringArray( + com.android.internal.R.array.config_optionalIpSecAlgorithms); + for (String str : resourceAlgos) { + if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { + // This error should be caught by CTS and never be thrown to API callers + throw new IllegalArgumentException("Invalid or repeated algorithm " + str); + } + } + + for (Entry entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { + if (Build.VERSION.FIRST_SDK_INT >= entry.getValue()) { + enabledAlgos.add(entry.getKey()); + } + } + + return enabledAlgos; + } + + private static void checkValidOrThrow(String name, int keyLen, int truncLen) { + final boolean isValidLen; + final boolean isValidTruncLen; + + if (!getSupportedAlgorithms().contains(name)) { + throw new IllegalArgumentException("Unsupported algorithm: " + name); + } + + switch (name) { case CRYPT_AES_CBC: isValidLen = keyLen == 128 || keyLen == 192 || keyLen == 256; + isValidTruncLen = true; + break; + case CRYPT_AES_CTR: + // The keying material for AES-CTR is a key plus a 32-bit salt + isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; + isValidTruncLen = true; break; case AUTH_HMAC_MD5: isValidLen = keyLen == 128; @@ -234,12 +385,22 @@ public final class IpSecAlgorithm implements Parcelable { isValidLen = keyLen == 512; isValidTruncLen = truncLen >= 256 && truncLen <= 512; break; + case AUTH_AES_XCBC: + isValidLen = keyLen == 128; + isValidTruncLen = truncLen == 96; + break; case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; isValidTruncLen = truncLen == 64 || truncLen == 96 || truncLen == 128; break; + case AUTH_CRYPT_CHACHA20_POLY1305: + // The keying material for ChaCha20Poly1305 is a key plus a 32-bit salt + isValidLen = keyLen == 256 + 32; + isValidTruncLen = truncLen == 128; + break; default: + // Should never hit here. throw new IllegalArgumentException("Couldn't find an algorithm: " + name); } @@ -260,6 +421,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_HMAC_SHA256: case AUTH_HMAC_SHA384: case AUTH_HMAC_SHA512: + case AUTH_AES_XCBC: return true; default: return false; @@ -268,12 +430,24 @@ public final class IpSecAlgorithm implements Parcelable { /** @hide */ public boolean isEncryption() { - return getName().equals(CRYPT_AES_CBC); + switch (getName()) { + case CRYPT_AES_CBC: // fallthrough + case CRYPT_AES_CTR: + return true; + default: + return false; + } } /** @hide */ public boolean isAead() { - return getName().equals(AUTH_CRYPT_AES_GCM); + switch (getName()) { + case AUTH_CRYPT_AES_GCM: // fallthrough + case AUTH_CRYPT_CHACHA20_POLY1305: + return true; + default: + return false; + } } // Because encryption keys are sensitive and userdebug builds are used by large user pools From a0515bec7677f5752f24ec9ecde93f88b92f741c Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 7 Oct 2020 18:29:20 +0900 Subject: [PATCH 0816/1150] Allow the network stack to read network stats history Identical to ag/12843161 Bug: 168984229 Test: testNetworkStatsProvider Change-Id: I7ad72c3b2b95f26ceec1371e7e0fdb92fa88920c Merged-In: Ibb6342b0f263c874bb1f7ab4031a639778bad37e --- .../java/com/android/server/net/NetworkStatsAccess.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 7c1c1c7ce4..72559b4825 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -28,6 +28,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -113,10 +114,11 @@ public final class NetworkStatsAccess { TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner - || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { - // Carrier-privileged apps and device owners, and the system can access data usage for - // all apps on the device. + || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { + // Carrier-privileged apps and device owners, and the system (including the + // network stack) can access data usage for all apps on the device. return NetworkStatsAccess.Level.DEVICE; } From ba07cf027d2ae25b78d0549130bd8dde01958002 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 12 Aug 2020 13:48:39 -0700 Subject: [PATCH 0817/1150] Expose new algorithms as public API Bug: 161716062 Test: FrameworksNetTests:IpSecAlgorithmTest Change-Id: I5041c61ad5a4aa58b259e24de80a2c63d6b19dae --- core/java/android/net/IpSecAlgorithm.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 61b2a59f52..a4f7b7454b 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -74,8 +74,6 @@ public final class IpSecAlgorithm implements Parcelable { * requested on an unsupported device. * *

            @see {@link #getSupportedAlgorithms()} - * - * @hide */ // This algorithm may be available on devices released before Android 12, and is guaranteed // to be available on devices first shipped with Android 12 or later. @@ -142,8 +140,6 @@ public final class IpSecAlgorithm implements Parcelable { * requested on an unsupported device. * *

            @see {@link #getSupportedAlgorithms()} - * - * @hide */ // This algorithm may be available on devices released before Android 12, and is guaranteed // to be available on devices first shipped with Android 12 or later. @@ -180,8 +176,6 @@ public final class IpSecAlgorithm implements Parcelable { * requested on an unsupported device. * *

            @see {@link #getSupportedAlgorithms()} - * - * @hide */ // This algorithm may be available on devices released before Android 12, and is guaranteed // to be available on devices first shipped with Android 12 or later. @@ -314,8 +308,6 @@ public final class IpSecAlgorithm implements Parcelable { * *

            Some algorithms may not be supported on old devices. Callers MUST check if an algorithm is * supported before using it. - * - * @hide */ @NonNull public static Set getSupportedAlgorithms() { From dce1bf9353b47ea427298fd7f79ac5691f5d074b Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Mon, 19 Oct 2020 16:15:58 +0100 Subject: [PATCH 0818/1150] Remove @TestApi from @SystemApi symbols I ran these commands: cd frameworks/base grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@SystemApi[\s\n]+(\@\w+[\s\n]+)?\@TestApi/\@SystemApi\1/gs' grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@TestApi[\s\n]+(\@\w+[\s\n]+)?\@SystemApi/\1\@SystemApi/gs' Bug: 171179806 Test: m checkapi Change-Id: I772790b783b0a8730b8bf680c9e569a886b8d789 Merged-In: I772790b783b0a8730b8bf680c9e569a886b8d789 --- core/java/android/net/EthernetManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index d975017f9c..5860e20ad3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -37,7 +37,6 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi -@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; From 95a69f8f1b15bc625bbefc895e17e450d9ce767a Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Mon, 19 Oct 2020 18:57:17 +0100 Subject: [PATCH 0819/1150] Remove @TestApi from @SystemApi symbols I ran these commands: cd frameworks/base grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@SystemApi[\s\n]+(\@\w+[\s\n]+)?\@TestApi/\@SystemApi\1/gs' grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@TestApi[\s\n]+(\@\w+[\s\n]+)?\@SystemApi/\1\@SystemApi/gs' Bug: 171179806 Test: m checkapi Change-Id: I772790b783b0a8730b8bf680c9e569a886b8d789 Merged-In: I772790b783b0a8730b8bf680c9e569a886b8d789 --- core/java/android/net/EthernetManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index d975017f9c..5860e20ad3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -37,7 +37,6 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi -@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; From 731713c821d183958bb9b50f1dc988074c19e7c3 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Mon, 19 Oct 2020 11:38:00 +0100 Subject: [PATCH 0820/1150] Remove @TestApi from @SystemApi symbols I ran these commands: cd frameworks/base grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@SystemApi[\s\n]+(\@\w+[\s\n]+)?\@TestApi/\@SystemApi\1/gs' grep -rl '@TestApi' --include '*.java' | xargs perl -i -p0e \ 's/\@TestApi[\s\n]+(\@\w+[\s\n]+)?\@SystemApi/\1\@SystemApi/gs' Bug: 171179806 Test: m checkapi Change-Id: I772790b783b0a8730b8bf680c9e569a886b8d789 --- core/java/android/net/EthernetManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index d975017f9c..5860e20ad3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -37,7 +37,6 @@ import java.util.concurrent.Executor; * @hide */ @SystemApi -@TestApi @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; From 3b8f510f9ea00e2e8ccaec2038e1f786bf259804 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 20 Oct 2020 14:49:20 -0700 Subject: [PATCH 0821/1150] Require devices with first sdk 0 or later to support mandatory algorithms It is safe because these mandatory algorithms are already required before new algorithms are added It is also a quick fix to unblock b/171279612, whose root cause is the device first sdk is wrong Bug: 171279612 Test: atest CtsNetTestCases:IpSecManagerTest Change-Id: I5b9d85b2bc8f13f54467c97160d138a4628265f7 --- core/java/android/net/IpSecAlgorithm.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index a4f7b7454b..e89451e4f4 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -201,14 +201,16 @@ public final class IpSecAlgorithm implements Parcelable { @VisibleForTesting public static final Map ALGO_TO_REQUIRED_FIRST_SDK = new HashMap<>(); + private static final int SDK_VERSION_ZERO = 0; + static { - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, Build.VERSION_CODES.P); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, Build.VERSION_CODES.P); + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CBC, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_MD5, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA1, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA256, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA384, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); From 91ea75cd46e912ed75ed0aec243ce449e5fe5d82 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 17 Oct 2020 21:20:13 -0600 Subject: [PATCH 0822/1150] Apply fixes for EfficientStrings. Refactoring to avoid StringBuffer synchronization overhead. Bug: 170978902 Test: none Exempt-From-Owner-Approval: trivial refactoring Change-Id: Ibf843ed780c1202d5d96a11eaca889e592f19263 --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 4a1820a8e5..78bd4cdd4e 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -824,7 +824,7 @@ public class NsdService extends INsdManager.Stub { @Override public String toString() { - StringBuffer sb = new StringBuffer(); + StringBuilder sb = new StringBuilder(); sb.append("mChannel ").append(mChannel).append("\n"); sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); From 18929e62ca16d9227212218d7f098d96af204841 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 27 Oct 2020 11:47:29 +0000 Subject: [PATCH 0823/1150] Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. Bug: 170729553 Test: Treehugger Change-Id: I4c8fd0006f950de9955242e93968fb0996ceb372 --- .../app/usage/NetworkStatsManager.java | 5 +-- core/java/android/net/EthernetManager.java | 17 +++++----- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 33 ++++++++++--------- .../java/android/net/NetworkStatsHistory.java | 17 +++++----- core/java/android/net/NetworkTemplate.java | 3 +- core/java/android/net/TrafficStats.java | 4 +-- core/java/android/net/nsd/INsdManager.aidl | 2 +- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fc8248e101..1ddfe0d247 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,6 +34,7 @@ import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -129,7 +130,7 @@ public class NetworkStatsManager { /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); @@ -153,7 +154,7 @@ public class NetworkStatsManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 5860e20ad3..84a8e1c3dc 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -76,7 +77,7 @@ public class EthernetManager { * @param isAvailable {@code true} if Ethernet port exists. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -97,7 +98,7 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -110,7 +111,7 @@ public class EthernetManager { * Set Ethernet configuration. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -123,7 +124,7 @@ public class EthernetManager { * Indicates whether the system currently has one or more Ethernet interfaces. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -134,7 +135,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -149,7 +150,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -168,7 +169,7 @@ public class EthernetManager { * Returns an array of available Ethernet interface names. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -183,7 +184,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 5fa515a143..1a3dc97448 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,7 +42,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index cbee010246..d42beae601 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -219,11 +220,11 @@ public final class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int size; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int capacity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String[] iface; @UnsupportedAppUsage private int[] uid; @@ -231,21 +232,21 @@ public final class NetworkStats implements Parcelable { private int[] set; @UnsupportedAppUsage private int[] tag; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] metered; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] roaming; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] defaultNetwork; @UnsupportedAppUsage private long[] rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] rxPackets; @UnsupportedAppUsage private long[] txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] txPackets; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] operations; /** @@ -258,7 +259,7 @@ public final class NetworkStats implements Parcelable { @SystemApi public static class Entry { /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String iface; /** @hide */ @UnsupportedAppUsage @@ -267,7 +268,7 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public int set; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -294,20 +295,20 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public long rxBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; /** @hide */ @UnsupportedAppUsage public long txBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long operations; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -454,7 +455,7 @@ public final class NetworkStats implements Parcelable { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 51f09a0103..fba7561434 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -32,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -91,18 +92,18 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketDuration; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketStart; public long activeTime; @UnsupportedAppUsage public long rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; @UnsupportedAppUsage public long txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; public long operations; } @@ -134,7 +135,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -220,7 +221,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int size() { return bucketCount; } @@ -258,7 +259,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -286,7 +287,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index a95ba12f65..dc33cc7b61 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -159,7 +160,7 @@ public class NetworkTemplate implements Parcelable { * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7bba69dbb..a985e934ed 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -565,7 +565,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -581,7 +581,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 9484c74bcb..e9e8935a19 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface INsdManager { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) Messenger getMessenger(); void setEnabled(boolean enable); } From afa0209617d36e058f2f5522f13b759472834f2e Mon Sep 17 00:00:00 2001 From: Hongwei Wang Date: Wed, 28 Oct 2020 19:38:11 +0000 Subject: [PATCH 0824/1150] Revert "Add maxTargetSdk restriction to unused APIs." This reverts commit 18929e62ca16d9227212218d7f098d96af204841. Reason for revert: Droidcop-triggered revert due to breakage https://android-build.googleplex.com/builds/quarterdeck?testMethod=testAppZygotePreload&testClass=android.app.cts.ServiceTest&atpConfigName=suite%2Ftest-mapping-presubmit-retry_cloud-tf&testModule=CtsAppTestCases&fkbb=6936597&lkbb=6936969&lkgb=6936551&testResults=true&branch=git_master&target=cf_x86_phone-userdebug>, bug b/171886397 Bug: 171886397 Change-Id: Ibe0f0430a3451477c1ee8ef56a596e91ea1e7672 --- .../app/usage/NetworkStatsManager.java | 5 ++- core/java/android/net/EthernetManager.java | 17 +++++----- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 33 +++++++++---------- .../java/android/net/NetworkStatsHistory.java | 17 +++++----- core/java/android/net/NetworkTemplate.java | 3 +- core/java/android/net/TrafficStats.java | 4 +-- core/java/android/net/nsd/INsdManager.aidl | 2 +- 8 files changed, 39 insertions(+), 44 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1ddfe0d247..fc8248e101 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,7 +34,6 @@ import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; -import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -130,7 +129,7 @@ public class NetworkStatsManager { /** * {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); @@ -154,7 +153,7 @@ public class NetworkStatsManager { } /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 84a8e1c3dc..5860e20ad3 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -23,7 +23,6 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -77,7 +76,7 @@ public class EthernetManager { * @param isAvailable {@code true} if Ethernet port exists. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -98,7 +97,7 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -111,7 +110,7 @@ public class EthernetManager { * Set Ethernet configuration. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -124,7 +123,7 @@ public class EthernetManager { * Indicates whether the system currently has one or more Ethernet interfaces. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -135,7 +134,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -150,7 +149,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -169,7 +168,7 @@ public class EthernetManager { * Returns an array of available Ethernet interface names. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -184,7 +183,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 1a3dc97448..5fa515a143 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,7 +42,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) + @UnsupportedAppUsage INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index d42beae601..cbee010246 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,7 +21,6 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -220,11 +219,11 @@ public final class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private int size; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private int capacity; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private String[] iface; @UnsupportedAppUsage private int[] uid; @@ -232,21 +231,21 @@ public final class NetworkStats implements Parcelable { private int[] set; @UnsupportedAppUsage private int[] tag; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private int[] metered; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private int[] roaming; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private int[] defaultNetwork; @UnsupportedAppUsage private long[] rxBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private long[] rxPackets; @UnsupportedAppUsage private long[] txBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private long[] txPackets; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage private long[] operations; /** @@ -259,7 +258,7 @@ public final class NetworkStats implements Parcelable { @SystemApi public static class Entry { /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public String iface; /** @hide */ @UnsupportedAppUsage @@ -268,7 +267,7 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public int set; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -295,20 +294,20 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public long rxBytes; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long rxPackets; /** @hide */ @UnsupportedAppUsage public long txBytes; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long txPackets; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long operations; /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -455,7 +454,7 @@ public final class NetworkStats implements Parcelable { } /** @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index fba7561434..51f09a0103 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -32,7 +32,6 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -92,18 +91,18 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long bucketDuration; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long bucketStart; public long activeTime; @UnsupportedAppUsage public long rxBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long rxPackets; @UnsupportedAppUsage public long txBytes; - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public long txPackets; public long operations; } @@ -135,7 +134,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -221,7 +220,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public int size() { return bucketCount; } @@ -259,7 +258,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -287,7 +286,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index dc33cc7b61..a95ba12f65 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,7 +37,6 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; -import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -160,7 +159,7 @@ public class NetworkTemplate implements Parcelable { * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index a985e934ed..e7bba69dbb 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -565,7 +565,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -581,7 +581,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + @UnsupportedAppUsage public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index e9e8935a19..9484c74bcb 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface INsdManager { - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) + @UnsupportedAppUsage Messenger getMessenger(); void setEnabled(boolean enable); } From 06de3de5b496e6cf879dc1aa6ee6a5a64c2ee06d Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Tue, 27 Oct 2020 11:47:29 +0000 Subject: [PATCH 0825/1150] Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. This is a resubmit of ag/12929664 with some APIs excluded that caused test failures; see bugs 171886397, 171888296, 171864568. APIs excluded: Landroid/bluetooth/le/ScanRecord;->parseFromBytes([B)Landroid/bluetooth/le/ScanRecord; Landroid/os/Process;->myPpid()I Landroid/os/SharedMemory;->getFd()I Landroid/hardware/input/InputManager;->INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH:I Bug: 170729553 Test: Treehugger Change-Id: I8285daa8530260251ecad6f3f38f98e263629ca7 --- .../app/usage/NetworkStatsManager.java | 5 +-- core/java/android/net/EthernetManager.java | 17 +++++----- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 33 ++++++++++--------- .../java/android/net/NetworkStatsHistory.java | 17 +++++----- core/java/android/net/NetworkTemplate.java | 3 +- core/java/android/net/TrafficStats.java | 4 +-- core/java/android/net/nsd/INsdManager.aidl | 2 +- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fc8248e101..1ddfe0d247 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,6 +34,7 @@ import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -129,7 +130,7 @@ public class NetworkStatsManager { /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); @@ -153,7 +154,7 @@ public class NetworkStatsManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 5860e20ad3..84a8e1c3dc 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -76,7 +77,7 @@ public class EthernetManager { * @param isAvailable {@code true} if Ethernet port exists. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -97,7 +98,7 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -110,7 +111,7 @@ public class EthernetManager { * Set Ethernet configuration. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -123,7 +124,7 @@ public class EthernetManager { * Indicates whether the system currently has one or more Ethernet interfaces. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -134,7 +135,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -149,7 +150,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -168,7 +169,7 @@ public class EthernetManager { * Returns an array of available Ethernet interface names. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -183,7 +184,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 5fa515a143..1a3dc97448 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,7 +42,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index cbee010246..d42beae601 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -219,11 +220,11 @@ public final class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int size; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int capacity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String[] iface; @UnsupportedAppUsage private int[] uid; @@ -231,21 +232,21 @@ public final class NetworkStats implements Parcelable { private int[] set; @UnsupportedAppUsage private int[] tag; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] metered; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] roaming; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] defaultNetwork; @UnsupportedAppUsage private long[] rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] rxPackets; @UnsupportedAppUsage private long[] txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] txPackets; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] operations; /** @@ -258,7 +259,7 @@ public final class NetworkStats implements Parcelable { @SystemApi public static class Entry { /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String iface; /** @hide */ @UnsupportedAppUsage @@ -267,7 +268,7 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public int set; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -294,20 +295,20 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public long rxBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; /** @hide */ @UnsupportedAppUsage public long txBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long operations; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -454,7 +455,7 @@ public final class NetworkStats implements Parcelable { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 51f09a0103..fba7561434 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -32,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -91,18 +92,18 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketDuration; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketStart; public long activeTime; @UnsupportedAppUsage public long rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; @UnsupportedAppUsage public long txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; public long operations; } @@ -134,7 +135,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -220,7 +221,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int size() { return bucketCount; } @@ -258,7 +259,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -286,7 +287,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index a95ba12f65..dc33cc7b61 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -159,7 +160,7 @@ public class NetworkTemplate implements Parcelable { * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7bba69dbb..a985e934ed 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -565,7 +565,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -581,7 +581,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 9484c74bcb..e9e8935a19 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface INsdManager { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) Messenger getMessenger(); void setEnabled(boolean enable); } From e538030325954aa1ba08ba426d61d88a8b838923 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 15:21:39 +0000 Subject: [PATCH 0826/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Change-Id: I2accb96abbdfa665ef34aa79e87af040226bcf32 --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From 155b7dea4015b95dc2832da88e3e9a1fa84b7a17 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 16:31:24 +0000 Subject: [PATCH 0827/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Merged-In: I2accb96abbdfa665ef34aa79e87af040226bcf32 Change-Id: Ide2ba760c0552e614635b3e402890b587ddc3c4c --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From f8c98957b79f2bb915000c105c380d20cd6bb046 Mon Sep 17 00:00:00 2001 From: Ashwini Oruganti Date: Thu, 29 Oct 2020 11:19:36 -0700 Subject: [PATCH 0828/1150] Apply FLAG_IMMUTABLE to the PendingIntent in NetworkStatService.java Broadcast intents sent by AlarmManager are immutable; the system dispatches them without customization. Fixes: 171815343 Test: TH Change-Id: I35ccfc0f69fd98b5803da74d9eb12902b351acc7 --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 71e7c8adc5..12c24d4186 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -552,7 +552,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. final PendingIntent pollIntent = - PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), + PendingIntent.FLAG_IMMUTABLE); final long currentRealtime = SystemClock.elapsedRealtime(); mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, From e1600e7152da3ed78d6ea93075a1bfb3765fc279 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 16:25:34 +0000 Subject: [PATCH 0829/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Merged-In: Ide2ba760c0552e614635b3e402890b587ddc3c4c Change-Id: I68cc959b56d5984b038cea4c621c60f34472f34c --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From 93c1ce12f3ac5880f0b2ed9764b7a9b9b0233f7f Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 14:35:17 +0000 Subject: [PATCH 0830/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Merged-In: I68cc959b56d5984b038cea4c621c60f34472f34c Change-Id: Ia22c69ebff88d2d117a058e6ad22b23fa5d04fda --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From 7900906a87c1df326be9c10ecabb0853e799d851 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 13:10:51 +0000 Subject: [PATCH 0831/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: m com.android.tethering + TH Merged-In: Ib4a3a7a14d7d0e544aadf1bfb21ad390f1ba76a7 Change-Id: Ifae56d991b43c02f1e3496abbafc87d1869add8a --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From 48c46f29725e1522b5daee4241637c7e2d75c87c Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Thu, 29 Oct 2020 17:58:29 +0000 Subject: [PATCH 0832/1150] Restructure Module code [ com.android.tethering ] Code Migration from frameworks/base/packages/Tethering -> packages/modules/Connectivity/Tethering BUG: 167962976 Test: TH Merged-In: I2accb96abbdfa665ef34aa79e87af040226bcf32 Change-Id: Id7656fe7f6a6fae044dc8defd05e83d81c6b8c11 --- .../net/util/TetheringMessageBase.java | 25 ------------------- 1 file changed, 25 deletions(-) delete mode 100644 packages/Tethering/src/android/net/util/TetheringMessageBase.java diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java deleted file mode 100644 index 29c0a817b6..0000000000 --- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.net.util; - -/** - * This class defines Message.what base addresses for various state machine. - */ -public class TetheringMessageBase { - public static final int BASE_MAIN_SM = 0; - public static final int BASE_IPSERVER = 100; - -} From 6a224d7cfa9564115ecce0d75ef274be0b6f93ad Mon Sep 17 00:00:00 2001 From: Ashwini Oruganti Date: Fri, 30 Oct 2020 10:49:45 -0700 Subject: [PATCH 0833/1150] Apply FLAG_IMMUTABLE to the PendingIntent in NetworkStatService.java Broadcast intents sent by AlarmManager are immutable; the system dispatches them without customization. Fixes: 171815343 Test: TH Change-Id: I35ccfc0f69fd98b5803da74d9eb12902b351acc7 Merged-In: I35ccfc0f69fd98b5803da74d9eb12902b351acc7 --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 71e7c8adc5..12c24d4186 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -552,7 +552,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. final PendingIntent pollIntent = - PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), 0); + PendingIntent.getBroadcast(mContext, 0, new Intent(ACTION_NETWORK_STATS_POLL), + PendingIntent.FLAG_IMMUTABLE); final long currentRealtime = SystemClock.elapsedRealtime(); mAlarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, currentRealtime, From e34ebe1a097ee676fce0332a85c07de7e6efb335 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Aug 2020 16:07:22 +0900 Subject: [PATCH 0834/1150] Move module utils to the module package. Test: FrameworksWifiTest FrameworksNetTest Change-Id: I067eeecd458c34b7f2fbfa439072682661ac750c --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 78bd4cdd4e..84f40cb4b8 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; -import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; From 9627724c3b676500886d94061e6bbfbfccac29b1 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Fri, 16 Oct 2020 04:22:07 +0000 Subject: [PATCH 0835/1150] Allow the network stack to read network stats history Bug: 168984229 Test: testNetworkStatsProvider Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1450457 Change-Id: Ic9bd2d2d06c790a84e56ec8a6915f1faab16dda0 Merged-In: Ibb6342b0f263c874bb1f7ab4031a639778bad37e (cherry picked from commit 9010baec16faa806c2253f90225d002c4b2efb0c) --- .../java/com/android/server/net/NetworkStatsAccess.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 7c1c1c7ce4..72559b4825 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -28,6 +28,7 @@ import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -113,10 +114,11 @@ public final class NetworkStatsAccess { TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner - || UserHandle.getAppId(callingUid) == android.os.Process.SYSTEM_UID) { - // Carrier-privileged apps and device owners, and the system can access data usage for - // all apps on the device. + || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { + // Carrier-privileged apps and device owners, and the system (including the + // network stack) can access data usage for all apps on the device. return NetworkStatsAccess.Level.DEVICE; } From 2650c9287d93f31bf57480679d844f194767b8d9 Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Mon, 2 Nov 2020 10:29:35 +0000 Subject: [PATCH 0836/1150] Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. Bug: 170729553 Test: Treehugger Merged-In: I8285daa8530260251ecad6f3f38f98e263629ca7 Change-Id: I626caf7c1fe46c5ab1f39c2895b42a34319f771a --- .../app/usage/NetworkStatsManager.java | 5 +-- core/java/android/net/EthernetManager.java | 17 +++++----- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 33 ++++++++++--------- .../java/android/net/NetworkStatsHistory.java | 17 +++++----- core/java/android/net/NetworkTemplate.java | 3 +- core/java/android/net/TrafficStats.java | 4 +-- core/java/android/net/nsd/INsdManager.aidl | 2 +- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fc8248e101..1ddfe0d247 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,6 +34,7 @@ import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -129,7 +130,7 @@ public class NetworkStatsManager { /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); @@ -153,7 +154,7 @@ public class NetworkStatsManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 5860e20ad3..84a8e1c3dc 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -76,7 +77,7 @@ public class EthernetManager { * @param isAvailable {@code true} if Ethernet port exists. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -97,7 +98,7 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -110,7 +111,7 @@ public class EthernetManager { * Set Ethernet configuration. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -123,7 +124,7 @@ public class EthernetManager { * Indicates whether the system currently has one or more Ethernet interfaces. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -134,7 +135,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -149,7 +150,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -168,7 +169,7 @@ public class EthernetManager { * Returns an array of available Ethernet interface names. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -183,7 +184,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 5fa515a143..1a3dc97448 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,7 +42,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 34e48eb44f..cf40ce58d4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -219,11 +220,11 @@ public final class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int size; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int capacity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String[] iface; @UnsupportedAppUsage private int[] uid; @@ -231,21 +232,21 @@ public final class NetworkStats implements Parcelable { private int[] set; @UnsupportedAppUsage private int[] tag; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] metered; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] roaming; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] defaultNetwork; @UnsupportedAppUsage private long[] rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] rxPackets; @UnsupportedAppUsage private long[] txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] txPackets; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] operations; /** @@ -258,7 +259,7 @@ public final class NetworkStats implements Parcelable { @SystemApi public static class Entry { /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String iface; /** @hide */ @UnsupportedAppUsage @@ -267,7 +268,7 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public int set; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -294,20 +295,20 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public long rxBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; /** @hide */ @UnsupportedAppUsage public long txBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long operations; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -454,7 +455,7 @@ public final class NetworkStats implements Parcelable { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 51f09a0103..fba7561434 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -32,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -91,18 +92,18 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketDuration; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketStart; public long activeTime; @UnsupportedAppUsage public long rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; @UnsupportedAppUsage public long txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; public long operations; } @@ -134,7 +135,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -220,7 +221,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int size() { return bucketCount; } @@ -258,7 +259,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -286,7 +287,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cd26079a7b..72be835a1c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -159,7 +160,7 @@ public class NetworkTemplate implements Parcelable { * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7bba69dbb..a985e934ed 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -565,7 +565,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -581,7 +581,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 9484c74bcb..e9e8935a19 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface INsdManager { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) Messenger getMessenger(); void setEnabled(boolean enable); } From 5c74a0f002352a120b38e3b241123dfbdfa27d1f Mon Sep 17 00:00:00 2001 From: Mathew Inwood Date: Wed, 4 Nov 2020 09:29:36 +0000 Subject: [PATCH 0837/1150] Add maxTargetSdk restriction to unused APIs. These are APIs that have @UnsupportedAppUsage but for which we don't have any evidence of them currently being used, so should be safe to remove from the unsupported list. Bug: 170729553 Test: Treehugger Merged-In: I626caf7c1fe46c5ab1f39c2895b42a34319f771a Change-Id: I54e5ecd11e76ca1de3c5893e3a98b0108e735413 --- .../app/usage/NetworkStatsManager.java | 5 +-- core/java/android/net/EthernetManager.java | 17 +++++----- .../android/net/INetworkStatsService.aidl | 2 +- core/java/android/net/NetworkStats.java | 33 ++++++++++--------- .../java/android/net/NetworkStatsHistory.java | 17 +++++----- core/java/android/net/NetworkTemplate.java | 3 +- core/java/android/net/TrafficStats.java | 4 +-- core/java/android/net/nsd/INsdManager.aidl | 2 +- 8 files changed, 44 insertions(+), 39 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fc8248e101..1ddfe0d247 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -34,6 +34,7 @@ import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.Message; @@ -129,7 +130,7 @@ public class NetworkStatsManager { /** * {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsManager(Context context) throws ServiceNotFoundException { this(context, INetworkStatsService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); @@ -153,7 +154,7 @@ public class NetworkStatsManager { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) @TestApi public void setPollForce(boolean pollForce) { if (pollForce) { diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 5860e20ad3..84a8e1c3dc 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -23,6 +23,7 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.os.Build; import android.os.Handler; import android.os.Message; import android.os.RemoteException; @@ -76,7 +77,7 @@ public class EthernetManager { * @param isAvailable {@code true} if Ethernet port exists. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); } @@ -97,7 +98,7 @@ public class EthernetManager { * @return the Ethernet Configuration, contained in {@link IpConfiguration}. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public IpConfiguration getConfiguration(String iface) { try { return mService.getConfiguration(iface); @@ -110,7 +111,7 @@ public class EthernetManager { * Set Ethernet configuration. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void setConfiguration(String iface, IpConfiguration config) { try { mService.setConfiguration(iface, config); @@ -123,7 +124,7 @@ public class EthernetManager { * Indicates whether the system currently has one or more Ethernet interfaces. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable() { return getAvailableInterfaces().length > 0; } @@ -134,7 +135,7 @@ public class EthernetManager { * @param iface Ethernet interface name * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public boolean isAvailable(String iface) { try { return mService.isAvailable(iface); @@ -149,7 +150,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); @@ -168,7 +169,7 @@ public class EthernetManager { * Returns an array of available Ethernet interface names. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String[] getAvailableInterfaces() { try { return mService.getAvailableInterfaces(); @@ -183,7 +184,7 @@ public class EthernetManager { * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void removeListener(Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 5fa515a143..1a3dc97448 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -42,7 +42,7 @@ interface INetworkStatsService { * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted * READ_NETWORK_USAGE_STATS is checked for. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage); /** Return data layer snapshot of UID network usage. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 34e48eb44f..cf40ce58d4 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -21,6 +21,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.os.SystemClock; @@ -219,11 +220,11 @@ public final class NetworkStats implements Parcelable { * generated. */ private long elapsedRealtime; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int size; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int capacity; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private String[] iface; @UnsupportedAppUsage private int[] uid; @@ -231,21 +232,21 @@ public final class NetworkStats implements Parcelable { private int[] set; @UnsupportedAppUsage private int[] tag; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] metered; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] roaming; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int[] defaultNetwork; @UnsupportedAppUsage private long[] rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] rxPackets; @UnsupportedAppUsage private long[] txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] txPackets; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private long[] operations; /** @@ -258,7 +259,7 @@ public final class NetworkStats implements Parcelable { @SystemApi public static class Entry { /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public String iface; /** @hide */ @UnsupportedAppUsage @@ -267,7 +268,7 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public int set; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int tag; /** * Note that this is only populated w/ the default value when read from /proc or written @@ -294,20 +295,20 @@ public final class NetworkStats implements Parcelable { @UnsupportedAppUsage public long rxBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; /** @hide */ @UnsupportedAppUsage public long txBytes; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long operations; /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry() { this(IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0L); } @@ -454,7 +455,7 @@ public final class NetworkStats implements Parcelable { } /** @hide */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStats(Parcel parcel) { elapsedRealtime = parcel.readLong(); size = parcel.readInt(); diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index 51f09a0103..fba7561434 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -32,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; @@ -91,18 +92,18 @@ public class NetworkStatsHistory implements Parcelable { public static class Entry { public static final long UNKNOWN = -1; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketDuration; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketStart; public long activeTime; @UnsupportedAppUsage public long rxBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; @UnsupportedAppUsage public long txBytes; - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; public long operations; } @@ -134,7 +135,7 @@ public class NetworkStatsHistory implements Parcelable { recordEntireHistory(existing); } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); bucketStart = readLongArray(in); @@ -220,7 +221,7 @@ public class NetworkStatsHistory implements Parcelable { return 0; } - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int size() { return bucketCount; } @@ -258,7 +259,7 @@ public class NetworkStatsHistory implements Parcelable { * Return index of bucket that contains or is immediately before the * requested time. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getIndexBefore(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); if (index < 0) { @@ -286,7 +287,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry getValues(int i, Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.bucketStart = bucketStart[i]; diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index cd26079a7b..72be835a1c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -37,6 +37,7 @@ import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; @@ -159,7 +160,7 @@ public class NetworkTemplate implements Parcelable { * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null); } diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7bba69dbb..a985e934ed 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -565,7 +565,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpRxPackets() { long total = 0; for (String iface : getMobileIfaces()) { @@ -581,7 +581,7 @@ public class TrafficStats { } /** {@hide} */ - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static long getMobileTcpTxPackets() { long total = 0; for (String iface : getMobileIfaces()) { diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index 9484c74bcb..e9e8935a19 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -25,7 +25,7 @@ import android.os.Messenger; */ interface INsdManager { - @UnsupportedAppUsage + @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) Messenger getMessenger(); void setEnabled(boolean enable); } From 1dbd5ded7e005e4e884d6e0ccaf3aacb326a6995 Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Tue, 3 Nov 2020 16:49:30 +0000 Subject: [PATCH 0838/1150] DO NOT MERGE: Introduce DPMS shim for active DO/PO check Introduce a shim into DevicePolicyManagerInternal & DevicePolicyManagerService so that NetworkStatsAccessTest would not diverge from internal development branches. The DevicePolicyManagerService refactoring on the internal branch removed isActiveAdminWithPolicy in favour of isActiveDeviceOwner and isActiveProfileOwner. These methods are being made available in AOSP for NetworkStatsAccessTest. Bug: 170459325 Test: atest NetworkStatsAccessTest Change-Id: Ic7e0898989fb8222aaba2b35436765c04eb3250c --- .../java/com/android/server/net/NetworkStatsAccess.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 72559b4825..ddc5ef2000 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -24,7 +24,6 @@ import static android.net.TrafficStats.UID_TETHERING; import android.Manifest; import android.annotation.IntDef; import android.app.AppOpsManager; -import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; @@ -112,8 +111,7 @@ public final class NetworkStatsAccess { boolean hasCarrierPrivileges = tm != null && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; - boolean isDeviceOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { @@ -128,8 +126,9 @@ public final class NetworkStatsAccess { return NetworkStatsAccess.Level.DEVICESUMMARY; } - boolean isProfileOwner = dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. + boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid) + || dpmi.isActiveDeviceOwner(callingUid)); if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile. From 1694538a2059788085f233cc5ba3a49d3bfa7714 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 6 Oct 2020 16:04:31 +0800 Subject: [PATCH 0839/1150] Remove unused getTetherStats Before Android R, getTetherStats were used to collect tethering iface stats of all clients who extends ITetheringStatsProvider, which typically contains NetdTetheringStatsProvider and OffloadController. However, this always returns 0 since Android R, because: 1. OffloadController implemented NetworkStatsProvider and no longer reports stats through getTetherStats. 2. NetdTetheringStatsProvider always return 0 by design since non-offloaded iface tethering stats are already included in native iface stats. This change is a no-op refactoring to remove unused getTetherStats and update test which is not pratical. Fix for offloaded tethering stats will be in follow-up CLs. Test: atest FrameworksNetTests TetheringTests Bug: 162292214 Change-Id: Icd0717c5c2807ae3bd98626b897e4b148f142815 --- .../server/net/NetworkStatsService.java | 63 +++---------------- 1 file changed, 10 insertions(+), 53 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 12c24d4186..96e3c5163f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1083,13 +1083,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (nativeIfaceStats == -1) { return nativeIfaceStats; } else { - // When tethering offload is in use, nativeIfaceStats does not contain usage from - // offload, add it back here. - // When tethering offload is not in use, nativeIfaceStats contains tethering usage. - // this does not cause double-counting of tethering traffic, because - // NetdTetheringStatsProvider returns zero NetworkStats - // when called with STATS_PER_IFACE. - return nativeIfaceStats + getTetherStats(iface, type); + // TODO: When tethering offload is in use, nativeIfaceStats does not contain usage from + // offload, add it back here. + return nativeIfaceStats; } } @@ -1100,42 +1096,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return nativeTotalStats; } else { // Refer to comment in getIfaceStats - return nativeTotalStats + getTetherStats(IFACE_ALL, type); - } - } - - private long getTetherStats(String iface, int type) { - final NetworkStats tetherSnapshot; - final long token = Binder.clearCallingIdentity(); - try { - tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); - } catch (RemoteException e) { - Slog.w(TAG, "Error get TetherStats: " + e); - return 0; - } finally { - Binder.restoreCallingIdentity(token); - } - HashSet limitIfaces; - if (iface == IFACE_ALL) { - limitIfaces = null; - } else { - limitIfaces = new HashSet(); - limitIfaces.add(iface); - } - NetworkStats.Entry entry = tetherSnapshot.getTotal(null, limitIfaces); - if (LOGD) Slog.d(TAG, "TetherStats: iface=" + iface + " type=" + type + - " entry=" + entry); - switch (type) { - case 0: // TYPE_RX_BYTES - return entry.rxBytes; - case 1: // TYPE_RX_PACKETS - return entry.rxPackets; - case 2: // TYPE_TX_BYTES - return entry.txBytes; - case 3: // TYPE_TX_PACKETS - return entry.txPackets; - default: - return 0; + return nativeTotalStats; } } @@ -1429,14 +1390,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStats devSnapshot = readNetworkStatsSummaryDev(); Trace.traceEnd(TRACE_TAG_NETWORK); - // Tethering snapshot for dev and xt stats. Counts per-interface data from tethering stats - // providers that isn't already counted by dev and XT stats. - Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotTether"); - final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_IFACE); - Trace.traceEnd(TRACE_TAG_NETWORK); - xtSnapshot.combineAllValues(tetherSnapshot); - devSnapshot.combineAllValues(tetherSnapshot); - // Snapshot for dev/xt stats from all custom stats providers. Counts per-interface data // from stats providers that isn't already counted by dev and XT stats. Trace.traceBegin(TRACE_TAG_NETWORK, "snapshotStatsProvider"); @@ -1931,9 +1884,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Return snapshot of current tethering statistics. Will return empty - * {@link NetworkStats} if any problems are encountered. + * Return snapshot of current non-offloaded tethering statistics. Will return empty + * {@link NetworkStats} if any problems are encountered, or queried by {@code STATS_PER_IFACE} + * since it is already included by {@link #nativeGetIfaceStat}. + * See {@code OffloadTetheringStatsProvider} for offloaded tethering stats. */ + // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded + // tethering stats. private NetworkStats getNetworkStatsTethering(int how) throws RemoteException { try { return mNetworkManager.getNetworkStatsTethering(how); From 3841fbeecabca2c7922b41990479c5f5189d0d66 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 6 Oct 2020 11:59:56 +0800 Subject: [PATCH 0840/1150] Return offloaded traffic when querying from TrafficStats API TrafficStats API are being used for querying realtime network statistics for years. However, on certain devices, some network traffic are produced by hardware components and not be able to seen by kernel counters. Thus, include statistics for those missing network traffic is necessary. Note that the included statistics might be stale since polling newest stats from hardware might impact system health and not suitable for TrafficStats API use cases. Test: atest FrameworksNetTests TetheringTests Bug: 16229221 Change-Id: I6741c41cb5145ca8748f9b083b9c15e7e2735681 --- core/java/android/net/TrafficStats.java | 20 +++-- .../server/net/NetworkStatsService.java | 87 +++++++++++++------ 2 files changed, 73 insertions(+), 34 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index e7bba69dbb..7a79ceb14a 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -976,11 +976,17 @@ public class TrafficStats { } } - // NOTE: keep these in sync with android_net_TrafficStats.cpp - private static final int TYPE_RX_BYTES = 0; - private static final int TYPE_RX_PACKETS = 1; - private static final int TYPE_TX_BYTES = 2; - private static final int TYPE_TX_PACKETS = 3; - private static final int TYPE_TCP_RX_PACKETS = 4; - private static final int TYPE_TCP_TX_PACKETS = 5; + // NOTE: keep these in sync with {@code com_android_server_net_NetworkStatsService.cpp}. + /** {@hide} */ + public static final int TYPE_RX_BYTES = 0; + /** {@hide} */ + public static final int TYPE_RX_PACKETS = 1; + /** {@hide} */ + public static final int TYPE_TX_BYTES = 2; + /** {@hide} */ + public static final int TYPE_TX_PACKETS = 3; + /** {@hide} */ + public static final int TYPE_TCP_RX_PACKETS = 4; + /** {@hide} */ + public static final int TYPE_TCP_TX_PACKETS = 5; } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 96e3c5163f..bfd0211f18 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1083,9 +1083,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (nativeIfaceStats == -1) { return nativeIfaceStats; } else { - // TODO: When tethering offload is in use, nativeIfaceStats does not contain usage from - // offload, add it back here. - return nativeIfaceStats; + // When tethering offload is in use, nativeIfaceStats does not contain usage from + // offload, add it back here. Note that the included statistics might be stale + // since polling newest stats from hardware might impact system health and not + // suitable for TrafficStats API use cases. + return nativeIfaceStats + getProviderIfaceStats(iface, type); } } @@ -1096,7 +1098,31 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return nativeTotalStats; } else { // Refer to comment in getIfaceStats - return nativeTotalStats; + return nativeTotalStats + getProviderIfaceStats(IFACE_ALL, type); + } + } + + private long getProviderIfaceStats(@Nullable String iface, int type) { + final NetworkStats providerSnapshot = getNetworkStatsFromProviders(STATS_PER_IFACE); + final HashSet limitIfaces; + if (iface == IFACE_ALL) { + limitIfaces = null; + } else { + limitIfaces = new HashSet<>(); + limitIfaces.add(iface); + } + final NetworkStats.Entry entry = providerSnapshot.getTotal(null, limitIfaces); + switch (type) { + case TrafficStats.TYPE_RX_BYTES: + return entry.rxBytes; + case TrafficStats.TYPE_RX_PACKETS: + return entry.rxPackets; + case TrafficStats.TYPE_TX_BYTES: + return entry.txBytes; + case TrafficStats.TYPE_TX_PACKETS: + return entry.txPackets; + default: + return 0; } } @@ -1464,29 +1490,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean persistUid = (flags & FLAG_PERSIST_UID) != 0; final boolean persistForce = (flags & FLAG_PERSIST_FORCE) != 0; - // Request asynchronous stats update from all providers for next poll. And wait a bit of - // time to allow providers report-in given that normally binder call should be fast. Note - // that size of list might be changed because addition/removing at the same time. For - // addition, the stats of the missed provider can only be collected in next poll; - // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS - // once that happened. - // TODO: request with a valid token. - Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); - final int registeredCallbackCount = mStatsProviderCbList.size(); - mStatsProviderSem.drainPermits(); - invokeForAllStatsProviderCallbacks( - (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); - try { - mStatsProviderSem.tryAcquire(registeredCallbackCount, - MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - // Strictly speaking it's possible a provider happened to deliver between the timeout - // and the log, and that doesn't matter too much as this is just a debug log. - Log.d(TAG, "requestStatsUpdate - providers responded " - + mStatsProviderSem.availablePermits() - + "/" + registeredCallbackCount + " : " + e); - } - Trace.traceEnd(TRACE_TAG_NETWORK); + performPollFromProvidersLocked(); // TODO: consider marking "untrusted" times in historical stats final long currentTime = mClock.millis(); @@ -1531,6 +1535,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); } + @GuardedBy("mStatsLock") + private void performPollFromProvidersLocked() { + // Request asynchronous stats update from all providers for next poll. And wait a bit of + // time to allow providers report-in given that normally binder call should be fast. Note + // that size of list might be changed because addition/removing at the same time. For + // addition, the stats of the missed provider can only be collected in next poll; + // for removal, wait might take up to MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS + // once that happened. + // TODO: request with a valid token. + Trace.traceBegin(TRACE_TAG_NETWORK, "provider.requestStatsUpdate"); + final int registeredCallbackCount = mStatsProviderCbList.size(); + mStatsProviderSem.drainPermits(); + invokeForAllStatsProviderCallbacks( + (cb) -> cb.mProvider.onRequestStatsUpdate(0 /* unused */)); + try { + mStatsProviderSem.tryAcquire(registeredCallbackCount, + MAX_STATS_PROVIDER_POLL_WAIT_TIME_MS, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + // Strictly speaking it's possible a provider happened to deliver between the timeout + // and the log, and that doesn't matter too much as this is just a debug log. + Log.d(TAG, "requestStatsUpdate - providers responded " + + mStatsProviderSem.availablePermits() + + "/" + registeredCallbackCount + " : " + e); + } + Trace.traceEnd(TRACE_TAG_NETWORK); + } + /** * Sample recent statistics summary into {@link EventLog}. */ @@ -2183,6 +2214,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + // TODO: Remove unused definitions after removing JNI that fills these variables. + // See {@code com_android_server_net_NetworkStatsService.cpp}. private static int TYPE_RX_BYTES; private static int TYPE_RX_PACKETS; private static int TYPE_TX_BYTES; From bc955da83fc8a054d12f52c2ef4a191cfdc5ca37 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 6 Nov 2020 19:19:31 +0800 Subject: [PATCH 0841/1150] Remove unused variables From aosp/537809, variables that used to fetch realtime stats are defined in NetworkStatsService. These varialbles are filled by JNI in boot up stage in order to keep definitions sync with native layer. However, there is still a copy in TrafficStats.java, and this copy cannot be filled in boot-up stage since it is in app process. Besides, making a binder call to fetch these constants from service is considered an overkill. Thus, since there is no caller to these variables and callers should use definitions in TrafficStats, remove these variables. Test: atest FrameworksNetTests Bug: 16229221 Change-Id: I6a48d4dbb1b824cfc6c4a47395b2a76aa28cf5c9 --- .../android/server/net/NetworkStatsService.java | 9 --------- ...com_android_server_net_NetworkStatsService.cpp | 15 --------------- 2 files changed, 24 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index bfd0211f18..81a6641de8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -2214,15 +2214,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - // TODO: Remove unused definitions after removing JNI that fills these variables. - // See {@code com_android_server_net_NetworkStatsService.cpp}. - private static int TYPE_RX_BYTES; - private static int TYPE_RX_PACKETS; - private static int TYPE_TX_BYTES; - private static int TYPE_TX_PACKETS; - private static int TYPE_TCP_RX_PACKETS; - private static int TYPE_TCP_TX_PACKETS; - private static native long nativeGetTotalStat(int type, boolean useBpfStats); private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats); private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats); diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 0275f3ea32..10b248a70e 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -215,21 +215,6 @@ static const JNINativeMethod gMethods[] = { }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { - jclass netStatsService = env->FindClass("com/android/server/net/NetworkStatsService"); - jfieldID rxBytesId = env->GetStaticFieldID(netStatsService, "TYPE_RX_BYTES", "I"); - jfieldID rxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_RX_PACKETS", "I"); - jfieldID txBytesId = env->GetStaticFieldID(netStatsService, "TYPE_TX_BYTES", "I"); - jfieldID txPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TX_PACKETS", "I"); - jfieldID tcpRxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_RX_PACKETS", "I"); - jfieldID tcpTxPacketsId = env->GetStaticFieldID(netStatsService, "TYPE_TCP_TX_PACKETS", "I"); - - env->SetStaticIntField(netStatsService, rxBytesId, RX_BYTES); - env->SetStaticIntField(netStatsService, rxPacketsId, RX_PACKETS); - env->SetStaticIntField(netStatsService, txBytesId, TX_BYTES); - env->SetStaticIntField(netStatsService, txPacketsId, TX_PACKETS); - env->SetStaticIntField(netStatsService, tcpRxPacketsId, TCP_RX_PACKETS); - env->SetStaticIntField(netStatsService, tcpTxPacketsId, TCP_TX_PACKETS); - return jniRegisterNativeMethods(env, "com/android/server/net/NetworkStatsService", gMethods, NELEM(gMethods)); } From 6b2f5bb979dfff11e56cd38ddb85495f92581db1 Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Thu, 12 Nov 2020 18:26:09 -0800 Subject: [PATCH 0842/1150] Remove legacy style metalava suppression @SuppressLint("Doclava125") is a legacy way of suppressing RequiresPermission check. Updating to the new style of suppression so metalava no longer has to support the legacy mode. sed -i "s/@SuppressLint(\"Doclava125/@SuppressLint(\"RequiresPermission/" \ core/java/android/app/admin/DevicePolicyManager.java \ core/java/android/hardware/hdmi/HdmiControlManager.java \ core/java/android/hardware/location/ContextHubManager.java \ core/java/android/hardware/usb/UsbDeviceConnection.java \ core/java/android/net/TrafficStats.java \ core/java/android/os/RecoverySystem.java \ core/java/android/os/storage/StorageManager.java \ core/java/android/service/persistentdata/PersistentDataBlockManager.java \ location/java/android/location/LocationManager.java \ media/java/android/media/AudioManager.java \ telecomm/java/android/telecom/TelecomManager.java \ telephony/java/android/telephony/CarrierConfigManager.java \ telephony/java/android/telephony/TelephonyManager.java \ wifi/java/android/net/wifi/RttManager.java \ wifi/java/android/net/wifi/WifiScanner.java Test: make Exempt-From-Owner-Approval: No-op change Change-Id: I6d5df95cfca2950ea86872d2f0afc1ba828841dc --- core/java/android/net/TrafficStats.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 7376830505..4e019cf073 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -301,7 +301,7 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - @SuppressLint("Doclava125") + @SuppressLint("RequiresPermission") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } @@ -339,7 +339,7 @@ public class TrafficStats { * * @see #setThreadStatsUid(int) */ - @SuppressLint("Doclava125") + @SuppressLint("RequiresPermission") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } From 0caeaa3ba226793d03b273d3695e0dc0e00eccff Mon Sep 17 00:00:00 2001 From: Aurimas Liutikas Date: Thu, 12 Nov 2020 18:29:11 -0800 Subject: [PATCH 0843/1150] Remove legacy style metalava suppression @SuppressLint("Doclava125") is a legacy way of suppressing RequiresPermission check. Updating to the new style of suppression so metalava no longer has to support the legacy mode. sed -i "s/@SuppressLint(\"Doclava125/@SuppressLint(\"RequiresPermission/" \ core/java/android/app/admin/DevicePolicyManager.java \ core/java/android/hardware/hdmi/HdmiControlManager.java \ core/java/android/hardware/location/ContextHubManager.java \ core/java/android/hardware/usb/UsbDeviceConnection.java \ core/java/android/net/TrafficStats.java \ core/java/android/os/RecoverySystem.java \ core/java/android/os/storage/StorageManager.java \ core/java/android/service/persistentdata/PersistentDataBlockManager.java \ location/java/android/location/LocationManager.java \ media/java/android/media/AudioManager.java \ telecomm/java/android/telecom/TelecomManager.java \ telephony/java/android/telephony/CarrierConfigManager.java \ telephony/java/android/telephony/TelephonyManager.java \ wifi/java/android/net/wifi/RttManager.java \ wifi/java/android/net/wifi/WifiScanner.java Test: make Exempt-From-Owner-Approval: No-op change Merged-In: I6d5df95cfca2950ea86872d2f0afc1ba828841dc Change-Id: I6d5df95cfca2950ea86872d2f0afc1ba828841dc --- core/java/android/net/TrafficStats.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 7376830505..4e019cf073 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -301,7 +301,7 @@ public class TrafficStats { * Changes only take effect during subsequent calls to * {@link #tagSocket(Socket)}. */ - @SuppressLint("Doclava125") + @SuppressLint("RequiresPermission") public static void setThreadStatsUid(int uid) { NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); } @@ -339,7 +339,7 @@ public class TrafficStats { * * @see #setThreadStatsUid(int) */ - @SuppressLint("Doclava125") + @SuppressLint("RequiresPermission") public static void clearThreadStatsUid() { NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); } From 01f60b234e90e1c0d8e694faa8c08f880228eadc Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 29 Sep 2020 14:19:24 +0800 Subject: [PATCH 0844/1150] Expose getTx/RxBytes in TrafficStats Test: atest FrameworksNetTests TrafficStatsTest atest android.net.cts android.net.wifi.cts Bug: 164965653 Change-Id: I17b9d0bc2404c5727d4c4530ad941439b7b71a54 --- core/java/android/net/TrafficStats.java | 60 ++++++++++++++++++++----- 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java index 4e019cf073..fa650617f3 100644 --- a/core/java/android/net/TrafficStats.java +++ b/core/java/android/net/TrafficStats.java @@ -597,10 +597,17 @@ public class TrafficStats { } /** - * Return the number of packets transmitted on the specified interface since - * device boot. Statistics are measured at the network layer, so both TCP and + * Return the number of packets transmitted on the specified interface since the interface + * was created. Statistics are measured at the network layer, so both TCP and * UDP usage are included. * + * Note that the returned values are partial statistics that do not count data from several + * sources and do not apply several adjustments that are necessary for correctness, such + * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to + * determine whether traffic is being transferred on the specific interface but are not a + * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} + * APIs. + * * @param iface The name of the interface. * @return The number of transmitted packets. */ @@ -613,10 +620,17 @@ public class TrafficStats { } /** - * Return the number of packets received on the specified interface since - * device boot. Statistics are measured at the network layer, so both TCP + * Return the number of packets received on the specified interface since the interface was + * created. Statistics are measured at the network layer, so both TCP * and UDP usage are included. * + * Note that the returned values are partial statistics that do not count data from several + * sources and do not apply several adjustments that are necessary for correctness, such + * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to + * determine whether traffic is being transferred on the specific interface but are not a + * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} + * APIs. + * * @param iface The name of the interface. * @return The number of received packets. */ @@ -628,9 +642,22 @@ public class TrafficStats { } } - /** {@hide} */ - @UnsupportedAppUsage - public static long getTxBytes(String iface) { + /** + * Return the number of bytes transmitted on the specified interface since the interface + * was created. Statistics are measured at the network layer, so both TCP and + * UDP usage are included. + * + * Note that the returned values are partial statistics that do not count data from several + * sources and do not apply several adjustments that are necessary for correctness, such + * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to + * determine whether traffic is being transferred on the specific interface but are not a + * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} + * APIs. + * + * @param iface The name of the interface. + * @return The number of transmitted bytes. + */ + public static long getTxBytes(@NonNull String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_TX_BYTES); } catch (RemoteException e) { @@ -638,9 +665,22 @@ public class TrafficStats { } } - /** {@hide} */ - @UnsupportedAppUsage - public static long getRxBytes(String iface) { + /** + * Return the number of bytes received on the specified interface since the interface + * was created. Statistics are measured at the network layer, so both TCP + * and UDP usage are included. + * + * Note that the returned values are partial statistics that do not count data from several + * sources and do not apply several adjustments that are necessary for correctness, such + * as adjusting for VPN apps, IPv6-in-IPv4 translation, etc. These values can be used to + * determine whether traffic is being transferred on the specific interface but are not a + * substitute for the more accurate statistics provided by the {@link NetworkStatsManager} + * APIs. + * + * @param iface The name of the interface. + * @return The number of received bytes. + */ + public static long getRxBytes(@NonNull String iface) { try { return getStatsService().getIfaceStats(iface, TYPE_RX_BYTES); } catch (RemoteException e) { From 00cc9a265bc10cb220d451df269f69b04abcf074 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Aug 2020 16:07:22 +0900 Subject: [PATCH 0845/1150] Move module utils to the module package. Test: FrameworksWifiTest FrameworksNetTest Change-Id: I067eeecd458c34b7f2fbfa439072682661ac750c Merged-In: I067eeecd458c34b7f2fbfa439072682661ac750c --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 4a1820a8e5..d907505481 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; -import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; From 9768bc681f16d532d884ef9fb60cb14737fb9448 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 30 Nov 2020 16:47:34 +0900 Subject: [PATCH 0846/1150] Remove NATT keepalive from IpSecTransform The code is unused, and based on ConnectivityManager#startNattKeepalive, which is deprecated. Bug: 174436414 Test: atest FrameworksNetTests Change-Id: I08c6c1baec668a304d971bb6f2328891a5611e6a --- core/java/android/net/IpSecTransform.java | 104 ---------------------- 1 file changed, 104 deletions(-) diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index 44a0a4f3e1..aa7811a3a1 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -17,8 +17,6 @@ package android.net; import static android.net.IpSecManager.INVALID_RESOURCE_ID; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresFeature; @@ -27,7 +25,6 @@ import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; -import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.ServiceManager; @@ -181,7 +178,6 @@ public final class IpSecTransform implements AutoCloseable { try { IIpSecService svc = getIpSecService(); svc.deleteTransform(mResourceId); - stopNattKeepalive(); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } catch (Exception e) { @@ -212,36 +208,6 @@ public final class IpSecTransform implements AutoCloseable { private int mResourceId; private final Context mContext; private final CloseGuard mCloseGuard = CloseGuard.get(); - private ConnectivityManager.PacketKeepalive mKeepalive; - private Handler mCallbackHandler; - private final ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback = - new ConnectivityManager.PacketKeepaliveCallback() { - - @Override - public void onStarted() { - synchronized (this) { - mCallbackHandler.post(() -> mUserKeepaliveCallback.onStarted()); - } - } - - @Override - public void onStopped() { - synchronized (this) { - mKeepalive = null; - mCallbackHandler.post(() -> mUserKeepaliveCallback.onStopped()); - } - } - - @Override - public void onError(int error) { - synchronized (this) { - mKeepalive = null; - mCallbackHandler.post(() -> mUserKeepaliveCallback.onError(error)); - } - } - }; - - private NattKeepaliveCallback mUserKeepaliveCallback; /** @hide */ @VisibleForTesting @@ -273,76 +239,6 @@ public final class IpSecTransform implements AutoCloseable { public void onError(int error) {} } - /** - * Start a NAT-T keepalive session for the current transform. - * - * For a transform that is using UDP encapsulated IPv4, NAT-T offloading provides - * a power efficient mechanism of sending NAT-T packets at a specified interval. - * - * @param userCallback a {@link #NattKeepaliveCallback} to receive asynchronous status - * information about the requested NAT-T keepalive session. - * @param intervalSeconds the interval between NAT-T keepalives being sent. The - * the allowed range is between 20 and 3600 seconds. - * @param handler a handler on which to post callbacks when received. - * - * @hide - */ - @RequiresPermission(anyOf = { - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, - android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD - }) - public void startNattKeepalive(@NonNull NattKeepaliveCallback userCallback, - int intervalSeconds, @NonNull Handler handler) throws IOException { - checkNotNull(userCallback); - if (intervalSeconds < 20 || intervalSeconds > 3600) { - throw new IllegalArgumentException("Invalid NAT-T keepalive interval"); - } - checkNotNull(handler); - if (mResourceId == INVALID_RESOURCE_ID) { - throw new IllegalStateException( - "Packet keepalive cannot be started for an inactive transform"); - } - - synchronized (mKeepaliveCallback) { - if (mKeepaliveCallback != null) { - throw new IllegalStateException("Keepalive already active"); - } - - mUserKeepaliveCallback = userCallback; - ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - mKeepalive = cm.startNattKeepalive( - mConfig.getNetwork(), intervalSeconds, mKeepaliveCallback, - NetworkUtils.numericToInetAddress(mConfig.getSourceAddress()), - 4500, // FIXME urgently, we need to get the port number from the Encap socket - NetworkUtils.numericToInetAddress(mConfig.getDestinationAddress())); - mCallbackHandler = handler; - } - } - - /** - * Stop an ongoing NAT-T keepalive session. - * - * Calling this API will request that an ongoing NAT-T keepalive session be terminated. - * If this API is not called when a Transform is closed, the underlying NAT-T session will - * be terminated automatically. - * - * @hide - */ - @RequiresPermission(anyOf = { - android.Manifest.permission.MANAGE_IPSEC_TUNNELS, - android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD - }) - public void stopNattKeepalive() { - synchronized (mKeepaliveCallback) { - if (mKeepalive == null) { - Log.e(TAG, "No active keepalive to stop"); - return; - } - mKeepalive.stop(); - } - } - /** This class is used to build {@link IpSecTransform} objects. */ public static class Builder { private Context mContext; From 60dcea8f1e8799c9c17efbf30d2fe219530abed7 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 30 Nov 2020 15:47:53 +0900 Subject: [PATCH 0847/1150] Remove hidden API usage in metrics toString Remove usage of hidden NetworkType, transport APIs in toString() implementations of metrics and data usage classes. The toString implementations can log the transports or network type as hex or raw indices. While slightly less readable, the metrics classes and network type APIs are deprecated. Bug: 174436414 Test: m Change-Id: I79239a540b66dadd3bbe0a997960530878331358 --- core/java/android/net/NetworkIdentity.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 0948a4da1a..efbfbf93f9 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -17,7 +17,6 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeMobile; import android.content.Context; @@ -84,7 +83,7 @@ public class NetworkIdentity implements Comparable { @Override public String toString() { final StringBuilder builder = new StringBuilder("{"); - builder.append("type=").append(getNetworkTypeName(mType)); + builder.append("type=").append(mType); builder.append(", subType="); if (mSubType == SUBTYPE_COMBINED) { builder.append("COMBINED"); From 8ea7ad3d7b5f20c0e67248ac3477c3b2473723ed Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 30 Nov 2020 15:52:46 +0900 Subject: [PATCH 0848/1150] Set NetworkIdentity subscriberId on all networks Instead of setting NetworkIdentity.subscriberId only on telephony networks, set it when provided on any network. At the moment only telephony is expected to have a subscriberId in its NetworkState anyway, and while there are plans for other network agents (wifi) to have a subscriberId, it should also be set in that case. This allows NetworkIdentity to stop depending on hidden network type APIs to determine if the network is mobile. Bug: 174436414 Test: atest FrameworksNetTests Change-Id: I4f09987f8737d1801342eb5d6d7c2b9968b466b0 --- core/java/android/net/NetworkIdentity.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index efbfbf93f9..a0dc72d4ad 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -17,7 +17,6 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; -import static android.net.ConnectivityManager.isNetworkTypeMobile; import android.content.Context; import android.net.wifi.WifiInfo; @@ -25,7 +24,6 @@ import android.net.wifi.WifiManager; import android.os.Build; import android.service.NetworkIdentityProto; import android.telephony.Annotation.NetworkType; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import java.util.Objects; @@ -193,18 +191,9 @@ public class NetworkIdentity implements Comparable { boolean metered = !state.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - if (isNetworkTypeMobile(type)) { - if (state.subscriberId == null) { - if (state.networkInfo.getState() != NetworkInfo.State.DISCONNECTED && - state.networkInfo.getState() != NetworkInfo.State.UNKNOWN) { - Slog.w(TAG, "Active mobile network without subscriber! ni = " - + state.networkInfo); - } - } + subscriberId = state.subscriberId; - subscriberId = state.subscriberId; - - } else if (type == TYPE_WIFI) { + if (type == TYPE_WIFI) { if (state.networkId != null) { networkId = state.networkId; } else { From 7ff5b025cdac39824932c6940dd1799bf62dcb8a Mon Sep 17 00:00:00 2001 From: Serik Beketayev Date: Sun, 6 Dec 2020 22:31:23 -0800 Subject: [PATCH 0849/1150] [Mainline Migration] Migrate NetworkUtils Migrating makeStrings(), numericToInetAddress() APIs Bug: 173089079 Test: atest FrameworksNetTests Change-Id: Ie914fd41bc3ce16d07f5d2768b89ce805b9245a9 --- .../java/com/android/server/IpSecService.java | 6 +++--- .../com/android/server/net/IpConfigStore.java | 21 +++++++++++-------- .../android/server/net/IpConfigStoreTest.java | 6 +++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index b2f0c8376d..f648c3e146 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -31,6 +31,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.IIpSecService; import android.net.INetd; +import android.net.InetAddresses; import android.net.IpSecAlgorithm; import android.net.IpSecConfig; import android.net.IpSecManager; @@ -41,7 +42,6 @@ import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; import android.net.LinkAddress; import android.net.Network; -import android.net.NetworkUtils; import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; @@ -1083,7 +1083,7 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Unspecified address"); } - InetAddress checkAddr = NetworkUtils.numericToInetAddress(inetAddress); + InetAddress checkAddr = InetAddresses.parseNumericAddress(inetAddress); if (checkAddr.isAnyLocalAddress()) { throw new IllegalArgumentException("Inappropriate wildcard address: " + inetAddress); @@ -1467,7 +1467,7 @@ public class IpSecService extends IIpSecService.Stub { private int getFamily(String inetAddress) { int family = AF_UNSPEC; - InetAddress checkAddress = NetworkUtils.numericToInetAddress(inetAddress); + InetAddress checkAddress = InetAddresses.parseNumericAddress(inetAddress); if (checkAddress instanceof Inet4Address) { family = AF_INET; } else if (checkAddress instanceof Inet6Address) { diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index f0bf5c0975..9c5abd4706 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -16,11 +16,11 @@ package com.android.server.net; +import android.net.InetAddresses; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.StaticIpConfiguration; @@ -284,8 +284,10 @@ public class IpConfigStore { } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress linkAddr = new LinkAddress( - NetworkUtils.numericToInetAddress(in.readUTF()), in.readInt()); + LinkAddress linkAddr = + new LinkAddress( + InetAddresses.parseNumericAddress(in.readUTF()), + in.readInt()); if (linkAddr.getAddress() instanceof Inet4Address && staticIpConfiguration.ipAddress == null) { staticIpConfiguration.ipAddress = linkAddr; @@ -297,7 +299,7 @@ public class IpConfigStore { InetAddress gateway = null; if (version == 1) { // only supported default gateways - leave the dest/prefix empty - gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + gateway = InetAddresses.parseNumericAddress(in.readUTF()); if (staticIpConfiguration.gateway == null) { staticIpConfiguration.gateway = gateway; } else { @@ -305,12 +307,13 @@ public class IpConfigStore { } } else { if (in.readInt() == 1) { - dest = new LinkAddress( - NetworkUtils.numericToInetAddress(in.readUTF()), - in.readInt()); + dest = + new LinkAddress( + InetAddresses.parseNumericAddress(in.readUTF()), + in.readInt()); } if (in.readInt() == 1) { - gateway = NetworkUtils.numericToInetAddress(in.readUTF()); + gateway = InetAddresses.parseNumericAddress(in.readUTF()); } RouteInfo route = new RouteInfo(dest, gateway); if (route.isIPv4Default() && @@ -322,7 +325,7 @@ public class IpConfigStore { } } else if (key.equals(DNS_KEY)) { staticIpConfiguration.dnsServers.add( - NetworkUtils.numericToInetAddress(in.readUTF())); + InetAddresses.parseNumericAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); } else if (key.equals(PROXY_HOST_KEY)) { diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java index 7767a2810a..9d300a6113 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -20,11 +20,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.fail; +import android.net.InetAddresses; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; -import android.net.NetworkUtils; import android.net.ProxyInfo; import android.net.StaticIpConfiguration; import android.util.ArrayMap; @@ -79,8 +79,8 @@ public class IpConfigStoreTest { StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); staticIpConfiguration.ipAddress = new LinkAddress(IP_ADDR_1); - staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_1)); - staticIpConfiguration.dnsServers.add(NetworkUtils.numericToInetAddress(DNS_IP_ADDR_2)); + staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); + staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); ProxyInfo proxyInfo = new ProxyInfo("10.10.10.10", 88, "host1,host2"); From 6f31ece763d4fda9b3b15651f3d3cf8ede1c3f4e Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 2 Dec 2020 12:50:18 +0900 Subject: [PATCH 0850/1150] Split NetworkUtils and NetworkUtilsInternal NetworkUtils is planned to move to a dedicated JAR for connectivity classes, while NetworkUtilsInternal would stay in the frameworks-minus-apex JAR, in the com.android.internal.net package. Bug: 171540887 Test: m, boots, wifi working atest FrameworksNetTests Change-Id: I3d38d72ad23a4bf84af823c7baeb6fed25c0665f --- core/java/android/net/NetworkStatsHistory.java | 2 +- .../java/com/android/server/net/NetworkStatsCollection.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index fba7561434..bf25602041 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -26,9 +26,9 @@ import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLongArray; import static android.net.NetworkStatsHistory.Entry.UNKNOWN; import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; -import static android.net.NetworkUtils.multiplySafeByRational; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; import static com.android.internal.util.ArrayUtils.total; import android.compat.annotation.UnsupportedAppUsage; diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 342a11b87a..c4beddd42e 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -28,9 +28,9 @@ import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; -import static android.net.NetworkUtils.multiplySafeByRational; import static android.text.format.DateUtils.WEEK_IN_MILLIS; +import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; import static com.android.server.net.NetworkStatsService.TAG; import android.net.NetworkIdentity; From d436634a35924807d2ef6f21948941bdcd8b57ec Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 3 Dec 2020 17:58:49 +0900 Subject: [PATCH 0851/1150] Register ethernet listeners on specific Executors Have users of EthernetManager#addListener specify an Executor instead of running callbacks on ConnectivityThread. For existing clients, run callbacks on the common BackgroundThread. This change in behavior is fine because addListener is not an API, the threading model in Q was to run callbacks on the looper of the thread that first created EthernetManager (so there is already no guarantee on which thread is used), and the only users are in Settings. ConnectivityThread is moving to a connectivity-specific JAR, so it should not be used by external classes. Bug: 174436414 Test: Ethernet client / tethering working atest TetheringIntegrationTests Change-Id: Ic9a959f89915329f79eeeaa0a210ad50811d1291 --- core/java/android/net/EthernetManager.java | 93 ++++++++++++++-------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/EthernetManager.java b/core/java/android/net/EthernetManager.java index 84a8e1c3dc..7cd63ef9cc 100644 --- a/core/java/android/net/EthernetManager.java +++ b/core/java/android/net/EthernetManager.java @@ -24,10 +24,11 @@ import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.os.Build; -import android.os.Handler; -import android.os.Message; import android.os.RemoteException; +import com.android.internal.annotations.GuardedBy; +import com.android.internal.os.BackgroundThread; + import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; @@ -41,31 +42,35 @@ import java.util.concurrent.Executor; @SystemService(Context.ETHERNET_SERVICE) public class EthernetManager { private static final String TAG = "EthernetManager"; - private static final int MSG_AVAILABILITY_CHANGED = 1000; - private final Context mContext; private final IEthernetManager mService; - private final Handler mHandler = new Handler(ConnectivityThread.getInstanceLooper()) { - @Override - public void handleMessage(Message msg) { - if (msg.what == MSG_AVAILABILITY_CHANGED) { - boolean isAvailable = (msg.arg1 == 1); - for (Listener listener : mListeners) { - listener.onAvailabilityChanged((String) msg.obj, isAvailable); - } - } - } - }; - private final ArrayList mListeners = new ArrayList<>(); + @GuardedBy("mListeners") + private final ArrayList mListeners = new ArrayList<>(); private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override public void onAvailabilityChanged(String iface, boolean isAvailable) { - mHandler.obtainMessage( - MSG_AVAILABILITY_CHANGED, isAvailable ? 1 : 0, 0, iface).sendToTarget(); + synchronized (mListeners) { + for (ListenerInfo li : mListeners) { + li.executor.execute(() -> + li.listener.onAvailabilityChanged(iface, isAvailable)); + } + } } }; + private static class ListenerInfo { + @NonNull + public final Executor executor; + @NonNull + public final Listener listener; + + private ListenerInfo(@NonNull Executor executor, @NonNull Listener listener) { + this.executor = executor; + this.listener = listener; + } + } + /** * A listener interface to receive notification on changes in Ethernet. * @hide @@ -89,7 +94,6 @@ public class EthernetManager { * @hide */ public EthernetManager(Context context, IEthernetManager service) { - mContext = context; mService = service; } @@ -146,21 +150,38 @@ public class EthernetManager { /** * Adds a listener. + * + * Consider using {@link #addListener(Listener, Executor)} instead: this method uses a default + * executor that may have higher latency than a provided executor. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void addListener(Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); + public void addListener(@NonNull Listener listener) { + addListener(listener, BackgroundThread.getExecutor()); + } + + /** + * Adds a listener. + * @param listener A {@link Listener} to add. + * @param executor Executor to run callbacks on. + * @throws IllegalArgumentException If the listener or executor is null. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void addListener(@NonNull Listener listener, @NonNull Executor executor) { + if (listener == null || executor == null) { + throw new NullPointerException("listener and executor must not be null"); } - mListeners.add(listener); - if (mListeners.size() == 1) { - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + synchronized (mListeners) { + mListeners.add(new ListenerInfo(executor, listener)); + if (mListeners.size() == 1) { + try { + mService.addListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } } } @@ -185,16 +206,18 @@ public class EthernetManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(Listener listener) { + public void removeListener(@NonNull Listener listener) { if (listener == null) { throw new IllegalArgumentException("listener must not be null"); } - mListeners.remove(listener); - if (mListeners.isEmpty()) { - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + synchronized (mListeners) { + mListeners.removeIf(l -> l.listener == listener); + if (mListeners.isEmpty()) { + try { + mService.removeListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } } } From 1b161bcebcbe0c72c6a0c45728a2f62adac492a3 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 19 Aug 2020 16:07:22 +0900 Subject: [PATCH 0852/1150] Move module utils to the module package. Test: FrameworksWifiTest FrameworksNetTest Change-Id: If5d1e4a58fb2d6d9544e6d01995dabe445cf1f25 Merged-In: I067eeecd458c34b7f2fbfa439072682661ac750c --- services/core/java/com/android/server/NsdService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 4a1820a8e5..d907505481 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -25,7 +25,6 @@ import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; -import android.net.util.nsd.DnsSdTxtRecord; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; @@ -42,6 +41,7 @@ import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; From 38a17a772684b89e1616ee7180aeb898d2d2af79 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Wed, 23 Dec 2020 22:42:10 +0000 Subject: [PATCH 0853/1150] Migrate frameworks/base/wifi & frameworks/base/packages/OsuLogin Migrate to packages/modules/Wifi. This CL will be presubmit tested once migration is complete. This CL drops the code from frameworks/base/wifi and migrated to packages/modules/Wifi. Also adjusts visibility rules in frameworks/base/Android.bp Bug: 137323948 Test: TH Change-Id: Id02e28648e922a30d6a81cf92b39eff4ca3cc002 --- .../android/net/wifi/p2p/IWifiP2pManager.aidl | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl deleted file mode 100644 index fd89d3b048..0000000000 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p; - -import android.os.Messenger; - -/** - * Interface that WifiP2pService implements - * - * {@hide} - */ -interface IWifiP2pManager -{ - Messenger getMessenger(in IBinder binder, in String packageName); - Messenger getP2pStateMachineMessenger(); - oneway void close(in IBinder binder); - void setMiracastMode(int mode); - void checkConfigureWifiDisplayPermission(); -} - From a94c867fba73f470696156fa1ef81429904e8bff Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Wed, 23 Dec 2020 22:53:04 +0000 Subject: [PATCH 0854/1150] Migrate frameworks/base/wifi & frameworks/base/packages/OsuLogin Migrate to packages/modules/Wifi. This CL will be presubmit tested once migration is complete. This CL drops the code from frameworks/base/wifi and migrated to packages/modules/Wifi. Also adjusts visibility rules in frameworks/base/Android.bp Bug: 137323948 Test: TH Merged-In: I9031a37c84e17c2cf5c0552d1b33e8fd59216b92 Change-Id: I4ad80b1584f9f80dffed7786739b80f3aaf88cdc --- .../android/net/wifi/p2p/IWifiP2pManager.aidl | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl deleted file mode 100644 index bfdd45d9f9..0000000000 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p; - -import android.os.Messenger; - -/** - * Interface that WifiP2pService implements - * - * {@hide} - */ -interface IWifiP2pManager -{ - Messenger getMessenger(in IBinder binder); - Messenger getP2pStateMachineMessenger(); - oneway void close(in IBinder binder); - void setMiracastMode(int mode); - void checkConfigureWifiDisplayPermission(); -} - From bbbc041523437626ed6ec076534be0b1bc97f147 Mon Sep 17 00:00:00 2001 From: Baligh Uddin Date: Wed, 23 Dec 2020 23:18:44 +0000 Subject: [PATCH 0855/1150] Migrate frameworks/base/wifi & frameworks/base/packages/OsuLogin Migrate to packages/modules/Wifi. This CL will be presubmit tested once migration is complete. This CL drops the code from frameworks/base/wifi and migrated to packages/modules/Wifi. Also adjusts visibility rules in frameworks/base/Android.bp Bug: 137323948 Test: TH Merged-In: Id02e28648e922a30d6a81cf92b39eff4ca3cc002 Change-Id: I28e35cea55001c2333374c2342f496a0340f2f32 --- .../android/net/wifi/p2p/IWifiP2pManager.aidl | 34 ------------------- 1 file changed, 34 deletions(-) delete mode 100644 wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl diff --git a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl b/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl deleted file mode 100644 index bfdd45d9f9..0000000000 --- a/wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.p2p; - -import android.os.Messenger; - -/** - * Interface that WifiP2pService implements - * - * {@hide} - */ -interface IWifiP2pManager -{ - Messenger getMessenger(in IBinder binder); - Messenger getP2pStateMachineMessenger(); - oneway void close(in IBinder binder); - void setMiracastMode(int mode); - void checkConfigureWifiDisplayPermission(); -} - From b71ce2a04f1d315f07e128fd79a5868602961ebe Mon Sep 17 00:00:00 2001 From: Serik Beketayev Date: Sun, 6 Dec 2020 23:08:08 -0800 Subject: [PATCH 0856/1150] [Mainline] Migrate ProxyInfo Bug: 173455434 Test: atest FrameworksNetTests Change-Id: I924aed710b62a0c91b888a9e04ac2c90cdfd88d0 --- .../java/com/android/server/net/IpConfigStore.java | 11 +++++++---- .../src/com/android/server/net/IpConfigStoreTest.java | 4 +++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 9c5abd4706..cc3a002adc 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -30,6 +30,7 @@ import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.ProxyUtils; import java.io.BufferedInputStream; import java.io.DataInputStream; @@ -123,7 +124,8 @@ public class IpConfigStore { switch (config.proxySettings) { case STATIC: ProxyInfo proxyProperties = config.httpProxy; - String exclusionList = proxyProperties.getExclusionListAsString(); + String exclusionList = ProxyUtils.exclusionListAsString( + proxyProperties.getExclusionList()); out.writeUTF(PROXY_SETTINGS_KEY); out.writeUTF(config.proxySettings.toString()); out.writeUTF(PROXY_HOST_KEY); @@ -370,13 +372,14 @@ public class IpConfigStore { switch (proxySettings) { case STATIC: - ProxyInfo proxyInfo = - new ProxyInfo(proxyHost, proxyPort, exclusionList); + ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, + ProxyUtils.exclusionStringAsList(exclusionList)); config.proxySettings = proxySettings; config.httpProxy = proxyInfo; break; case PAC: - ProxyInfo proxyPacProperties = new ProxyInfo(Uri.parse(pacFileUrl)); + ProxyInfo proxyPacProperties = + ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); config.proxySettings = proxySettings; config.httpProxy = proxyPacProperties; break; diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java index 9d300a6113..401d6e30df 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -39,6 +39,7 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; /** * Unit tests for {@link IpConfigStore} @@ -82,7 +83,8 @@ public class IpConfigStoreTest { staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); - ProxyInfo proxyInfo = new ProxyInfo("10.10.10.10", 88, "host1,host2"); + ProxyInfo proxyInfo = + ProxyInfo.buildDirectProxy("10.10.10.10", 88, Arrays.asList("host1", "host2")); IpConfiguration expectedConfig1 = new IpConfiguration(IpAssignment.STATIC, ProxySettings.STATIC, staticIpConfiguration, proxyInfo); From 5520d9d6017e800e286af03dd93728977b862ff0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Mon, 4 Jan 2021 22:35:57 -0700 Subject: [PATCH 0857/1150] Pivot network statistics to use DataInput/Output. Using these generalized interfaces is more flexible, since it enables us to pivot the implementation being used internally. In particular, an upcoming CL will pivot them to use a more efficient alternative. This is a no-op refactoring. Bug: 176777285 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Ibd4717174cf1f136e9d5d80172ecb6e493265306 --- .../java/android/net/NetworkStatsHistory.java | 18 +++++++++--------- .../server/net/NetworkIdentitySet.java | 12 ++++++------ .../server/net/NetworkStatsCollection.java | 19 +++++++++++++------ .../server/net/NetworkStatsRecorder.java | 5 ++--- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index bf25602041..f41306301d 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -45,8 +45,8 @@ import com.android.internal.util.IndentingPrintWriter; import libcore.util.EmptyArray; import java.io.CharArrayWriter; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataInput; +import java.io.DataOutput; import java.io.IOException; import java.io.PrintWriter; import java.net.ProtocolException; @@ -162,7 +162,7 @@ public class NetworkStatsHistory implements Parcelable { out.writeLong(totalBytes); } - public NetworkStatsHistory(DataInputStream in) throws IOException { + public NetworkStatsHistory(DataInput in) throws IOException { final int version = in.readInt(); switch (version) { case VERSION_INIT: { @@ -204,7 +204,7 @@ public class NetworkStatsHistory implements Parcelable { } } - public void writeToStream(DataOutputStream out) throws IOException { + public void writeToStream(DataOutput out) throws IOException { out.writeInt(VERSION_ADD_ACTIVE); out.writeLong(bucketDuration); writeVarLongArray(out, bucketStart, bucketCount); @@ -768,7 +768,7 @@ public class NetworkStatsHistory implements Parcelable { */ public static class DataStreamUtils { @Deprecated - public static long[] readFullLongArray(DataInputStream in) throws IOException { + public static long[] readFullLongArray(DataInput in) throws IOException { final int size = in.readInt(); if (size < 0) throw new ProtocolException("negative array size"); final long[] values = new long[size]; @@ -781,7 +781,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Read variable-length {@link Long} using protobuf-style approach. */ - public static long readVarLong(DataInputStream in) throws IOException { + public static long readVarLong(DataInput in) throws IOException { int shift = 0; long result = 0; while (shift < 64) { @@ -797,7 +797,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Write variable-length {@link Long} using protobuf-style approach. */ - public static void writeVarLong(DataOutputStream out, long value) throws IOException { + public static void writeVarLong(DataOutput out, long value) throws IOException { while (true) { if ((value & ~0x7FL) == 0) { out.writeByte((int) value); @@ -809,7 +809,7 @@ public class NetworkStatsHistory implements Parcelable { } } - public static long[] readVarLongArray(DataInputStream in) throws IOException { + public static long[] readVarLongArray(DataInput in) throws IOException { final int size = in.readInt(); if (size == -1) return null; if (size < 0) throw new ProtocolException("negative array size"); @@ -820,7 +820,7 @@ public class NetworkStatsHistory implements Parcelable { return values; } - public static void writeVarLongArray(DataOutputStream out, long[] values, int size) + public static void writeVarLongArray(DataOutput out, long[] values, int size) throws IOException { if (values == null) { out.writeInt(-1); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index 2326ad39fd..bce80696f7 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -20,8 +20,8 @@ import android.net.NetworkIdentity; import android.service.NetworkIdentitySetProto; import android.util.proto.ProtoOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; +import java.io.DataInput; +import java.io.DataOutput; import java.io.IOException; import java.util.HashSet; @@ -44,7 +44,7 @@ public class NetworkIdentitySet extends HashSet implements public NetworkIdentitySet() { } - public NetworkIdentitySet(DataInputStream in) throws IOException { + public NetworkIdentitySet(DataInput in) throws IOException { final int version = in.readInt(); final int size = in.readInt(); for (int i = 0; i < size; i++) { @@ -89,7 +89,7 @@ public class NetworkIdentitySet extends HashSet implements } } - public void writeToStream(DataOutputStream out) throws IOException { + public void writeToStream(DataOutput out) throws IOException { out.writeInt(VERSION_ADD_DEFAULT_NETWORK); out.writeInt(size()); for (NetworkIdentity ident : this) { @@ -143,7 +143,7 @@ public class NetworkIdentitySet extends HashSet implements return true; } - private static void writeOptionalString(DataOutputStream out, String value) throws IOException { + private static void writeOptionalString(DataOutput out, String value) throws IOException { if (value != null) { out.writeByte(1); out.writeUTF(value); @@ -152,7 +152,7 @@ public class NetworkIdentitySet extends HashSet implements } } - private static String readOptionalString(DataInputStream in) throws IOException { + private static String readOptionalString(DataInput in) throws IOException { if (in.readByte() != 0) { return in.readUTF(); } else { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index c4beddd42e..6aefe41891 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -63,12 +63,15 @@ import com.google.android.collect.Lists; import com.google.android.collect.Maps; import java.io.BufferedInputStream; +import java.io.DataInput; import java.io.DataInputStream; +import java.io.DataOutput; import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.PrintWriter; import java.net.ProtocolException; import java.time.ZonedDateTime; @@ -82,7 +85,7 @@ import java.util.Objects; * Collection of {@link NetworkStatsHistory}, stored based on combined key of * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. */ -public class NetworkStatsCollection implements FileRotator.Reader { +public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; @@ -431,10 +434,10 @@ public class NetworkStatsCollection implements FileRotator.Reader { @Override public void read(InputStream in) throws IOException { - read(new DataInputStream(in)); + read((DataInput) new DataInputStream(in)); } - public void read(DataInputStream in) throws IOException { + private void read(DataInput in) throws IOException { // verify file magic header intact final int magic = in.readInt(); if (magic != FILE_MAGIC) { @@ -468,7 +471,13 @@ public class NetworkStatsCollection implements FileRotator.Reader { } } - public void write(DataOutputStream out) throws IOException { + @Override + public void write(OutputStream out) throws IOException { + write((DataOutput) new DataOutputStream(out)); + out.flush(); + } + + private void write(DataOutput out) throws IOException { // cluster key lists grouped by ident final HashMap> keysByIdent = Maps.newHashMap(); for (Key key : mStats.keySet()) { @@ -497,8 +506,6 @@ public class NetworkStatsCollection implements FileRotator.Reader { history.writeToStream(out); } } - - out.flush(); } @Deprecated diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java index ce741693cb..978ae87d39 100644 --- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java +++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java @@ -42,7 +42,6 @@ import com.google.android.collect.Sets; import libcore.io.IoUtils; import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -375,7 +374,7 @@ public class NetworkStatsRecorder { @Override public void write(OutputStream out) throws IOException { - mCollection.write(new DataOutputStream(out)); + mCollection.write(out); mCollection.reset(); } } @@ -412,7 +411,7 @@ public class NetworkStatsRecorder { @Override public void write(OutputStream out) throws IOException { - mTemp.write(new DataOutputStream(out)); + mTemp.write(out); } } From 4715a5c3820451e4f4adb604d8929aa66873c53f Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 3 Dec 2020 17:08:29 -0800 Subject: [PATCH 0858/1150] Expose IPsec tunnel APIs from @SystemApi to public APIs Since IKE APIs to negotiate IPsec tunnel migration (MOBIKE) are public, all IPsec tunnel APIs should also be public so that public callers are able to create, manage and migrate IPsec tunnels Bug: 174606949 Test: atest IpSecManagerTunnelTest Change-Id: I86aec334cfc937953f9c2b411cc55862032aae4d --- core/java/android/net/IpSecManager.java | 93 +++++++++++++++++-------- 1 file changed, 65 insertions(+), 28 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index d83715c692..b6ae7ecfdb 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -705,7 +705,7 @@ public final class IpSecManager { } /** - * This class represents an IpSecTunnelInterface + * This class represents an IpSecTunnelInterface. * *

            IpSecTunnelInterface objects track tunnel interfaces that serve as * local endpoints for IPsec tunnels. @@ -714,9 +714,7 @@ public final class IpSecManager { * applied to provide IPsec security to packets sent through the tunnel. While a tunnel * cannot be used in standalone mode within Android, the higher layers may use the tunnel * to create Network objects which are accessible to the Android system. - * @hide */ - @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { private final String mOpPackageName; private final IIpSecService mService; @@ -727,23 +725,26 @@ public final class IpSecManager { private String mInterfaceName; private int mResourceId = INVALID_RESOURCE_ID; - /** Get the underlying SPI held by this object. */ + /** + * Get the underlying SPI held by this object. + * + * @hide + */ + @SystemApi @NonNull public String getInterfaceName() { return mInterfaceName; } /** - * Add an address to the IpSecTunnelInterface + * Add an address to the IpSecTunnelInterface. * *

            Add an address which may be used as the local inner address for * tunneled traffic. * * @param address the local address for traffic inside the tunnel * @param prefixLen length of the InetAddress prefix - * @hide */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -758,15 +759,13 @@ public final class IpSecManager { } /** - * Remove an address from the IpSecTunnelInterface + * Remove an address from the IpSecTunnelInterface. * - *

            Remove an address which was previously added to the IpSecTunnelInterface + *

            Remove an address which was previously added to the IpSecTunnelInterface. * * @param address to be removed * @param prefixLen length of the InetAddress prefix - * @hide */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -817,7 +816,7 @@ public final class IpSecManager { } /** - * Delete an IpSecTunnelInterface + * Delete an IpSecTunnelInterface. * *

            Calling close will deallocate the IpSecTunnelInterface and all of its system * resources. Any packets bound for this interface either inbound or outbound will @@ -839,7 +838,12 @@ public final class IpSecManager { } } - /** Check that the Interface was closed properly. */ + + /** + * Check that the Interface was closed properly. + * + * @hide + */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -871,17 +875,52 @@ public final class IpSecManager { * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. * *

            An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network goes away, and the onLost() callback is received. + * underlying network disconnects, and the {@link + * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. * - * @param localAddress The local addres of the tunnel - * @param remoteAddress The local addres of the tunnel - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. - * This network should almost certainly be a network such as WiFi with an L2 address. - * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the socket could not be opened or bound - * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open - * @hide + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets + * that go through the tunnel will need a underlying network to transit to the IPsec peer. + * This network should almost certainly be a physical network such as WiFi. + * @return a new {@link IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the tunnel could not be created due to a lower-layer + * error + * @throws ResourceUnavailableException indicating that the number of opening tunnels has + * reached the limit. */ + @NonNull + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork) + throws ResourceUnavailableException, IOException { + + // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link + // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be + // safely removed. + final InetAddress address = InetAddress.getLocalHost(); + return createIpSecTunnelInterface(address, address, underlyingNetwork); + } + + /** + * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. + * + *

            An application that creates tunnels is responsible for cleaning up the tunnel when the + * underlying network disconnects, and the {@link + * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. + * + * @param localAddress The local address of the tunnel + * @param remoteAddress The local address of the tunnel + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets + * that go through the tunnel will need a underlying network to transit to the IPsec peer. + * This network should almost certainly be a physical network such as WiFi. + * @return a new {@link IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the tunnel could not be created due to a lower-layer + * error + * @throws ResourceUnavailableException indicating that the number of opening tunnels has + * reached the limit. + * @hide + * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)} + */ + @Deprecated @SystemApi @NonNull @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @@ -905,16 +944,14 @@ public final class IpSecManager { *

            Applications should probably not use this API directly. * * - * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied + * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied * transform. - * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which + * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which * the transform will be used. * @param transform an {@link IpSecTransform} created in tunnel mode - * @throws IOException indicating that the transform could not be applied due to a lower - * layer failure. - * @hide + * @throws IOException indicating that the transform could not be applied due to a lower-layer + * error */ - @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, From e42fc5ff7624e666dbe8d067eb7b0be11161aaa6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 8 Jan 2021 20:22:27 +0800 Subject: [PATCH 0859/1150] [FUI14] Get SSID from NetworkCapabilities This allows subsequent patches to remove the need of exposing SSID in NetworkState. Test: atest NetworkStatsServiceTest Bug: 174123988 Change-Id: Ib9ab07c9610954c9a5de035a3aefbf6d0bb0b53b --- core/java/android/net/NetworkIdentity.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index a0dc72d4ad..b644ed56ad 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -194,13 +194,15 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; if (type == TYPE_WIFI) { - if (state.networkId != null) { - networkId = state.networkId; - } else { - final WifiManager wifi = (WifiManager) context.getSystemService( - Context.WIFI_SERVICE); - final WifiInfo info = wifi.getConnectionInfo(); - networkId = info != null ? info.getSSID() : null; + if (state.networkCapabilities.getSsid() != null) { + networkId = state.networkCapabilities.getSsid(); + if (networkId == null) { + // TODO: Figure out if this code path never runs. If so, remove them. + final WifiManager wifi = (WifiManager) context.getSystemService( + Context.WIFI_SERVICE); + final WifiInfo info = wifi.getConnectionInfo(); + networkId = info != null ? info.getSSID() : null; + } } } From 2fe9a7247542f7d4ab8f2d09beaf69af261dcab2 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Tue, 12 Jan 2021 18:48:13 +0800 Subject: [PATCH 0860/1150] Expose UdpEncapsulationSocket.getResourceId() ConnectivityManager.createSocketKeepalive() will need to get the socket resource ID as a parameter for creating a new NattSocketKeepalive. ConnectivityManager is a part of incoming ConnectivityService mainline, so expose getResourceId() as an API since the hidden APIs are not accessible for a mainline module. This API should not be exposed to apps, so make it a MODULE_LIBRARIES system API. Bug: 172183305 Test: make update-api Change-Id: Ic0722352ea186fcb18a2d91cc3969f771fde9e86 --- core/java/android/net/IpSecManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b6ae7ecfdb..60923f5ea8 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -15,6 +15,8 @@ */ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -628,7 +630,7 @@ public final class IpSecManager { } /** @hide */ - @VisibleForTesting + @SystemApi(client = MODULE_LIBRARIES) public int getResourceId() { return mResourceId; } From c9983ee71c5071d6bdbff5ba893298924e0a5bae Mon Sep 17 00:00:00 2001 From: junyulai Date: Sat, 23 Jan 2021 01:09:11 +0800 Subject: [PATCH 0861/1150] [FUI03] No-op refactoring of VpnInfo As a preparation of exposing system API. This patch does some harmless refactoring, which includes: 1. Move VpnInfo to android.net 2. Add nullability annotations 3. Make members final Bug: 174123988 Test: TH Change-Id: I1530bb45d0e84c28c6deac33596bc686058afc0d --- core/java/android/net/INetworkStatsService.aidl | 2 +- core/java/{com/android/internal => android}/net/VpnInfo.aidl | 2 +- .../core/java/com/android/server/net/NetworkStatsFactory.java | 2 +- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename core/java/{com/android/internal => android}/net/VpnInfo.aidl (94%) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 1a3dc97448..d5aede7101 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,11 +23,11 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; +import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; import android.os.Messenger; -import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { diff --git a/core/java/com/android/internal/net/VpnInfo.aidl b/core/java/android/net/VpnInfo.aidl similarity index 94% rename from core/java/com/android/internal/net/VpnInfo.aidl rename to core/java/android/net/VpnInfo.aidl index 6fc97be409..8bcaa81f39 100644 --- a/core/java/com/android/internal/net/VpnInfo.aidl +++ b/core/java/android/net/VpnInfo.aidl @@ -14,6 +14,6 @@ * limitations under the License. */ -package com.android.internal.net; +package android.net; parcelable VpnInfo; diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index e9868fde30..4faa7903c6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -27,6 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; import android.net.INetd; import android.net.NetworkStats; +import android.net.VpnInfo; import android.net.util.NetdService; import android.os.RemoteException; import android.os.StrictMode; @@ -34,7 +35,6 @@ import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 81a6641de8..4be7b483af 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -105,6 +105,7 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.net.Uri; +import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; @@ -143,7 +144,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; From 6a1f216c0efe24f17c087ee9f6c51ec400294ed9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sat, 23 Jan 2021 09:46:34 +0800 Subject: [PATCH 0862/1150] [FUI04] Refactor VpnInfo As a preparation of exposing system API. This patch does some harmless refactoring, which includes: 1. Change raw arrays into lists according to API guidelines. 2. Write test. 3. Rename class to UnderlyingNetworkInfo. 4. Rename vpnIface to iface. 5. Make underlyingIfaces @NonNull in order to adapt new unparceling code. 6. implement equals and hashCode for testing. Test: atest android.net.UnderlyingNetworkInfoTest Bug: 174123988 Change-Id: I405c21e57c4af8a12a9dd0a1749b9e6690f87045 --- .../android/net/INetworkStatsService.aidl | 4 +- ...pnInfo.aidl => UnderlyingNetworkInfo.aidl} | 2 +- .../android/net/UnderlyingNetworkInfo.java | 110 ++++++++++++++++++ .../server/net/NetworkStatsFactory.java | 19 +-- .../server/net/NetworkStatsService.java | 6 +- 5 files changed, 126 insertions(+), 15 deletions(-) rename core/java/android/net/{VpnInfo.aidl => UnderlyingNetworkInfo.aidl} (94%) create mode 100644 core/java/android/net/UnderlyingNetworkInfo.java diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index d5aede7101..0baf11e850 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -23,7 +23,7 @@ import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.net.VpnInfo; +import android.net.UnderlyingNetworkInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; @@ -70,7 +70,7 @@ interface INetworkStatsService { in Network[] defaultNetworks, in NetworkState[] networkStates, in String activeIface, - in VpnInfo[] vpnInfos); + in UnderlyingNetworkInfo[] underlyingNetworkInfos); /** Force update of statistics. */ @UnsupportedAppUsage void forceUpdate(); diff --git a/core/java/android/net/VpnInfo.aidl b/core/java/android/net/UnderlyingNetworkInfo.aidl similarity index 94% rename from core/java/android/net/VpnInfo.aidl rename to core/java/android/net/UnderlyingNetworkInfo.aidl index 8bcaa81f39..a56f2f4058 100644 --- a/core/java/android/net/VpnInfo.aidl +++ b/core/java/android/net/UnderlyingNetworkInfo.aidl @@ -16,4 +16,4 @@ package android.net; -parcelable VpnInfo; +parcelable UnderlyingNetworkInfo; diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java new file mode 100644 index 0000000000..8fb4832e06 --- /dev/null +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * A lightweight container used to carry information on the networks that underly a given + * virtual network. + * + * @hide + */ +public final class UnderlyingNetworkInfo implements Parcelable { + /** The owner of this network. */ + public final int ownerUid; + /** The interface name of this network. */ + @NonNull + public final String iface; + /** The names of the interfaces underlying this network. */ + @NonNull + public final List underlyingIfaces; + + public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, + @NonNull List underlyingIfaces) { + Objects.requireNonNull(iface); + Objects.requireNonNull(underlyingIfaces); + this.ownerUid = ownerUid; + this.iface = iface; + this.underlyingIfaces = underlyingIfaces; + } + + private UnderlyingNetworkInfo(@NonNull Parcel in) { + this.ownerUid = in.readInt(); + this.iface = in.readString(); + this.underlyingIfaces = new ArrayList<>(); + in.readList(this.underlyingIfaces, null /*classLoader*/); + } + + @Override + public String toString() { + return "UnderlyingNetworkInfo{" + + "ownerUid=" + ownerUid + + ", iface='" + iface + '\'' + + ", underlyingIfaces='" + underlyingIfaces.toString() + '\'' + + '}'; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(ownerUid); + dest.writeString(iface); + dest.writeList(underlyingIfaces); + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @NonNull + @Override + public UnderlyingNetworkInfo createFromParcel(@NonNull Parcel in) { + return new UnderlyingNetworkInfo(in); + } + + @NonNull + @Override + public UnderlyingNetworkInfo[] newArray(int size) { + return new UnderlyingNetworkInfo[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof UnderlyingNetworkInfo)) return false; + final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; + return ownerUid == that.ownerUid + && Objects.equals(iface, that.iface) + && Objects.equals(underlyingIfaces, that.underlyingIfaces); + } + + @Override + public int hashCode() { + return Objects.hash(ownerUid, iface, underlyingIfaces); + } +} diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 4faa7903c6..d042b882fe 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -27,7 +27,7 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.Nullable; import android.net.INetd; import android.net.NetworkStats; -import android.net.VpnInfo; +import android.net.UnderlyingNetworkInfo; import android.net.util.NetdService; import android.os.RemoteException; import android.os.StrictMode; @@ -81,7 +81,7 @@ public class NetworkStatsFactory { private final Object mPersistentDataLock = new Object(); /** Set containing info about active VPNs and their underlying networks. */ - private volatile VpnInfo[] mVpnInfos = new VpnInfo[0]; + private volatile UnderlyingNetworkInfo[] mUnderlyingNetworkInfos = new UnderlyingNetworkInfo[0]; // A persistent snapshot of cumulative stats since device start @GuardedBy("mPersistentDataLock") @@ -116,8 +116,8 @@ public class NetworkStatsFactory { * * @param vpnArray The snapshot of the currently-running VPNs. */ - public void updateVpnInfos(VpnInfo[] vpnArray) { - mVpnInfos = vpnArray.clone(); + public void updateUnderlyingNetworkInfos(UnderlyingNetworkInfo[] vpnArray) { + mUnderlyingNetworkInfos = vpnArray.clone(); } /** @@ -319,7 +319,7 @@ public class NetworkStatsFactory { // code that will acquire other locks within the system server. See b/134244752. synchronized (mPersistentDataLock) { // Take a reference. If this gets swapped out, we still have the old reference. - final VpnInfo[] vpnArray = mVpnInfos; + final UnderlyingNetworkInfo[] vpnArray = mUnderlyingNetworkInfos; // Take a defensive copy. mPersistSnapshot is mutated in some cases below final NetworkStats prev = mPersistSnapshot.clone(); @@ -369,8 +369,8 @@ public class NetworkStatsFactory { } @GuardedBy("mPersistentDataLock") - private NetworkStats adjustForTunAnd464Xlat( - NetworkStats uidDetailStats, NetworkStats previousStats, VpnInfo[] vpnArray) { + private NetworkStats adjustForTunAnd464Xlat(NetworkStats uidDetailStats, + NetworkStats previousStats, UnderlyingNetworkInfo[] vpnArray) { // Calculate delta from last snapshot final NetworkStats delta = uidDetailStats.subtract(previousStats); @@ -381,8 +381,9 @@ public class NetworkStatsFactory { delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. - for (VpnInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.vpnIface, info.underlyingIfaces); + for (UnderlyingNetworkInfo info : vpnArray) { + delta.migrateTun(info.ownerUid, info.iface, + info.underlyingIfaces.toArray(new String[0])); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4be7b483af..0ab35a9110 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -104,8 +104,8 @@ import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; +import android.net.UnderlyingNetworkInfo; import android.net.Uri; -import android.net.VpnInfo; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; @@ -973,7 +973,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Network[] defaultNetworks, NetworkState[] networkStates, String activeIface, - VpnInfo[] vpnInfos) { + UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); @@ -986,7 +986,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Update the VPN underlying interfaces only after the poll is made and tun data has been // migrated. Otherwise the migration would use the new interfaces instead of the ones that // were current when the polled data was transferred. - mStatsFactory.updateVpnInfos(vpnInfos); + mStatsFactory.updateUnderlyingNetworkInfos(underlyingNetworkInfos); } @Override From a60efcc095d51dfe5c7be87c9b0894c445828d96 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Fri, 15 Jan 2021 18:08:24 +0900 Subject: [PATCH 0863/1150] Move module sources to packages/Connectivity Files that are planned to be part of the connectivity module are grouped in packages/Connectivity, so they can be built separately and moved in one operation with their history into packages/modules/Connectivity. This places the files in the existing framework-connectivity-sources filegroup instead of the current framework-core-sources filegroup. Both are used the same way in framework-non-updatable-sources. Bug: 171540887 Test: m Change-Id: I62d9d91574ace6f5c4624035d190260c3126b91e --- core/java/android/net/UidRange.aidl | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl deleted file mode 100644 index f70fc8e2fe..0000000000 --- a/core/java/android/net/UidRange.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * An inclusive range of UIDs. - * - * {@hide} - */ -parcelable UidRange; \ No newline at end of file From c35b88591b6c1d430c280d5b4efe3d10730c6952 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 1 Feb 2021 08:12:34 +0000 Subject: [PATCH 0864/1150] Revert "Expose IPsec tunnel APIs from @SystemApi to public APIs" This reverts commit 4715a5c3820451e4f4adb604d8929aa66873c53f. Reason for revert: not necessary, since VCN already has access to system APIs Bug: 174606949 Test: revert with no conflicts Change-Id: Ife2d0fc08c540265d52cdf930d0b6df005990ac8 --- core/java/android/net/IpSecManager.java | 91 ++++++++----------------- 1 file changed, 27 insertions(+), 64 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index b6ae7ecfdb..d83715c692 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -705,7 +705,7 @@ public final class IpSecManager { } /** - * This class represents an IpSecTunnelInterface. + * This class represents an IpSecTunnelInterface * *

            IpSecTunnelInterface objects track tunnel interfaces that serve as * local endpoints for IPsec tunnels. @@ -714,7 +714,9 @@ public final class IpSecManager { * applied to provide IPsec security to packets sent through the tunnel. While a tunnel * cannot be used in standalone mode within Android, the higher layers may use the tunnel * to create Network objects which are accessible to the Android system. + * @hide */ + @SystemApi public static final class IpSecTunnelInterface implements AutoCloseable { private final String mOpPackageName; private final IIpSecService mService; @@ -725,26 +727,23 @@ public final class IpSecManager { private String mInterfaceName; private int mResourceId = INVALID_RESOURCE_ID; - /** - * Get the underlying SPI held by this object. - * - * @hide - */ - @SystemApi + /** Get the underlying SPI held by this object. */ @NonNull public String getInterfaceName() { return mInterfaceName; } /** - * Add an address to the IpSecTunnelInterface. + * Add an address to the IpSecTunnelInterface * *

            Add an address which may be used as the local inner address for * tunneled traffic. * * @param address the local address for traffic inside the tunnel * @param prefixLen length of the InetAddress prefix + * @hide */ + @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void addAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -759,13 +758,15 @@ public final class IpSecManager { } /** - * Remove an address from the IpSecTunnelInterface. + * Remove an address from the IpSecTunnelInterface * - *

            Remove an address which was previously added to the IpSecTunnelInterface. + *

            Remove an address which was previously added to the IpSecTunnelInterface * * @param address to be removed * @param prefixLen length of the InetAddress prefix + * @hide */ + @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void removeAddress(@NonNull InetAddress address, int prefixLen) throws IOException { @@ -816,7 +817,7 @@ public final class IpSecManager { } /** - * Delete an IpSecTunnelInterface. + * Delete an IpSecTunnelInterface * *

            Calling close will deallocate the IpSecTunnelInterface and all of its system * resources. Any packets bound for this interface either inbound or outbound will @@ -838,12 +839,7 @@ public final class IpSecManager { } } - - /** - * Check that the Interface was closed properly. - * - * @hide - */ + /** Check that the Interface was closed properly. */ @Override protected void finalize() throws Throwable { if (mCloseGuard != null) { @@ -875,52 +871,17 @@ public final class IpSecManager { * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. * *

            An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network disconnects, and the {@link - * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. + * underlying network goes away, and the onLost() callback is received. * - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets - * that go through the tunnel will need a underlying network to transit to the IPsec peer. - * This network should almost certainly be a physical network such as WiFi. - * @return a new {@link IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the tunnel could not be created due to a lower-layer - * error - * @throws ResourceUnavailableException indicating that the number of opening tunnels has - * reached the limit. - */ - @NonNull - @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) - @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) - public IpSecTunnelInterface createIpSecTunnelInterface(@NonNull Network underlyingNetwork) - throws ResourceUnavailableException, IOException { - - // TODO: Remove the need for adding two unused addresses with IPsec tunnels when {@link - // #createIpSecTunnelInterface(localAddress, remoteAddress, underlyingNetwork)} can be - // safely removed. - final InetAddress address = InetAddress.getLocalHost(); - return createIpSecTunnelInterface(address, address, underlyingNetwork); - } - - /** - * Create a new IpSecTunnelInterface as a local endpoint for tunneled IPsec traffic. - * - *

            An application that creates tunnels is responsible for cleaning up the tunnel when the - * underlying network disconnects, and the {@link - * ConnectivityManager.NetworkCallback#onLost(Network)} callback is received. - * - * @param localAddress The local address of the tunnel - * @param remoteAddress The local address of the tunnel - * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. Packets - * that go through the tunnel will need a underlying network to transit to the IPsec peer. - * This network should almost certainly be a physical network such as WiFi. - * @return a new {@link IpSecTunnelInterface} with the specified properties - * @throws IOException indicating that the tunnel could not be created due to a lower-layer - * error - * @throws ResourceUnavailableException indicating that the number of opening tunnels has - * reached the limit. + * @param localAddress The local addres of the tunnel + * @param remoteAddress The local addres of the tunnel + * @param underlyingNetwork the {@link Network} that will carry traffic for this tunnel. + * This network should almost certainly be a network such as WiFi with an L2 address. + * @return a new {@link IpSecManager#IpSecTunnelInterface} with the specified properties + * @throws IOException indicating that the socket could not be opened or bound + * @throws ResourceUnavailableException indicating that too many encapsulation sockets are open * @hide - * @deprecated Callers should use {@link #createIpSecTunnelInterface(Network)} */ - @Deprecated @SystemApi @NonNull @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @@ -944,14 +905,16 @@ public final class IpSecManager { *

            Applications should probably not use this API directly. * * - * @param tunnel The {@link IpSecTunnelInterface} that will use the supplied + * @param tunnel The {@link IpSecManager#IpSecTunnelInterface} that will use the supplied * transform. - * @param direction the direction, {@link #DIRECTION_OUT} or {@link #DIRECTION_IN} in which + * @param direction the direction, {@link DIRECTION_OUT} or {@link #DIRECTION_IN} in which * the transform will be used. * @param transform an {@link IpSecTransform} created in tunnel mode - * @throws IOException indicating that the transform could not be applied due to a lower-layer - * error + * @throws IOException indicating that the transform could not be applied due to a lower + * layer failure. + * @hide */ + @SystemApi @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) public void applyTunnelModeTransform(@NonNull IpSecTunnelInterface tunnel, From 614515339cfa515881d047d69f47ef36dcd647d1 Mon Sep 17 00:00:00 2001 From: junyulai Date: Thu, 28 Jan 2021 21:19:32 +0800 Subject: [PATCH 0865/1150] [FUI20] Expose UnderlyingNetworkInfo as system Api Test: atest android.net.UnderlyingNetworkInfoTest Bug: 174123988 Change-Id: Id602fbe744669f472d27fb466d00dcc601bd8f17 --- core/java/android/net/UnderlyingNetworkInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 8fb4832e06..7bf9231239 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -16,11 +16,15 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Objects; @@ -30,6 +34,7 @@ import java.util.Objects; * * @hide */ +@SystemApi(client = MODULE_LIBRARIES) public final class UnderlyingNetworkInfo implements Parcelable { /** The owner of this network. */ public final int ownerUid; @@ -46,7 +51,7 @@ public final class UnderlyingNetworkInfo implements Parcelable { Objects.requireNonNull(underlyingIfaces); this.ownerUid = ownerUid; this.iface = iface; - this.underlyingIfaces = underlyingIfaces; + this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); } private UnderlyingNetworkInfo(@NonNull Parcel in) { From 00a5b7f75255ba88e479429c99e362b87e734662 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 29 Jan 2021 20:20:15 +0800 Subject: [PATCH 0866/1150] [FUI21] Move scrubSubscriberId to utils class This patch also removes the functionality of returning original subscriberId in eng build since it is not really useful. Test: atest NetworkIdentityUtilsTest Bug: 174123988 Change-Id: I721457e571aa9403a2200b3e4261b4895e4f7a3e --- .../app/usage/NetworkStatsManager.java | 4 +-- core/java/android/net/NetworkIdentity.java | 35 ++++--------------- core/java/android/net/NetworkTemplate.java | 5 +-- 3 files changed, 11 insertions(+), 33 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1ddfe0d247..1d5dc1d5df 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -28,7 +28,6 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; -import android.net.NetworkIdentity; import android.net.NetworkStack; import android.net.NetworkTemplate; import android.net.netstats.provider.INetworkStatsProviderCallback; @@ -47,6 +46,7 @@ import android.util.DataUnit; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.NetworkIdentityUtils; import java.util.Objects; @@ -628,7 +628,7 @@ public class NetworkStatsManager { default: throw new IllegalArgumentException("Cannot create template for network type " + networkType + ", subscriberId '" - + NetworkIdentity.scrubSubscriberId(subscriberId) + "'."); + + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + "'."); } return template; } diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b644ed56ad..521ed9b194 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -21,11 +21,12 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; -import android.os.Build; import android.service.NetworkIdentityProto; import android.telephony.Annotation.NetworkType; import android.util.proto.ProtoOutputStream; +import com.android.net.module.util.NetworkIdentityUtils; + import java.util.Objects; /** @@ -89,7 +90,8 @@ public class NetworkIdentity implements Comparable { builder.append(mSubType); } if (mSubscriberId != null) { - builder.append(", subscriberId=").append(scrubSubscriberId(mSubscriberId)); + builder.append(", subscriberId=") + .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); @@ -110,7 +112,8 @@ public class NetworkIdentity implements Comparable { // Not dumping mSubType, subtypes are no longer supported. if (mSubscriberId != null) { - proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId)); + proto.write(NetworkIdentityProto.SUBSCRIBER_ID, + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); } proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); proto.write(NetworkIdentityProto.ROAMING, mRoaming); @@ -148,32 +151,6 @@ public class NetworkIdentity implements Comparable { return mDefaultNetwork; } - /** - * Scrub given IMSI on production builds. - */ - public static String scrubSubscriberId(String subscriberId) { - if (Build.IS_ENG) { - return subscriberId; - } else if (subscriberId != null) { - // TODO: parse this as MCC+MNC instead of hard-coding - return subscriberId.substring(0, Math.min(6, subscriberId.length())) + "..."; - } else { - return "null"; - } - } - - /** - * Scrub given IMSI on production builds. - */ - public static String[] scrubSubscriberId(String[] subscriberId) { - if (subscriberId == null) return null; - final String[] res = new String[subscriberId.length]; - for (int i = 0; i < res.length; i++) { - res[i] = NetworkIdentity.scrubSubscriberId(subscriberId[i]); - } - return res; - } - /** * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, * assuming that any mobile networks are using the current IMSI. The subType if applicable, diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 72be835a1c..2322048708 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -48,6 +48,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.net.module.util.NetworkIdentityUtils; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; @@ -296,11 +297,11 @@ public class NetworkTemplate implements Parcelable { builder.append("matchRule=").append(getMatchRuleName(mMatchRule)); if (mSubscriberId != null) { builder.append(", subscriberId=").append( - NetworkIdentity.scrubSubscriberId(mSubscriberId)); + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); } if (mMatchSubscriberIds != null) { builder.append(", matchSubscriberIds=").append( - Arrays.toString(NetworkIdentity.scrubSubscriberId(mMatchSubscriberIds))); + Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); } if (mNetworkId != null) { builder.append(", networkId=").append(mNetworkId); From 3088c8fab8d3e73901eaa172ad5941323c5daf7e Mon Sep 17 00:00:00 2001 From: Roman Kalukiewicz Date: Wed, 14 Oct 2020 15:59:06 -0700 Subject: [PATCH 0867/1150] Add @Nullable to Object#equals() This is a partial cherry-pick of change: I5eedb571c9d78862115dfdc5dae1cf2a35343580 for connectivity classes. Bug: 170883422 Test: m Merged-In: I5eedb571c9d78862115dfdc5dae1cf2a35343580 Change-Id: I7dc661863b73f4198ddb4f3a1566583d0f07db3c --- core/java/android/net/DataUsageRequest.java | 3 ++- core/java/android/net/IpSecTransform.java | 3 ++- core/java/android/net/NetworkIdentity.java | 3 ++- core/java/android/net/NetworkStats.java | 2 +- core/java/android/net/NetworkTemplate.java | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/DataUsageRequest.java b/core/java/android/net/DataUsageRequest.java index 0ac8f7e794..b06d515b3a 100644 --- a/core/java/android/net/DataUsageRequest.java +++ b/core/java/android/net/DataUsageRequest.java @@ -16,6 +16,7 @@ package android.net; +import android.annotation.Nullable; import android.net.NetworkTemplate; import android.os.Parcel; import android.os.Parcelable; @@ -95,7 +96,7 @@ public final class DataUsageRequest implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof DataUsageRequest == false) return false; DataUsageRequest that = (DataUsageRequest) obj; return that.requestId == this.requestId diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java index aa7811a3a1..b48c1fdaf1 100644 --- a/core/java/android/net/IpSecTransform.java +++ b/core/java/android/net/IpSecTransform.java @@ -19,6 +19,7 @@ import static android.net.IpSecManager.INVALID_RESOURCE_ID; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; @@ -150,7 +151,7 @@ public final class IpSecTransform implements AutoCloseable { /** * Standard equals. */ - public boolean equals(Object other) { + public boolean equals(@Nullable Object other) { if (this == other) return true; if (!(other instanceof IpSecTransform)) return false; final IpSecTransform rhs = (IpSecTransform) other; diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 521ed9b194..5d8122b6ce 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; +import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; @@ -67,7 +68,7 @@ public class NetworkIdentity implements Comparable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index cf40ce58d4..d42beae601 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -412,7 +412,7 @@ public final class NetworkStats implements Parcelable { /** @hide */ @Override - public boolean equals(Object o) { + public boolean equals(@Nullable Object o) { if (o instanceof Entry) { final Entry e = (Entry) o; return uid == e.uid && set == e.set && tag == e.tag && metered == e.metered diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 2322048708..aa61e03b28 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -329,7 +329,7 @@ public class NetworkTemplate implements Parcelable { } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof NetworkTemplate) { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule From 0fc5576b55133003597006766b2a722e2b03c384 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Wed, 3 Feb 2021 23:59:45 +0800 Subject: [PATCH 0868/1150] Use NetdUtils instead of NetworkManagementService in IpSecService NetdUtils has the same method(e.g. setInterfaceUp) as NetworkManagementService so using the one inside NetdUtils instead and try to remove NetworkManagementService from IpSecService in the following commit. Bug: 170598012 Test: atest FrameworksNetTests Change-Id: I0ed8b0c678b067a655b51b938b6b40eadd985321 --- services/core/java/com/android/server/IpSecService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index f648c3e146..b35091b5f2 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -62,6 +62,7 @@ import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.net.module.util.NetdUtils; import libcore.io.IoUtils; @@ -1317,7 +1318,7 @@ public class IpSecService extends IIpSecService.Stub { netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); Binder.withCleanCallingIdentity(() -> { - mNetworkManager.setInterfaceUp(intfName); + NetdUtils.setInterfaceUp(netd, intfName); }); for (int selAddrFamily : ADDRESS_FAMILIES) { From 2af9ad4065450641b8825d1c505bd3cde6879b4c Mon Sep 17 00:00:00 2001 From: lucaslin Date: Mon, 18 Jan 2021 13:06:39 +0800 Subject: [PATCH 0869/1150] Remove unused INetworkManagementService from IpSecService IpSecService is no longer using any methods of INetworkManagementService, so remove it from IpSecService and related files. Bug: 170598012 Test: atest FrameworksNetTests Change-Id: I852e3a534e0ffd26b4b22420754f3ec8a6f153ad --- .../java/com/android/server/IpSecService.java | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index b35091b5f2..2789f5f26d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -46,7 +46,6 @@ import android.net.TrafficStats; import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -116,9 +115,6 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; - /* NetworkManager instance */ - private final INetworkManagementService mNetworkManager; - /** * The next non-repeating global ID for tracking resources between users, this service, and * kernel data structures. Accessing this variable is not thread safe, so it is only read or @@ -997,13 +993,13 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context, INetworkManagementService networkManager) { - this(context, networkManager, IpSecServiceConfiguration.GETSRVINSTANCE); + private IpSecService(Context context) { + this(context, IpSecServiceConfiguration.GETSRVINSTANCE); } - static IpSecService create(Context context, INetworkManagementService networkManager) + static IpSecService create(Context context) throws InterruptedException { - final IpSecService service = new IpSecService(context, networkManager); + final IpSecService service = new IpSecService(context); service.connectNativeNetdService(); return service; } @@ -1017,11 +1013,9 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, INetworkManagementService networkManager, - IpSecServiceConfiguration config) { + public IpSecService(Context context, IpSecServiceConfiguration config) { this( context, - networkManager, config, (fd, uid) -> { try { @@ -1035,10 +1029,9 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, INetworkManagementService networkManager, - IpSecServiceConfiguration config, UidFdTagger uidFdTagger) { + public IpSecService(Context context, IpSecServiceConfiguration config, + UidFdTagger uidFdTagger) { mContext = context; - mNetworkManager = Objects.requireNonNull(networkManager); mSrvConfig = config; mUidFdTagger = uidFdTagger; } From 22d74f2833b9ad0a451eb4d09a3a4828710a3b99 Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 29 Dec 2020 19:17:01 +0800 Subject: [PATCH 0870/1150] [FUI06] Stop using NetworkInfo in NetworkState from external callers This is achieved by: 1. Use legacy network type inside NetworkState to replace the needs of referencing NetworkInfo.getType(). 2. Let getAllNetworkState only return networks with isConnected() equals true. This allows callers such as NPMS or NSS does not have to reference to NetworkInfo.isConnected(). Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest Bug: 174123988 Change-Id: I1c4eb08d18ca973eb8f41d06258872eabc0006b8 --- core/java/android/net/NetworkIdentity.java | 8 +- .../server/net/NetworkStatsService.java | 143 +++++++++--------- 2 files changed, 74 insertions(+), 77 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 521ed9b194..b4aed6f963 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -31,7 +31,7 @@ import java.util.Objects; /** * Network definition that includes strong identity. Analogous to combining - * {@link NetworkInfo} and an IMSI. + * {@link NetworkCapabilities} and an IMSI. * * @hide */ @@ -159,7 +159,7 @@ public class NetworkIdentity implements Comparable { */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, boolean defaultNetwork, @NetworkType int subType) { - final int type = state.networkInfo.getType(); + final int legacyType = state.legacyNetworkType; String subscriberId = null; String networkId = null; @@ -170,7 +170,7 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; - if (type == TYPE_WIFI) { + if (legacyType == TYPE_WIFI) { if (state.networkCapabilities.getSsid() != null) { networkId = state.networkCapabilities.getSsid(); if (networkId == null) { @@ -183,7 +183,7 @@ public class NetworkIdentity implements Comparable { } } - return new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, + return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered, defaultNetwork); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 0ab35a9110..9706bcece9 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -96,7 +96,6 @@ import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; -import android.net.NetworkInfo; import android.net.NetworkStack; import android.net.NetworkState; import android.net.NetworkStats; @@ -1264,7 +1263,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link - * NetworkStatsHistory}. When multiple {@link NetworkInfo} are active on a single {@code iface}, + * NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") @@ -1294,84 +1293,82 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkState state : states) { - if (state.networkInfo.isConnected()) { - final boolean isMobile = isNetworkTypeMobile(state.networkInfo.getType()); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); - final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED - : getSubTypeForState(state); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, - isDefault, subType); + final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED + : getSubTypeForState(state); + final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, + isDefault, subType); - // Traffic occurring on the base interface is always counted for - // both total usage and UID details. - final String baseIface = state.linkProperties.getInterfaceName(); - if (baseIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); + // Traffic occurring on the base interface is always counted for + // both total usage and UID details. + final String baseIface = state.linkProperties.getInterfaceName(); + if (baseIface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); - // Build a separate virtual interface for VT (Video Telephony) data usage. - // Only do this when IMS is not metered, but VT is metered. - // If IMS is metered, then the IMS network usage has already included VT usage. - // VT is considered always metered in framework's layer. If VT is not metered - // per carrier's policy, modem will report 0 usage for VT calls. - if (state.networkCapabilities.hasCapability( - NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { + // Build a separate virtual interface for VT (Video Telephony) data usage. + // Only do this when IMS is not metered, but VT is metered. + // If IMS is metered, then the IMS network usage has already included VT usage. + // VT is considered always metered in framework's layer. If VT is not metered + // per carrier's policy, modem will report 0 usage for VT calls. + if (state.networkCapabilities.hasCapability( + NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { - // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), - ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), - ident.getRoaming(), true /* metered */, - true /* onDefaultNetwork */); - findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); - } - - if (isMobile) { - mobileIfaces.add(baseIface); - } + // Copy the identify from IMS one but mark it as metered. + NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), + ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), + ident.getRoaming(), true /* metered */, + true /* onDefaultNetwork */); + findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } - // Traffic occurring on stacked interfaces is usually clatd. - // - // UID stats are always counted on the stacked interface and never on the base - // interface, because the packets on the base interface do not actually match - // application sockets (they're not IPv4) and thus the app uid is not known. - // For receive this is obvious: packets must be translated from IPv6 to IPv4 - // before the application socket can be found. - // For transmit: either they go through the clat daemon which by virtue of going - // through userspace strips the original socket association during the IPv4 to - // IPv6 translation process, or they are offloaded by eBPF, which doesn't: - // However, on an ebpf device the accounting is done in cgroup ebpf hooks, - // which don't trigger again post ebpf translation. - // (as such stats accounted to the clat uid are ignored) - // - // Interface stats are more complicated. - // - // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus - // *all* statistics are collected by iptables on the stacked v4-* interface. - // - // Additionally for ingress all packets bound for the clat IPv6 address are dropped - // in ip6tables raw prerouting and thus even non-offloaded packets are only - // accounted for on the stacked interface. - // - // For egress, packets subject to eBPF offload never appear on the base interface - // and only appear on the stacked interface. Thus to ensure packets increment - // interface stats, we must collate data from stacked interfaces. For xt_qtaguid - // (or non eBPF offloaded) TX they would appear on both, however egress interface - // accounting is explicitly bypassed for traffic from the clat uid. - // - final List stackedLinks = state.linkProperties.getStackedLinks(); - for (LinkProperties stackedLink : stackedLinks) { - final String stackedIface = stackedLink.getInterfaceName(); - if (stackedIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); - if (isMobile) { - mobileIfaces.add(stackedIface); - } + if (isMobile) { + mobileIfaces.add(baseIface); + } + } - mStatsFactory.noteStackedIface(stackedIface, baseIface); + // Traffic occurring on stacked interfaces is usually clatd. + // + // UID stats are always counted on the stacked interface and never on the base + // interface, because the packets on the base interface do not actually match + // application sockets (they're not IPv4) and thus the app uid is not known. + // For receive this is obvious: packets must be translated from IPv6 to IPv4 + // before the application socket can be found. + // For transmit: either they go through the clat daemon which by virtue of going + // through userspace strips the original socket association during the IPv4 to + // IPv6 translation process, or they are offloaded by eBPF, which doesn't: + // However, on an ebpf device the accounting is done in cgroup ebpf hooks, + // which don't trigger again post ebpf translation. + // (as such stats accounted to the clat uid are ignored) + // + // Interface stats are more complicated. + // + // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus + // *all* statistics are collected by iptables on the stacked v4-* interface. + // + // Additionally for ingress all packets bound for the clat IPv6 address are dropped + // in ip6tables raw prerouting and thus even non-offloaded packets are only + // accounted for on the stacked interface. + // + // For egress, packets subject to eBPF offload never appear on the base interface + // and only appear on the stacked interface. Thus to ensure packets increment + // interface stats, we must collate data from stacked interfaces. For xt_qtaguid + // (or non eBPF offloaded) TX they would appear on both, however egress interface + // accounting is explicitly bypassed for traffic from the clat uid. + // + final List stackedLinks = state.linkProperties.getStackedLinks(); + for (LinkProperties stackedLink : stackedLinks) { + final String stackedIface = stackedLink.getInterfaceName(); + if (stackedIface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + if (isMobile) { + mobileIfaces.add(stackedIface); } + + mStatsFactory.noteStackedIface(stackedIface, baseIface); } } } From 0f904190427da3203f51eb6503d35813ac927d4a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 29 Sep 2020 23:38:00 -0700 Subject: [PATCH 0871/1150] Update underlying network of IpSecTunnelInterface Bug: 169855650 Test: atest IpSecManagerTunnelTest Change-Id: I6d1b8d0e49f89c67ddc2caf4ba63fb0b1eb062c0 --- core/java/android/net/IIpSecService.aidl | 3 ++ core/java/android/net/IpSecManager.java | 37 +++++++++++++ .../java/com/android/server/IpSecService.java | 54 +++++++++++++++++-- 3 files changed, 90 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IIpSecService.aidl b/core/java/android/net/IIpSecService.aidl index d6774d47b4..933256a3b4 100644 --- a/core/java/android/net/IIpSecService.aidl +++ b/core/java/android/net/IIpSecService.aidl @@ -58,6 +58,9 @@ interface IIpSecService in LinkAddress localAddr, in String callingPackage); + void setNetworkForTunnelInterface( + int tunnelResourceId, in Network underlyingNetwork, in String callingPackage); + void deleteTunnelInterface(int resourceId, in String callingPackage); IpSecTransformResponse createTransform( diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 70bca30198..55fdafcea6 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -782,6 +782,43 @@ public final class IpSecManager { } } + /** + * Update the underlying network for this IpSecTunnelInterface. + * + *

            This new underlying network will be used for all transforms applied AFTER this call is + * complete. Before new {@link IpSecTransform}(s) with matching addresses are applied to + * this tunnel interface, traffic will still use the old SA, and be routed on the old + * underlying network. + * + *

            To migrate IPsec tunnel mode traffic, a caller should: + * + *

              + *
            1. Update the IpSecTunnelInterface’s underlying network. + *
            2. Apply {@link IpSecTransform}(s) with matching addresses to this + * IpSecTunnelInterface. + *
            + * + * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. + * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise + * this method will throw an {@link IllegalArgumentException}. + * @hide + */ + // TODO: b/169171001 Update the documentation when transform migration is supported. + // The purpose of making updating network and applying transforms separate is to leave open + // the possibility to support lossless migration procedures. To do that, Android platform + // will need to support multiple inbound tunnel mode transforms, just like it can support + // multiple transport mode transforms. + @RequiresFeature(PackageManager.FEATURE_IPSEC_TUNNELS) + @RequiresPermission(android.Manifest.permission.MANAGE_IPSEC_TUNNELS) + public void setUnderlyingNetwork(@NonNull Network underlyingNetwork) throws IOException { + try { + mService.setNetworkForTunnelInterface( + mResourceId, underlyingNetwork, mOpPackageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private IpSecTunnelInterface(@NonNull Context ctx, @NonNull IIpSecService service, @NonNull InetAddress localAddress, @NonNull InetAddress remoteAddress, @NonNull Network underlyingNetwork) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index f648c3e146..b48bc900aa 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -29,6 +29,7 @@ import android.annotation.NonNull; import android.app.AppOpsManager; import android.content.Context; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; import android.net.IIpSecService; import android.net.INetd; import android.net.InetAddresses; @@ -41,6 +42,7 @@ import android.net.IpSecTransformResponse; import android.net.IpSecTunnelInterfaceResponse; import android.net.IpSecUdpEncapResponse; import android.net.LinkAddress; +import android.net.LinkProperties; import android.net.Network; import android.net.TrafficStats; import android.net.util.NetdService; @@ -797,9 +799,15 @@ public class IpSecService extends IIpSecService.Stub { } } - private final class TunnelInterfaceRecord extends OwnedResourceRecord { + /** + * Tracks an tunnel interface, and manages cleanup paths. + * + *

            This class is not thread-safe, and expects that that users of this class will ensure + * synchronization and thread safety by holding the IpSecService.this instance lock + */ + @VisibleForTesting + final class TunnelInterfaceRecord extends OwnedResourceRecord { private final String mInterfaceName; - private final Network mUnderlyingNetwork; // outer addresses private final String mLocalAddress; @@ -810,6 +818,8 @@ public class IpSecService extends IIpSecService.Stub { private final int mIfId; + private Network mUnderlyingNetwork; + TunnelInterfaceRecord( int resourceId, String interfaceName, @@ -870,14 +880,22 @@ public class IpSecService extends IIpSecService.Stub { releaseNetId(mOkey); } - public String getInterfaceName() { - return mInterfaceName; + @GuardedBy("IpSecService.this") + public void setUnderlyingNetwork(Network underlyingNetwork) { + // When #applyTunnelModeTransform is called, this new underlying network will be used to + // update the output mark of the input transform. + mUnderlyingNetwork = underlyingNetwork; } + @GuardedBy("IpSecService.this") public Network getUnderlyingNetwork() { return mUnderlyingNetwork; } + public String getInterfaceName() { + return mInterfaceName; + } + /** Returns the local, outer address for the tunnelInterface */ public String getLocalAddress() { return mLocalAddress; @@ -1429,6 +1447,34 @@ public class IpSecService extends IIpSecService.Stub { } } + /** Set TunnelInterface to use a specific underlying network. */ + @Override + public synchronized void setNetworkForTunnelInterface( + int tunnelResourceId, Network underlyingNetwork, String callingPackage) { + enforceTunnelFeatureAndPermissions(callingPackage); + Objects.requireNonNull(underlyingNetwork, "No underlying network was specified"); + + final UserRecord userRecord = mUserResourceTracker.getUserRecord(Binder.getCallingUid()); + + // Get tunnelInterface record; if no such interface is found, will throw + // IllegalArgumentException. userRecord.mTunnelInterfaceRecords is never null + final TunnelInterfaceRecord tunnelInterfaceInfo = + userRecord.mTunnelInterfaceRecords.getResourceOrThrow(tunnelResourceId); + + final ConnectivityManager connectivityManager = + mContext.getSystemService(ConnectivityManager.class); + final LinkProperties lp = connectivityManager.getLinkProperties(underlyingNetwork); + if (tunnelInterfaceInfo.getInterfaceName().equals(lp.getInterfaceName())) { + throw new IllegalArgumentException( + "Underlying network cannot be the network being exposed by this tunnel"); + } + + // It is meaningless to check if the network exists or is valid because the network might + // disconnect at any time after it passes the check. + + tunnelInterfaceInfo.setUnderlyingNetwork(underlyingNetwork); + } + /** * Delete a TunnelInterface that has been been allocated by and registered with the system * server From b7d45ba3c6ccd9c3642d72fc9e1f5a2f971a1e9b Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 7 Oct 2020 18:48:57 -0700 Subject: [PATCH 0872/1150] [API] Expose IpSecTunnelInterface#setUnderlyingNetwork This API is required to perform MOBIKE. This API allows an IPsec peer to change the underlying network of its established IPsec tunnel without re-establishing the tunnel. Bug: 169855650 Test: atest IpSecManagerTunnelTest (new tests added) Change-Id: Ifc8ad902cbfbe4ad07e715f2fef0faa1bf9d68f3 --- core/java/android/net/IpSecManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 55fdafcea6..98acd98cc4 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -801,7 +801,6 @@ public final class IpSecManager { * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise * this method will throw an {@link IllegalArgumentException}. - * @hide */ // TODO: b/169171001 Update the documentation when transform migration is supported. // The purpose of making updating network and applying transforms separate is to leave open From 6b1f3eaf12e762c5d3dee469bb19fe75c51ceda1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Tue, 16 Feb 2021 11:48:55 -0800 Subject: [PATCH 0873/1150] Improve documentation of IpSecTunnelInterface#setUnderlyingNetwork Clarify the consequence of adding IpSecTunnelInterface to the underlying network. Bug: 169855650 Test: builds Change-Id: I2e3c4fe735b3374b2ff6d23850970e36c0aafda5 --- core/java/android/net/IpSecManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 98acd98cc4..f554dd5ab0 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -800,7 +800,9 @@ public final class IpSecManager { * * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise - * this method will throw an {@link IllegalArgumentException}. + * this method will throw an {@link IllegalArgumentException}. If the + * IpSecTunnelInterface is later added to this network, all outbound traffic will be + * blackholed. */ // TODO: b/169171001 Update the documentation when transform migration is supported. // The purpose of making updating network and applying transforms separate is to leave open From ce6537c9b739a311b109e726e76c89c6058be52f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 15 Feb 2021 20:16:28 +0900 Subject: [PATCH 0874/1150] Split parcelable .aidl files to aidl-export The one-line "parcelable X" files need to be imported by targets that do not build against SDK (the SDK has prebuilt definitions), so prepare a dedicated directory for them. This avoids having users of the classes include the whole src/ directory, which could contain definitions for classes that are not part of the public API, so should not be imported. Also move back to frameworks/base/core some .aidl definitions that were separated from their associated class. Bug: 171540887 Test: m Change-Id: I7432fe4c87cd3cab04dcb6185c9a4f3f84376549 --- core/java/android/net/UidRange.aidl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl new file mode 100644 index 0000000000..f70fc8e2fe --- /dev/null +++ b/core/java/android/net/UidRange.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +parcelable UidRange; \ No newline at end of file From 695378c7b210c1942fe66a0e017d4da8f559e7c8 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Mon, 15 Feb 2021 20:16:28 +0900 Subject: [PATCH 0875/1150] Split parcelable .aidl files to aidl-export The one-line "parcelable X" files need to be imported by targets that do not build against SDK (the SDK has prebuilt definitions), so prepare a dedicated directory for them. This avoids having users of the classes include the whole src/ directory, which could contain definitions for classes that are not part of the public API, so should not be imported. Also move back to frameworks/base/core some .aidl definitions that were separated from their associated class. Bug: 171540887 Test: m Merged-In: I7432fe4c87cd3cab04dcb6185c9a4f3f84376549 Change-Id: I7432fe4c87cd3cab04dcb6185c9a4f3f84376549 --- core/java/android/net/UidRange.aidl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl new file mode 100644 index 0000000000..f70fc8e2fe --- /dev/null +++ b/core/java/android/net/UidRange.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +/** + * An inclusive range of UIDs. + * + * {@hide} + */ +parcelable UidRange; \ No newline at end of file From 76649dfa94bd05ec6b229659c99fbd79fc04ce48 Mon Sep 17 00:00:00 2001 From: Chris Weir Date: Wed, 2 Dec 2020 17:58:54 -0800 Subject: [PATCH 0876/1150] Add support for tracking PANS data usage Adds support for tracking oemManagedNetwork types (OEM_PAID and OEM_PRIVATE). Bug: 174485293 Test: atest NetworkTemplateTest NetworkStatsCollectionTest NetworkStatsObserversTest NetworkStatsServiceTest NetworkIdentityTest Test: verify that the bytes go up in PansTest app only when `ping -I eth2 8.8.8.8` is run as root. Change-Id: I78660a835f16265ba8e44bb84332c6633dd72b84 --- core/java/android/net/NetworkIdentity.java | 57 +++++++++++++++++-- core/java/android/net/NetworkTemplate.java | 48 ++++++++++++++-- .../server/net/NetworkIdentitySet.java | 13 ++++- .../server/net/NetworkStatsService.java | 2 +- 4 files changed, 107 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 32b19a4622..303a40755d 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; @@ -41,6 +42,22 @@ public class NetworkIdentity implements Comparable { public static final int SUBTYPE_COMBINED = -1; + /** + * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}. + * @hide + */ + public static final int OEM_NONE = 0x0; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. + * @hide + */ + public static final int OEM_PAID = 0x1; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. + * @hide + */ + public static final int OEM_PRIVATE = 0x2; + final int mType; final int mSubType; final String mSubscriberId; @@ -48,10 +65,11 @@ public class NetworkIdentity implements Comparable { final boolean mRoaming; final boolean mMetered; final boolean mDefaultNetwork; + final int mOemManaged; public NetworkIdentity( int type, int subType, String subscriberId, String networkId, boolean roaming, - boolean metered, boolean defaultNetwork) { + boolean metered, boolean defaultNetwork, int oemManaged) { mType = type; mSubType = subType; mSubscriberId = subscriberId; @@ -59,12 +77,13 @@ public class NetworkIdentity implements Comparable { mRoaming = roaming; mMetered = metered; mDefaultNetwork = defaultNetwork; + mOemManaged = oemManaged; } @Override public int hashCode() { return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, - mDefaultNetwork); + mDefaultNetwork, mOemManaged); } @Override @@ -75,7 +94,8 @@ public class NetworkIdentity implements Comparable { && Objects.equals(mSubscriberId, ident.mSubscriberId) && Objects.equals(mNetworkId, ident.mNetworkId) && mMetered == ident.mMetered - && mDefaultNetwork == ident.mDefaultNetwork; + && mDefaultNetwork == ident.mDefaultNetwork + && mOemManaged == ident.mOemManaged; } return false; } @@ -102,6 +122,8 @@ public class NetworkIdentity implements Comparable { } builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); + // TODO(180557699): Print a human readable string for OEM managed state. + builder.append(", oemManaged=").append(mOemManaged); return builder.append("}").toString(); } @@ -120,6 +142,7 @@ public class NetworkIdentity implements Comparable { proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); proto.end(start); } @@ -152,6 +175,10 @@ public class NetworkIdentity implements Comparable { return mDefaultNetwork; } + public int getOemManaged() { + return mOemManaged; + } + /** * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, * assuming that any mobile networks are using the current IMSI. The subType if applicable, @@ -171,6 +198,8 @@ public class NetworkIdentity implements Comparable { subscriberId = state.subscriberId; + final int oemManaged = getOemBitfield(state.networkCapabilities); + if (legacyType == TYPE_WIFI) { if (state.networkCapabilities.getSsid() != null) { networkId = state.networkCapabilities.getSsid(); @@ -185,7 +214,24 @@ public class NetworkIdentity implements Comparable { } return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered, - defaultNetwork); + defaultNetwork, oemManaged); + } + + /** + * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}. + * @hide + */ + public static int getOemBitfield(NetworkCapabilities nc) { + int oemManaged = OEM_NONE; + + if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) { + oemManaged |= OEM_PAID; + } + if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE)) { + oemManaged |= OEM_PRIVATE; + } + + return oemManaged; } @Override @@ -209,6 +255,9 @@ public class NetworkIdentity implements Comparable { if (res == 0) { res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork); } + if (res == 0) { + res = Integer.compare(mOemManaged, another.mOemManaged); + } return res; } } diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index aa61e03b28..c83dd99c2a 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -23,6 +23,7 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.NetworkIdentity.OEM_NONE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -99,6 +100,22 @@ public class NetworkTemplate implements Parcelable { */ public static final int NETWORK_TYPE_5G_NSA = -2; + /** + * Value to match both OEM managed and unmanaged networks (all networks). + * @hide + */ + public static final int OEM_MANAGED_ALL = -1; + /** + * Value to match networks which are not OEM managed. + * @hide + */ + public static final int OEM_MANAGED_NO = OEM_NONE; + /** + * Value to match any OEM managed network. + * @hide + */ + public static final int OEM_MANAGED_YES = -2; + private static boolean isKnownMatchRule(final int rule) { switch (rule) { case MATCH_MOBILE: @@ -151,10 +168,10 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); } /** @@ -235,6 +252,9 @@ public class NetworkTemplate implements Parcelable { private final int mDefaultNetwork; private final int mSubType; + // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. + private final int mOemManaged; + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -243,11 +263,12 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork, int subType) { + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged) { mMatchRule = matchRule; mSubscriberId = subscriberId; mMatchSubscriberIds = matchSubscriberIds; @@ -256,6 +277,7 @@ public class NetworkTemplate implements Parcelable { mRoaming = roaming; mDefaultNetwork = defaultNetwork; mSubType = subType; + mOemManaged = oemManaged; if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule @@ -272,6 +294,7 @@ public class NetworkTemplate implements Parcelable { mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); mSubType = in.readInt(); + mOemManaged = in.readInt(); } @Override @@ -284,6 +307,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); + dest.writeInt(mOemManaged); } @Override @@ -319,13 +343,16 @@ public class NetworkTemplate implements Parcelable { if (mSubType != NETWORK_TYPE_ALL) { builder.append(", subType=").append(mSubType); } + if (mOemManaged != OEM_MANAGED_ALL) { + builder.append(", oemManaged=").append(mOemManaged); + } return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType); + mDefaultNetwork, mSubType, mOemManaged); } @Override @@ -338,7 +365,8 @@ public class NetworkTemplate implements Parcelable { && mMetered == other.mMetered && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork - && mSubType == other.mSubType; + && mSubType == other.mSubType + && mOemManaged == other.mOemManaged; } return false; } @@ -384,6 +412,7 @@ public class NetworkTemplate implements Parcelable { if (!matchesMetered(ident)) return false; if (!matchesRoaming(ident)) return false; if (!matchesDefaultNetwork(ident)) return false; + if (!matchesOemNetwork(ident)) return false; switch (mMatchRule) { case MATCH_MOBILE: @@ -425,6 +454,13 @@ public class NetworkTemplate implements Parcelable { || (mDefaultNetwork == DEFAULT_NETWORK_NO && !ident.mDefaultNetwork); } + private boolean matchesOemNetwork(NetworkIdentity ident) { + return (mOemManaged == OEM_MANAGED_ALL) + || (mOemManaged == OEM_MANAGED_YES + && ident.mOemManaged != OEM_NONE) + || (mOemManaged == ident.mOemManaged); + } + private boolean matchesCollapsedRatType(NetworkIdentity ident) { return mSubType == NETWORK_TYPE_ALL || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java index bce80696f7..22ed781da9 100644 --- a/services/core/java/com/android/server/net/NetworkIdentitySet.java +++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java @@ -40,6 +40,7 @@ public class NetworkIdentitySet extends HashSet implements private static final int VERSION_ADD_NETWORK_ID = 3; private static final int VERSION_ADD_METERED = 4; private static final int VERSION_ADD_DEFAULT_NETWORK = 5; + private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; public NetworkIdentitySet() { } @@ -84,13 +85,20 @@ public class NetworkIdentitySet extends HashSet implements defaultNetwork = true; } + final int oemNetCapabilities; + if (version >= VERSION_ADD_OEM_MANAGED_NETWORK) { + oemNetCapabilities = in.readInt(); + } else { + oemNetCapabilities = NetworkIdentity.OEM_NONE; + } + add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, - defaultNetwork)); + defaultNetwork, oemNetCapabilities)); } } public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_DEFAULT_NETWORK); + out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -100,6 +108,7 @@ public class NetworkIdentitySet extends HashSet implements out.writeBoolean(ident.getRoaming()); out.writeBoolean(ident.getMetered()); out.writeBoolean(ident.getDefaultNetwork()); + out.writeInt(ident.getOemManaged()); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9706bcece9..5b9a11bc5a 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1319,7 +1319,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, - true /* onDefaultNetwork */); + true /* onDefaultNetwork */, ident.getOemManaged()); findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); } From 1b4f0a409db397bcf877f36edcf15ed16e801d96 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 19 Jan 2021 10:47:55 -0700 Subject: [PATCH 0877/1150] Pivot network statistics to use DataInput/Output. The majority of this refactoring has already landed in AOSP, and this small CL is the remaining piece needed to begin using the new optimized classes which only exist in the internal tree. This is a no-op refactoring. Bug: 176777285 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Ifd7ac95c6cd6761e7d03cbf381dcc9e32b6406aa --- .../android/server/net/NetworkStatsCollection.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 6aefe41891..557fa89444 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -54,6 +54,8 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; +import com.android.internal.util.FastDataInput; +import com.android.internal.util.FastDataOutput; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; @@ -89,6 +91,9 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; + /** Default buffer size from BufferedInputStream */ + private static final int BUFFER_SIZE = 8192; + private static final int VERSION_NETWORK_INIT = 1; private static final int VERSION_UID_INIT = 1; @@ -434,7 +439,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W @Override public void read(InputStream in) throws IOException { - read((DataInput) new DataInputStream(in)); + final FastDataInput dataIn = new FastDataInput(in, BUFFER_SIZE); + read(dataIn); } private void read(DataInput in) throws IOException { @@ -473,8 +479,9 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W @Override public void write(OutputStream out) throws IOException { - write((DataOutput) new DataOutputStream(out)); - out.flush(); + final FastDataOutput dataOut = new FastDataOutput(out, BUFFER_SIZE); + write(dataOut); + dataOut.flush(); } private void write(DataOutput out) throws IOException { From 60fe5aa059f4caa2c521bbee4841a4c9cfe59470 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Mon, 8 Feb 2021 18:23:44 -0800 Subject: [PATCH 0878/1150] Support new IpSecAlgorithm AUTH_AES_CMAC Bug: 161716062 Test: IpSecAlgorithmTest, verified with CTS Change-Id: Ideaf4225bd851fad8c8072505c6ad99d85ba616e --- core/java/android/net/IpSecAlgorithm.java | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index e89451e4f4..8f1e2defd2 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -145,6 +145,25 @@ public final class IpSecAlgorithm implements Parcelable { // to be available on devices first shipped with Android 12 or later. public static final String AUTH_AES_XCBC = "xcbc(aes)"; + /** + * AES-CMAC Authentication/Integrity Algorithm. + * + *

            Keys for this algorithm must be 128 bits in length. + * + *

            The only valid truncation length is 96 bits. + * + *

            This algorithm may be available on the device. Caller MUST check if it is supported before + * using it by calling {@link #getSupportedAlgorithms()} and checking if this algorithm is + * included in the returned algorithm set. The returned algorithm set will not change unless the + * device is rebooted. {@link IllegalArgumentException} will be thrown if this algorithm is + * requested on an unsupported device. + * + *

            @see {@link #getSupportedAlgorithms()} + */ + // This algorithm may be available on devices released before Android 12, and is guaranteed + // to be available on devices first shipped with Android 12 or later. + public static final String AUTH_AES_CMAC = "cmac(aes)"; + /** * AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm. * @@ -191,6 +210,7 @@ public final class IpSecAlgorithm implements Parcelable { AUTH_HMAC_SHA384, AUTH_HMAC_SHA512, AUTH_AES_XCBC, + AUTH_AES_CMAC, AUTH_CRYPT_AES_GCM, AUTH_CRYPT_CHACHA20_POLY1305 }) @@ -215,6 +235,7 @@ public final class IpSecAlgorithm implements Parcelable { // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); } @@ -383,6 +404,10 @@ public final class IpSecAlgorithm implements Parcelable { isValidLen = keyLen == 128; isValidTruncLen = truncLen == 96; break; + case AUTH_AES_CMAC: + isValidLen = keyLen == 128; + isValidTruncLen = truncLen == 96; + break; case AUTH_CRYPT_AES_GCM: // The keying material for GCM is a key plus a 32-bit salt isValidLen = keyLen == 128 + 32 || keyLen == 192 + 32 || keyLen == 256 + 32; @@ -416,6 +441,7 @@ public final class IpSecAlgorithm implements Parcelable { case AUTH_HMAC_SHA384: case AUTH_HMAC_SHA512: case AUTH_AES_XCBC: + case AUTH_AES_CMAC: return true; default: return false; From 1745f3a7592fae9f572027f46df6441e61dc2bf5 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Thu, 25 Feb 2021 10:40:24 -0800 Subject: [PATCH 0879/1150] Use VERSION_CODES.S instead of VERSION_CODES.R + 1 Bug: 170424293 Test: IpSecAlgorithmTest Change-Id: I4662b0d43c476b744536a41000d578e8b69286ef --- core/java/android/net/IpSecAlgorithm.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 8f1e2defd2..268002f1dd 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,11 +232,10 @@ public final class IpSecAlgorithm implements Parcelable { ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); } private static final Set ENABLED_ALGOS = From 51fa8bd6d099fa478071f341df5696d4b5438e42 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 26 Feb 2021 11:19:41 +0800 Subject: [PATCH 0880/1150] Replace ConnectivityManager hidden symbols on framework Connectivity is becoming a mainline module in S, so ConnectivityManager hidden symbols can not be used for outside components. Besides, most Tethering relevant methods or variables on CM are migrated to TetheringManager. So replace all these methods or variables from ConnectivityManager to TetheringManager on Telephony on framework. Bug: 180693313 Test: atest FrameworksNetTests Change-Id: I14e032ad6f278a36e8756aa7045d73a403f8f059 --- .../core/java/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 9706bcece9..870768c186 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,6 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED; import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; @@ -45,6 +44,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; +import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UNSUPPORTED; From e553899c44c4a38eac2614ea92997cca5bd2133f Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 22 Jan 2021 20:59:50 +0800 Subject: [PATCH 0881/1150] [FUI08] Create NeworkStateSnapshot Since NetworkState has UnsupportedAppUsage APIs that cannot be changed, create another class for follow-up patches to expose as system API. Test: NetworkStateSnapshotTest Bug: 174123988 Change-Id: I54ef872847f34166aa34a79f6178c90ac12b6c72 --- .../android/net/NetworkStateSnapshot.java | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 core/java/android/net/NetworkStateSnapshot.java diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java new file mode 100644 index 0000000000..881b373fa2 --- /dev/null +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * Snapshot of network state. + * + * @hide + */ +public final class NetworkStateSnapshot implements Parcelable { + @NonNull + public final LinkProperties linkProperties; + @NonNull + public final NetworkCapabilities networkCapabilities; + @NonNull + public final Network network; + @Nullable + public final String subscriberId; + public final int legacyType; + + public NetworkStateSnapshot(@NonNull LinkProperties linkProperties, + @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network, + @Nullable String subscriberId, int legacyType) { + this.linkProperties = Objects.requireNonNull(linkProperties); + this.networkCapabilities = Objects.requireNonNull(networkCapabilities); + this.network = Objects.requireNonNull(network); + this.subscriberId = subscriberId; + this.legacyType = legacyType; + } + + public NetworkStateSnapshot(@NonNull Parcel in) { + linkProperties = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); + network = in.readParcelable(null); + subscriberId = in.readString(); + legacyType = in.readInt(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel out, int flags) { + out.writeParcelable(linkProperties, flags); + out.writeParcelable(networkCapabilities, flags); + out.writeParcelable(network, flags); + out.writeString(subscriberId); + out.writeInt(legacyType); + } + + @NonNull + public static final Creator CREATOR = + new Creator() { + @NonNull + @Override + public NetworkStateSnapshot createFromParcel(@NonNull Parcel in) { + return new NetworkStateSnapshot(in); + } + + @NonNull + @Override + public NetworkStateSnapshot[] newArray(int size) { + return new NetworkStateSnapshot[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof NetworkStateSnapshot)) return false; + NetworkStateSnapshot that = (NetworkStateSnapshot) o; + return legacyType == that.legacyType + && Objects.equals(linkProperties, that.linkProperties) + && Objects.equals(networkCapabilities, that.networkCapabilities) + && Objects.equals(network, that.network) + && Objects.equals(subscriberId, that.subscriberId); + } + + @Override + public int hashCode() { + return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType); + } +} From dd7831ded4f49af31a83be24b8a530917f344b41 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 2 Mar 2021 12:12:49 +0900 Subject: [PATCH 0882/1150] Move UidRange to connectivity UidRange is a data class that is an implementation detail of Connectivity. Move it to the connectivity boundary. Remaining usages of UidRange outside of Connectivity (in VPN) should be migrated to other classes, like Range or UidRangeParcel. Bug: 181512874 Test: m Change-Id: I6f2e3685ad1c07171dd90480d1e546329de8732d --- core/java/android/net/UidRange.aidl | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 core/java/android/net/UidRange.aidl diff --git a/core/java/android/net/UidRange.aidl b/core/java/android/net/UidRange.aidl deleted file mode 100644 index f70fc8e2fe..0000000000 --- a/core/java/android/net/UidRange.aidl +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -/** - * An inclusive range of UIDs. - * - * {@hide} - */ -parcelable UidRange; \ No newline at end of file From 73d79037dd94cf629f95ea111bf7dfd20db617bc Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 22 Jan 2021 22:46:01 +0800 Subject: [PATCH 0883/1150] [FUI17] Migrate NetworkStatsService to use NetworkStateSnapshot This change migrates NetworkStatsService and related code to use NetworkStateSnapshot which is used for replacing the NetworkState. This patch also changes some formating which is suggested by the linter. Test: FrameworksNetTests NetworkPolicyManagerServiceTest Bug: 174123988 Change-Id: I547da8f411cb45bdadc376ac3cadf3f3c55bb282 --- .../android/net/INetworkStatsService.aidl | 4 +- core/java/android/net/NetworkIdentity.java | 44 ++++++++++++------- .../server/net/NetworkStatsService.java | 41 +++++++++-------- 3 files changed, 50 insertions(+), 39 deletions(-) diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 0baf11e850..dc3b88a7c3 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,7 +19,7 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; @@ -68,7 +68,7 @@ interface INetworkStatsService { /** Force update of ifaces. */ void forceUpdateIfaces( in Network[] defaultNetworks, - in NetworkState[] networkStates, + in NetworkStateSnapshot[] snapshots, in String activeIface, in UnderlyingNetworkInfo[] underlyingNetworkInfos); /** Force update of statistics. */ diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 303a40755d..927db11ecd 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -18,7 +18,6 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; -import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; @@ -180,29 +179,42 @@ public class NetworkIdentity implements Comparable { } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState} and {@code subType}, - * assuming that any mobile networks are using the current IMSI. The subType if applicable, - * should be set as one of the TelephonyManager.NETWORK_TYPE_* constants, or - * {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. + * Build a {@link NetworkIdentity} from the given {@link NetworkState} and + * {@code subType}, assuming that any mobile networks are using the current IMSI. + * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* + * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. */ - public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, - boolean defaultNetwork, @NetworkType int subType) { - final int legacyType = state.legacyNetworkType; + // TODO: Delete this function after NetworkPolicyManagerService finishes the migration. + public static NetworkIdentity buildNetworkIdentity(Context context, + NetworkState state, boolean defaultNetwork, @NetworkType int subType) { + final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.linkProperties, + state.networkCapabilities, state.network, state.subscriberId, + state.legacyNetworkType); + return buildNetworkIdentity(context, snapshot, defaultNetwork, subType); + } - String subscriberId = null; + /** + * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and + * {@code subType}, assuming that any mobile networks are using the current IMSI. + * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* + * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. + */ + public static NetworkIdentity buildNetworkIdentity(Context context, + NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { + final int legacyType = snapshot.legacyType; + + final String subscriberId = snapshot.subscriberId; String networkId = null; - boolean roaming = !state.networkCapabilities.hasCapability( + boolean roaming = !snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !state.networkCapabilities.hasCapability( + boolean metered = !snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - subscriberId = state.subscriberId; - - final int oemManaged = getOemBitfield(state.networkCapabilities); + final int oemManaged = getOemBitfield(snapshot.networkCapabilities); if (legacyType == TYPE_WIFI) { - if (state.networkCapabilities.getSsid() != null) { - networkId = state.networkCapabilities.getSsid(); + if (snapshot.networkCapabilities.getSsid() != null) { + networkId = snapshot.networkCapabilities.getSsid(); if (networkId == null) { // TODO: Figure out if this code path never runs. If so, remove them. final WifiManager wifi = (WifiManager) context.getSystemService( diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 5b9a11bc5a..3a5e10ed95 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -97,7 +97,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkStack; -import android.net.NetworkState; +import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; @@ -296,7 +296,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Last states of all networks sent from ConnectivityService. */ @GuardedBy("mStatsLock") @Nullable - private NetworkState[] mLastNetworkStates = null; + private NetworkStateSnapshot[] mLastNetworkStateSnapshots = null; private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -378,8 +378,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } case MSG_UPDATE_IFACES: { // If no cached states, ignore. - if (mLastNetworkStates == null) break; - updateIfaces(mDefaultNetworks, mLastNetworkStates, mActiveIface); + if (mLastNetworkStateSnapshots == null) break; + updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } case MSG_PERFORM_POLL_REGISTER_ALERT: { @@ -967,10 +967,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - @Override public void forceUpdateIfaces( Network[] defaultNetworks, - NetworkState[] networkStates, + NetworkStateSnapshot[] networkStates, String activeIface, UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); @@ -1248,13 +1247,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void updateIfaces( Network[] defaultNetworks, - NetworkState[] networkStates, + NetworkStateSnapshot[] snapshots, String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { mActiveIface = activeIface; - updateIfacesLocked(defaultNetworks, networkStates); + updateIfacesLocked(defaultNetworks, snapshots); } finally { mWakeLock.release(); } @@ -1262,13 +1261,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Inspect all current {@link NetworkState} to derive mapping from {@code iface} to {@link - * NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, + * Inspect all current {@link NetworkStateSnapshot}s to derive mapping from {@code iface} to + * {@link NetworkStatsHistory}. When multiple networks are active on a single {@code iface}, * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") private void updateIfacesLocked(@Nullable Network[] defaultNetworks, - @NonNull NetworkState[] states) { + @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1288,21 +1287,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mDefaultNetworks = defaultNetworks; } - mLastNetworkStates = states; + mLastNetworkStateSnapshots = snapshots; final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); - for (NetworkState state : states) { - final boolean isMobile = isNetworkTypeMobile(state.legacyNetworkType); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, state.network); + for (NetworkStateSnapshot snapshot : snapshots) { + final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED - : getSubTypeForState(state); - final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, state, + : getSubTypeForStateSnapshot(snapshot); + final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, isDefault, subType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. - final String baseIface = state.linkProperties.getInterfaceName(); + final String baseIface = snapshot.linkProperties.getInterfaceName(); if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); @@ -1312,7 +1311,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // If IMS is metered, then the IMS network usage has already included VT usage. // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. - if (state.networkCapabilities.hasCapability( + if (snapshot.networkCapabilities.hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { // Copy the identify from IMS one but mark it as metered. @@ -1358,7 +1357,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // (or non eBPF offloaded) TX they would appear on both, however egress interface // accounting is explicitly bypassed for traffic from the clat uid. // - final List stackedLinks = state.linkProperties.getStackedLinks(); + final List stackedLinks = snapshot.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { @@ -1381,7 +1380,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different * transport types do not actually fill this value. */ - private int getSubTypeForState(@NonNull NetworkState state) { + private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } From 51392affe6a7473f6ece942a83d377410f2a3fee Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 30 Dec 2020 19:03:32 +0800 Subject: [PATCH 0884/1150] [FUI09] Expose NetworkStateSnapshot as system API This is needed by NetworkStatsService and NetworkPolicyManagerService to utilize the snapshots of information of networks that grabbed from ConnectivityService. Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest Bug: 174123988 Change-Id: I7e974ef7b23ba9ba6ee775eed9899b0c0e2eca55 --- core/java/android/net/NetworkIdentity.java | 4 +- .../android/net/NetworkStateSnapshot.java | 51 +++++++++++++------ 2 files changed, 38 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 927db11ecd..a5ece7b713 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -187,8 +187,8 @@ public class NetworkIdentity implements Comparable { // TODO: Delete this function after NetworkPolicyManagerService finishes the migration. public static NetworkIdentity buildNetworkIdentity(Context context, NetworkState state, boolean defaultNetwork, @NetworkType int subType) { - final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.linkProperties, - state.networkCapabilities, state.network, state.subscriberId, + final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network, + state.networkCapabilities, state.linkProperties, state.subscriberId, state.legacyNetworkType); return buildNetworkIdentity(context, snapshot, defaultNetwork, subType); } diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 881b373fa2..b3d8d4e614 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -16,8 +16,11 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -28,31 +31,49 @@ import java.util.Objects; * * @hide */ +@SystemApi(client = MODULE_LIBRARIES) public final class NetworkStateSnapshot implements Parcelable { - @NonNull - public final LinkProperties linkProperties; - @NonNull - public final NetworkCapabilities networkCapabilities; + /** The network associated with this snapshot. */ @NonNull public final Network network; + + /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ + @NonNull + public final NetworkCapabilities networkCapabilities; + + /** The {@link LinkProperties} of the network associated with this snapshot. */ + @NonNull + public final LinkProperties linkProperties; + + /** + * The Subscriber Id of the network associated with this snapshot. See + * {@link android.telephony.TelephonyManager#getSubscriberId()}. + */ @Nullable public final String subscriberId; + + /** + * The legacy type of the network associated with this snapshot. See + * {@code ConnectivityManager#TYPE_*}. + */ public final int legacyType; - public NetworkStateSnapshot(@NonNull LinkProperties linkProperties, - @NonNull NetworkCapabilities networkCapabilities, @NonNull Network network, + public NetworkStateSnapshot(@NonNull Network network, + @NonNull NetworkCapabilities networkCapabilities, + @NonNull LinkProperties linkProperties, @Nullable String subscriberId, int legacyType) { - this.linkProperties = Objects.requireNonNull(linkProperties); - this.networkCapabilities = Objects.requireNonNull(networkCapabilities); this.network = Objects.requireNonNull(network); + this.networkCapabilities = Objects.requireNonNull(networkCapabilities); + this.linkProperties = Objects.requireNonNull(linkProperties); this.subscriberId = subscriberId; this.legacyType = legacyType; } + /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - linkProperties = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); network = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); + linkProperties = in.readParcelable(null); subscriberId = in.readString(); legacyType = in.readInt(); } @@ -64,9 +85,9 @@ public final class NetworkStateSnapshot implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(linkProperties, flags); - out.writeParcelable(networkCapabilities, flags); out.writeParcelable(network, flags); + out.writeParcelable(networkCapabilities, flags); + out.writeParcelable(linkProperties, flags); out.writeString(subscriberId); out.writeInt(legacyType); } @@ -93,14 +114,14 @@ public final class NetworkStateSnapshot implements Parcelable { if (!(o instanceof NetworkStateSnapshot)) return false; NetworkStateSnapshot that = (NetworkStateSnapshot) o; return legacyType == that.legacyType - && Objects.equals(linkProperties, that.linkProperties) - && Objects.equals(networkCapabilities, that.networkCapabilities) && Objects.equals(network, that.network) + && Objects.equals(networkCapabilities, that.networkCapabilities) + && Objects.equals(linkProperties, that.linkProperties) && Objects.equals(subscriberId, that.subscriberId); } @Override public int hashCode() { - return Objects.hash(linkProperties, networkCapabilities, network, subscriberId, legacyType); + return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); } } From 124e136954fc9bfea1f804b1079f4cc062cca2c9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sat, 23 Jan 2021 11:00:10 +0800 Subject: [PATCH 0885/1150] [FUI18] Expose notifyNetworkStatus as system API Test: m -j doc-comment-check-docs Bug: 174123988 Change-Id: I11d4c9ab24de87fb2ad120e3787b78b73133e874 --- .../app/usage/NetworkStatsManager.java | 50 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 9 ++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1d5dc1d5df..098d8b6c60 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,6 +16,8 @@ package android.app.usage; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -28,8 +30,11 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; +import android.net.Network; import android.net.NetworkStack; +import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; +import android.net.UnderlyingNetworkInfo; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; @@ -48,6 +53,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkIdentityUtils; +import java.util.List; import java.util.Objects; /** @@ -633,6 +639,50 @@ public class NetworkStatsManager { return template; } + /** + * Notify {@code NetworkStatsService} about network status changed. + * + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. + * + * @param defaultNetworks the list of all networks that could be used by network traffic that + * does not explicitly select a network. + * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for + * each network that is currently connected. + * @param activeIface the active (i.e., connected) default network interface for the calling + * uid. Used to determine on which network future calls to + * {@link android.net.TrafficStats#incrementOperationCount} applies to. + * @param underlyingNetworkInfos the list of underlying network information for all + * currently-connected VPNs. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void notifyNetworkStatus( + @NonNull List defaultNetworks, + @NonNull List networkStateSnapshots, + @Nullable String activeIface, + @NonNull List underlyingNetworkInfos) { + try { + Objects.requireNonNull(defaultNetworks); + Objects.requireNonNull(networkStateSnapshots); + Objects.requireNonNull(underlyingNetworkInfos); + // TODO: Change internal namings after the name is decided. + mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, + underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private static class CallbackHandler extends Handler { private final int mNetworkType; private final String mSubscriberId; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3a5e10ed95..ebf1fe9d7c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -379,6 +379,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { case MSG_UPDATE_IFACES: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; + // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } @@ -1266,7 +1267,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + private void updateIfacesLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1282,10 +1283,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); - if (defaultNetworks != null) { - // Caller is ConnectivityService. Update the list of default networks. - mDefaultNetworks = defaultNetworks; - } + // Update the list of default networks. + mDefaultNetworks = defaultNetworks; mLastNetworkStateSnapshots = snapshots; From 87107539df3369428f7e74a7874739f0846200f8 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sat, 23 Jan 2021 11:00:10 +0800 Subject: [PATCH 0886/1150] [FUI18] Expose notifyNetworkStatus as system API Test: m -j doc-comment-check-docs Bug: 174123988 Merged-In: I11d4c9ab24de87fb2ad120e3787b78b73133e874 Change-Id: I11d4c9ab24de87fb2ad120e3787b78b73133e874 (cherry-picked from ag/13749978) --- .../app/usage/NetworkStatsManager.java | 50 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 9 ++-- 2 files changed, 54 insertions(+), 5 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 1d5dc1d5df..098d8b6c60 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -16,6 +16,8 @@ package android.app.usage; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -28,8 +30,11 @@ import android.content.Context; import android.net.ConnectivityManager; import android.net.DataUsageRequest; import android.net.INetworkStatsService; +import android.net.Network; import android.net.NetworkStack; +import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; +import android.net.UnderlyingNetworkInfo; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; @@ -48,6 +53,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.net.module.util.NetworkIdentityUtils; +import java.util.List; import java.util.Objects; /** @@ -633,6 +639,50 @@ public class NetworkStatsManager { return template; } + /** + * Notify {@code NetworkStatsService} about network status changed. + * + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. + * + * @param defaultNetworks the list of all networks that could be used by network traffic that + * does not explicitly select a network. + * @param networkStateSnapshots a list of {@link NetworkStateSnapshot}s, one for + * each network that is currently connected. + * @param activeIface the active (i.e., connected) default network interface for the calling + * uid. Used to determine on which network future calls to + * {@link android.net.TrafficStats#incrementOperationCount} applies to. + * @param underlyingNetworkInfos the list of underlying network information for all + * currently-connected VPNs. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void notifyNetworkStatus( + @NonNull List defaultNetworks, + @NonNull List networkStateSnapshots, + @Nullable String activeIface, + @NonNull List underlyingNetworkInfos) { + try { + Objects.requireNonNull(defaultNetworks); + Objects.requireNonNull(networkStateSnapshots); + Objects.requireNonNull(underlyingNetworkInfos); + // TODO: Change internal namings after the name is decided. + mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, + underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private static class CallbackHandler extends Handler { private final int mNetworkType; private final String mSubscriberId; diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3a5e10ed95..ebf1fe9d7c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -379,6 +379,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { case MSG_UPDATE_IFACES: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; + // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } @@ -1266,7 +1267,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@Nullable Network[] defaultNetworks, + private void updateIfacesLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1282,10 +1283,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); - if (defaultNetworks != null) { - // Caller is ConnectivityService. Update the list of default networks. - mDefaultNetworks = defaultNetworks; - } + // Update the list of default networks. + mDefaultNetworks = defaultNetworks; mLastNetworkStateSnapshots = snapshots; From 6ea46aec25e32ded5e5b012a1c279ceae30dc220 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 3 Mar 2021 12:09:05 +0800 Subject: [PATCH 0887/1150] [FUI22] Support getAllNetworkStateSnapshot Currently, ConnectivityService has getAllNetworkState but it is not ideal to expose as system API since the plan is to get rid of NetworkState. Thus, create a new one that returns NetworkStateSnapshot to fulfill the needs. Note the original getAllNetworkState cannot be deleted now since it has @UnsupportedAppUsage annotation. Test: atest FrameworksNetTests Bug: 174123988 Change-Id: Icddd434552b0e9ecbc8299e7242ec88cf3145aca --- core/java/android/net/NetworkStateSnapshot.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index b3d8d4e614..0d26c2de86 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -24,6 +24,8 @@ import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; +import com.android.net.module.util.NetworkIdentityUtils; + import java.util.Objects; /** @@ -124,4 +126,15 @@ public final class NetworkStateSnapshot implements Parcelable { public int hashCode() { return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); } + + @Override + public String toString() { + return "NetworkStateSnapshot{" + + "network=" + network + + ", networkCapabilities=" + networkCapabilities + + ", linkProperties=" + linkProperties + + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\'' + + ", legacyType=" + legacyType + + '}'; + } } From ebd239c88efa20518b2bb4da38960ee0c77dba99 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Fri, 5 Mar 2021 00:13:10 +0000 Subject: [PATCH 0888/1150] Revert "Use VERSION_CODES.S instead of VERSION_CODES.R + 1" This reverts commit 1745f3a7592fae9f572027f46df6441e61dc2bf5. Reason for revert: 1. The BUILD_VERSIONS.S is 1000, and thus it will prevent the code from requiring new algorithms on devices whose first sdk is 31 (e.g. cuttlefish), though these devices should be treated as first launched with SDK S. 2. It will break #testValidationForAlgosAddedInS, because the test code is using BUILD_VERSIONS.R to gate the test, which is inconsistent with the implementation. Bug: 181887451 Test: atest IpSecAlgorithmTest Change-Id: I5cd717c5ebd6086ae5cf9abf76311ae4fca0c6e9 --- core/java/android/net/IpSecAlgorithm.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 268002f1dd..8f1e2defd2 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,10 +232,11 @@ public final class IpSecAlgorithm implements Parcelable { ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); + // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); } private static final Set ENABLED_ALGOS = From 651a096e6f77a8cce5b9370e9c1199a6ad184ab1 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Mon, 8 Mar 2021 15:58:34 +0800 Subject: [PATCH 0889/1150] Replace ConnectivityManager.isNetworkTypeMobile usage in NSS ConnectivityManager is a part of connectivity mainline. The hidden methods dependency in ConnectivityManager should be removed to make it a moudle. NSS use isNetworkTypeMobile to check if the NetworkState belongs to a cellular network or not. It should be replaced by the NetworkCapabilities inside the NetworkState. The result of isNetworkTypeMobile relies on the legacy network type. The legacy network type comes from the network type of its network info. The replacement should consider VPN active case because the network type will not be TYPE_MOBILE. Thus, replace it with Networkcapabilities.getDisplayTransport() to get a transport that can be used to classify a network when displaying its info to users, i.e. it will return TRANSPORT_VPN for a vpn network on cellular network. Bug: 172183305 Test: atest FrameworksNetTests Change-Id: I2132a7288a93e4430cbd9efabc33ae56ce8bdd9b --- .../java/com/android/server/net/NetworkStatsService.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e0f534602d..7b376847fd 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,6 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.ConnectivityManager.isNetworkTypeMobile; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -71,6 +70,7 @@ import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; +import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; @@ -1291,7 +1291,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { - final boolean isMobile = isNetworkTypeMobile(snapshot.legacyType); + final int displayTransport = + getDisplayTransport(snapshot.networkCapabilities.getTransportTypes()); + final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); From aa5bdbffacd69ce24b11c09d4eff74747dea5b17 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 14:20:19 +0900 Subject: [PATCH 0890/1150] Add Ethernet, TestNetworkSpecifier API Rename StringNetworkSpecifier to EthernetNetworkSpecifier (its only production user), and make it module-lib API. The original StringNetworkSpecifier file is actually kept to satisfy some invalid dependencies; it will be removed separately. This allows specifying an Ethernet interface with a non-deprecated API: until this change the only way to do so would be to use NetworkRequest#setSpecifier(String), which is deprecated. Similarly, add the TestNetworkSpecifier API for TestNetworkManager, to replace previous usage of StringNetworkSpecifier. TestNetworkManager is module API, so TestNetworkSpecifier should be module API too. This allows tests to request the test interface specifically, without using the deprecated NetworkRequest#setSpecifier(String). Bug: 179329291 Test: m Change-Id: Iee569f5c8bbdc4bc979610e1191308281f3d4620 --- .../android/net/EthernetNetworkSpecifier.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 core/java/android/net/EthernetNetworkSpecifier.java diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/core/java/android/net/EthernetNetworkSpecifier.java new file mode 100644 index 0000000000..e1685887e8 --- /dev/null +++ b/core/java/android/net/EthernetNetworkSpecifier.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.Preconditions; + +import java.util.Objects; + +/** + * A {@link NetworkSpecifier} used to identify ethernet interfaces. + * + * @see EthernetManager + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { + + /** + * Name of the network interface. + */ + @NonNull + private final String mInterfaceName; + + public EthernetNetworkSpecifier(@NonNull String interfaceName) { + Preconditions.checkStringNotEmpty(interfaceName); + mInterfaceName = interfaceName; + } + + // This may be null in the future to support specifiers based on data other than the interface + // name. + @Nullable + public String getInterfaceName() { + return mInterfaceName; + } + + @Override + public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { + return equals(other); + } + + @Override + public boolean equals(@Nullable Object o) { + if (!(o instanceof EthernetNetworkSpecifier)) return false; + return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName); + } + + @Override + public int hashCode() { + return Objects.hashCode(mInterfaceName); + } + + @Override + public String toString() { + return "EthernetNetworkSpecifier (" + mInterfaceName + ")"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mInterfaceName); + } + + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public EthernetNetworkSpecifier createFromParcel(Parcel in) { + return new EthernetNetworkSpecifier(in.readString()); + } + public EthernetNetworkSpecifier[] newArray(int size) { + return new EthernetNetworkSpecifier[size]; + } + }; +} From 2d5af929269778cd8e61e52981a8b864bd06176f Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 9 Mar 2021 09:31:17 +0000 Subject: [PATCH 0891/1150] Remove unused buildNetworkIdentity The overload using a NetworkState is now unused. Bug: 174123988 Change-Id: I22f2d2fffd2d70c08097d3217f01393ff8e75ab5 Test: m --- core/java/android/net/NetworkIdentity.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index a5ece7b713..b037261f0b 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -178,21 +178,6 @@ public class NetworkIdentity implements Comparable { return mOemManaged; } - /** - * Build a {@link NetworkIdentity} from the given {@link NetworkState} and - * {@code subType}, assuming that any mobile networks are using the current IMSI. - * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* - * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. - */ - // TODO: Delete this function after NetworkPolicyManagerService finishes the migration. - public static NetworkIdentity buildNetworkIdentity(Context context, - NetworkState state, boolean defaultNetwork, @NetworkType int subType) { - final NetworkStateSnapshot snapshot = new NetworkStateSnapshot(state.network, - state.networkCapabilities, state.linkProperties, state.subscriberId, - state.legacyNetworkType); - return buildNetworkIdentity(context, snapshot, defaultNetwork, subType); - } - /** * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and * {@code subType}, assuming that any mobile networks are using the current IMSI. From fafaa4751a751918bf0053cfe28a8c3330f0a09a Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Wed, 10 Mar 2021 17:41:00 +0900 Subject: [PATCH 0892/1150] Annotate NSM heavy methods with @WorkerThread Test: TH Bug: 181906747 Change-Id: Ia30273466c1b91a3dcc5d36dac61f92185dec96e --- .../android/app/usage/NetworkStatsManager.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 098d8b6c60..9f1132b605 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -24,6 +24,7 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; @@ -201,6 +202,7 @@ public class NetworkStatsManager { * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered {@link NetworkStats.Bucket#METERED_ALL}, * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. + * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -219,6 +221,7 @@ public class NetworkStatsManager { * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ + @WorkerThread public Bucket querySummaryForDevice(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; @@ -240,6 +243,7 @@ public class NetworkStatsManager { * uid {@link NetworkStats.Bucket#UID_ALL}, tag {@link NetworkStats.Bucket#TAG_NONE}, * metered {@link NetworkStats.Bucket#METERED_ALL}, and roaming * {@link NetworkStats.Bucket#ROAMING_ALL}. + * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -258,6 +262,7 @@ public class NetworkStatsManager { * @return Bucket object or null if permissions are insufficient or error happened during * statistics collection. */ + @WorkerThread public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; @@ -283,6 +288,7 @@ public class NetworkStatsManager { * means buckets' start and end timestamps are going to be the same as the 'startTime' and * 'endTime' parameters. State, uid, metered, and roaming are going to vary, and tag is going to * be the same. + * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -301,6 +307,7 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ + @WorkerThread public NetworkStats querySummary(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; @@ -326,9 +333,11 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid. + * This may take a long time, and apps should avoid calling this on their main thread. * * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ + @WorkerThread public NetworkStats queryDetailsForUid(int networkType, String subscriberId, long startTime, long endTime, int uid) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, @@ -344,9 +353,11 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid and tag. + * This may take a long time, and apps should avoid calling this on their main thread. * * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ + @WorkerThread public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, @@ -365,6 +376,7 @@ public class NetworkStatsManager { *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. + * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -387,6 +399,7 @@ public class NetworkStatsManager { * @return Statistics object or null if an error happened during statistics collection. * @throws SecurityException if permissions are insufficient to read network statistics. */ + @WorkerThread public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { NetworkTemplate template; @@ -425,6 +438,7 @@ public class NetworkStatsManager { *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. Since bucket length is in the order of hours, this * method cannot be used to measure data usage on a fine grained time scale. + * This may take a long time, and apps should avoid calling this on their main thread. * * @param networkType As defined in {@link ConnectivityManager}, e.g. * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} @@ -443,6 +457,7 @@ public class NetworkStatsManager { * @return Statistics object or null if permissions are insufficient or error happened during * statistics collection. */ + @WorkerThread public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; From c9f9c3c5d20ea1a7db354929686d15822f6b1ff0 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 4 Feb 2021 14:20:19 +0900 Subject: [PATCH 0893/1150] Add Ethernet, TestNetworkSpecifier API Rename StringNetworkSpecifier to EthernetNetworkSpecifier (its only production user), and make it module-lib API. The original StringNetworkSpecifier file is actually kept to satisfy some invalid dependencies; it will be removed separately. This allows specifying an Ethernet interface with a non-deprecated API: until this change the only way to do so would be to use NetworkRequest#setSpecifier(String), which is deprecated. Similarly, add the TestNetworkSpecifier API for TestNetworkManager, to replace previous usage of StringNetworkSpecifier. TestNetworkManager is module API, so TestNetworkSpecifier should be module API too. This allows tests to request the test interface specifically, without using the deprecated NetworkRequest#setSpecifier(String). Bug: 179329291 Test: m Merged-In: Iee569f5c8bbdc4bc979610e1191308281f3d4620 Change-Id: Iee569f5c8bbdc4bc979610e1191308281f3d4620 --- .../android/net/EthernetNetworkSpecifier.java | 97 +++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 core/java/android/net/EthernetNetworkSpecifier.java diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/core/java/android/net/EthernetNetworkSpecifier.java new file mode 100644 index 0000000000..e1685887e8 --- /dev/null +++ b/core/java/android/net/EthernetNetworkSpecifier.java @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; +import android.text.TextUtils; + +import com.android.internal.util.Preconditions; + +import java.util.Objects; + +/** + * A {@link NetworkSpecifier} used to identify ethernet interfaces. + * + * @see EthernetManager + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { + + /** + * Name of the network interface. + */ + @NonNull + private final String mInterfaceName; + + public EthernetNetworkSpecifier(@NonNull String interfaceName) { + Preconditions.checkStringNotEmpty(interfaceName); + mInterfaceName = interfaceName; + } + + // This may be null in the future to support specifiers based on data other than the interface + // name. + @Nullable + public String getInterfaceName() { + return mInterfaceName; + } + + @Override + public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { + return equals(other); + } + + @Override + public boolean equals(@Nullable Object o) { + if (!(o instanceof EthernetNetworkSpecifier)) return false; + return TextUtils.equals(mInterfaceName, ((EthernetNetworkSpecifier) o).mInterfaceName); + } + + @Override + public int hashCode() { + return Objects.hashCode(mInterfaceName); + } + + @Override + public String toString() { + return "EthernetNetworkSpecifier (" + mInterfaceName + ")"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(mInterfaceName); + } + + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public EthernetNetworkSpecifier createFromParcel(Parcel in) { + return new EthernetNetworkSpecifier(in.readString()); + } + public EthernetNetworkSpecifier[] newArray(int size) { + return new EthernetNetworkSpecifier[size]; + } + }; +} From 2c264d7a259cf4812258825ee14ccf415be4b4f4 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Thu, 11 Mar 2021 17:39:49 +0800 Subject: [PATCH 0894/1150] Use new API - getIpSecNetIdRange() in IpSecService Use new API - getIpSecNetIdRange() to get the network ID range of IPSec tunnel interface. Bug: 172183305 Test: atest FrameworksNetTests:IpSecServiceTest Change-Id: Ib80f814f991e9f000a68f5c539d15d97cf56930e --- .../java/com/android/server/IpSecService.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 81d4b9da63..4c3c6ef21f 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -56,6 +56,7 @@ import android.system.Os; import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; +import android.util.Range; import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; @@ -756,13 +757,9 @@ public class IpSecService extends IIpSecService.Stub { } } - // These values have been reserved in NetIdManager - @VisibleForTesting static final int TUN_INTF_NETID_START = 0xFC00; - - public static final int TUN_INTF_NETID_RANGE = 0x0400; - private final SparseBooleanArray mTunnelNetIds = new SparseBooleanArray(); - private int mNextTunnelNetIdIndex = 0; + final Range mNetIdRange = ConnectivityManager.getIpSecNetIdRange(); + private int mNextTunnelNetId = mNetIdRange.getLower(); /** * Reserves a netId within the range of netIds allocated for IPsec tunnel interfaces @@ -775,11 +772,13 @@ public class IpSecService extends IIpSecService.Stub { */ @VisibleForTesting int reserveNetId() { + final int range = mNetIdRange.getUpper() - mNetIdRange.getLower() + 1; synchronized (mTunnelNetIds) { - for (int i = 0; i < TUN_INTF_NETID_RANGE; i++) { - int index = mNextTunnelNetIdIndex; - int netId = index + TUN_INTF_NETID_START; - if (++mNextTunnelNetIdIndex >= TUN_INTF_NETID_RANGE) mNextTunnelNetIdIndex = 0; + for (int i = 0; i < range; i++) { + final int netId = mNextTunnelNetId; + if (++mNextTunnelNetId > mNetIdRange.getUpper()) { + mNextTunnelNetId = mNetIdRange.getLower(); + } if (!mTunnelNetIds.get(netId)) { mTunnelNetIds.put(netId, true); return netId; From efbedc78e5c4a6294ae470560bc69461720663b4 Mon Sep 17 00:00:00 2001 From: Zhengyu Zhan Date: Wed, 6 Jan 2021 19:39:14 +0800 Subject: [PATCH 0895/1150] Support Dual ViLTE stats Some operator supports multiple VILTE, both two SIM cards can make VILTE call. We need to record VILTE data to different interface. Now NetworkStatsService has only one VILTE data interface: "vt_data0". All VILTE data stats will be recorded in this interface. Bug: 130871087 Test: NetworkStatsServiceTest#testDualVilteProviderStats Change-Id: I000ec756827bc42cac88dd0a2ca6b7999252357e --- .../server/net/NetworkStatsService.java | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7b376847fd..de14831ec3 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,6 +24,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -65,6 +66,7 @@ import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; import static android.text.format.DateUtils.MINUTE_IN_MILLIS; @@ -101,7 +103,9 @@ import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; +import android.net.NetworkSpecifier; import android.net.NetworkTemplate; +import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; import android.net.UnderlyingNetworkInfo; import android.net.Uri; @@ -1320,8 +1324,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */, ident.getOemManaged()); - findOrCreateNetworkIdentitySet(mActiveIfaces, IFACE_VT).add(vtIdent); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, IFACE_VT).add(vtIdent); + final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); + findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); } if (isMobile) { @@ -1376,6 +1381,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); } + private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { + if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); + } + + final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); + if (spec instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); + } else { + Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); + return INVALID_SUBSCRIPTION_ID; + } + } + /** * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different From f16d4995f4e0c6dea625e2faa022c401312a51d4 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 16:06:33 +0800 Subject: [PATCH 0896/1150] Use public API Network#getNetId() to get netid Network class will be a part of mainline module, external callers cannot call its hidden constant. Use public API - getNetId() to get netid instead. Bug: 182963397 Test: m Change-Id: I6d5dd0a8c3879df7bdc1d58e36022045c303bb40 --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 4c3c6ef21f..794cb9301d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1651,7 +1651,7 @@ public class IpSecService extends IIpSecService.Stub { c.getMode(), c.getSourceAddress(), c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().netId : 0, + (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, spiRecord.getSpi(), c.getMarkValue(), c.getMarkMask(), From 4249f3b86810a2419a0ab7a34cb17382f15d61e2 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 23:08:33 +0800 Subject: [PATCH 0897/1150] Use getAllInterfaceNames to get all interface names The current design is using hidden API - getStackedLinks() to get LinkProperties then call getInterfaceName() to get the interface name. In fact, this behavior could be replaced by system API - getAllInterfaceNames(). Bug: 182963397 Test: atest FrameworksNetTests Test: atest CtsNetTestCases Change-Id: Id2b19dc5099355af69d23a6d99d2b7e6c0e1e88a --- .../server/net/NetworkStatsService.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7b376847fd..fe43c311da 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -92,7 +92,6 @@ import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; -import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; @@ -131,6 +130,7 @@ import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -1358,17 +1358,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // (or non eBPF offloaded) TX they would appear on both, however egress interface // accounting is explicitly bypassed for traffic from the clat uid. // - final List stackedLinks = snapshot.linkProperties.getStackedLinks(); - for (LinkProperties stackedLink : stackedLinks) { - final String stackedIface = stackedLink.getInterfaceName(); - if (stackedIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + // TODO: This code might be combined to above code. + for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + // baseIface has been handled, so ignore it. + if (TextUtils.equals(baseIface, iface)) continue; + if (iface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); if (isMobile) { - mobileIfaces.add(stackedIface); + mobileIfaces.add(iface); } - mStatsFactory.noteStackedIface(stackedIface, baseIface); + mStatsFactory.noteStackedIface(iface, baseIface); } } } From 7a4706989607d068ef31b9fd14176ccf26ee6041 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 3 Feb 2021 00:51:29 +0800 Subject: [PATCH 0898/1150] Migrate hidden API in IpConfigStore to formal API IpConfiguration and StaticIpConfiguration are included in framework-connectivity which cannot have external hidden API usages dependencies on them. IpConfiguration and StaticIpConfiguration provide builder and getter methods for the fields of the objects which are formal APIs. So, replace the usages in IpConfigStore with those formal APIs to remove the dependencies. Bug: 178777253 Test: FrameworksServicesTests:IpConfigStoreTest Change-Id: Ie9e6af0efe2c39667bb8faa1e3a498b1f61e1432 --- .../com/android/server/net/IpConfigStore.java | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index cc3a002adc..512d2192b9 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -42,6 +42,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; public class IpConfigStore { private static final String TAG = "IpConfigStore"; @@ -83,25 +85,25 @@ public class IpConfigStore { boolean written = false; try { - switch (config.ipAssignment) { + switch (config.getIpAssignment()) { case STATIC: out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); - StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; + out.writeUTF(config.getIpAssignment().toString()); + StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration(); if (staticIpConfiguration != null) { - if (staticIpConfiguration.ipAddress != null) { - LinkAddress ipAddress = staticIpConfiguration.ipAddress; + if (staticIpConfiguration.getIpAddress() != null) { + LinkAddress ipAddress = staticIpConfiguration.getIpAddress(); out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(ipAddress.getAddress().getHostAddress()); out.writeInt(ipAddress.getPrefixLength()); } - if (staticIpConfiguration.gateway != null) { + if (staticIpConfiguration.getGateway() != null) { out.writeUTF(GATEWAY_KEY); out.writeInt(0); // Default route. out.writeInt(1); // Have a gateway. - out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); + out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); } - for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { + for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } @@ -110,7 +112,7 @@ public class IpConfigStore { break; case DHCP: out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); + out.writeUTF(config.getIpAssignment().toString()); written = true; break; case UNASSIGNED: @@ -121,13 +123,13 @@ public class IpConfigStore { break; } - switch (config.proxySettings) { + switch (config.getProxySettings()) { case STATIC: - ProxyInfo proxyProperties = config.httpProxy; + ProxyInfo proxyProperties = config.getHttpProxy(); String exclusionList = ProxyUtils.exclusionListAsString( proxyProperties.getExclusionList()); out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); out.writeUTF(PROXY_HOST_KEY); out.writeUTF(proxyProperties.getHost()); out.writeUTF(PROXY_PORT_KEY); @@ -139,16 +141,16 @@ public class IpConfigStore { written = true; break; case PAC: - ProxyInfo proxyPacProperties = config.httpProxy; + ProxyInfo proxyPacProperties = config.getHttpProxy(); out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); out.writeUTF(PROXY_PAC_FILE); out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); written = true; break; case NONE: out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); written = true; break; case UNASSIGNED: @@ -267,11 +269,14 @@ public class IpConfigStore { IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + LinkAddress linkAddress = null; + InetAddress gatewayAddress = null; String proxyHost = null; String pacFileUrl = null; int proxyPort = -1; String exclusionList = null; String key; + final List dnsServers = new ArrayList<>(); do { key = in.readUTF(); @@ -286,15 +291,15 @@ public class IpConfigStore { } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress linkAddr = + LinkAddress parsedLinkAddress = new LinkAddress( InetAddresses.parseNumericAddress(in.readUTF()), in.readInt()); - if (linkAddr.getAddress() instanceof Inet4Address && - staticIpConfiguration.ipAddress == null) { - staticIpConfiguration.ipAddress = linkAddr; + if (parsedLinkAddress.getAddress() instanceof Inet4Address + && linkAddress == null) { + linkAddress = parsedLinkAddress; } else { - loge("Non-IPv4 or duplicate address: " + linkAddr); + loge("Non-IPv4 or duplicate address: " + parsedLinkAddress); } } else if (key.equals(GATEWAY_KEY)) { LinkAddress dest = null; @@ -302,8 +307,8 @@ public class IpConfigStore { if (version == 1) { // only supported default gateways - leave the dest/prefix empty gateway = InetAddresses.parseNumericAddress(in.readUTF()); - if (staticIpConfiguration.gateway == null) { - staticIpConfiguration.gateway = gateway; + if (gatewayAddress == null) { + gatewayAddress = gateway; } else { loge("Duplicate gateway: " + gateway.getHostAddress()); } @@ -318,16 +323,14 @@ public class IpConfigStore { gateway = InetAddresses.parseNumericAddress(in.readUTF()); } RouteInfo route = new RouteInfo(dest, gateway); - if (route.isIPv4Default() && - staticIpConfiguration.gateway == null) { - staticIpConfiguration.gateway = gateway; + if (route.isIPv4Default() && gatewayAddress == null) { + gatewayAddress = gateway; } else { loge("Non-IPv4 default or duplicate route: " + route); } } } else if (key.equals(DNS_KEY)) { - staticIpConfiguration.dnsServers.add( - InetAddresses.parseNumericAddress(in.readUTF())); + dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); } else if (key.equals(PROXY_HOST_KEY)) { @@ -348,25 +351,31 @@ public class IpConfigStore { } } while (true); + staticIpConfiguration = new StaticIpConfiguration.Builder() + .setIpAddress(linkAddress) + .setGateway(gatewayAddress) + .setDnsServers(dnsServers) + .build(); + if (uniqueToken != null) { IpConfiguration config = new IpConfiguration(); networks.put(uniqueToken, config); switch (ipAssignment) { case STATIC: - config.staticIpConfiguration = staticIpConfiguration; - config.ipAssignment = ipAssignment; + config.setStaticIpConfiguration(staticIpConfiguration); + config.setIpAssignment(ipAssignment); break; case DHCP: - config.ipAssignment = ipAssignment; + config.setIpAssignment(ipAssignment); break; case UNASSIGNED: loge("BUG: Found UNASSIGNED IP on file, use DHCP"); - config.ipAssignment = IpAssignment.DHCP; + config.setIpAssignment(IpAssignment.DHCP); break; default: loge("Ignore invalid ip assignment while reading."); - config.ipAssignment = IpAssignment.UNASSIGNED; + config.setIpAssignment(IpAssignment.UNASSIGNED); break; } @@ -374,25 +383,25 @@ public class IpConfigStore { case STATIC: ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, ProxyUtils.exclusionStringAsList(exclusionList)); - config.proxySettings = proxySettings; - config.httpProxy = proxyInfo; + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyInfo); break; case PAC: ProxyInfo proxyPacProperties = ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); - config.proxySettings = proxySettings; - config.httpProxy = proxyPacProperties; + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyPacProperties); break; case NONE: - config.proxySettings = proxySettings; + config.setProxySettings(proxySettings); break; case UNASSIGNED: loge("BUG: Found UNASSIGNED proxy on file, use NONE"); - config.proxySettings = ProxySettings.NONE; + config.setProxySettings(ProxySettings.NONE); break; default: loge("Ignore invalid proxy settings while reading"); - config.proxySettings = ProxySettings.UNASSIGNED; + config.setProxySettings(ProxySettings.UNASSIGNED); break; } } else { From 2c6db2fa857ea0a87246e6eda048e5ca394f0e1d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 18 Mar 2021 21:35:45 +0800 Subject: [PATCH 0899/1150] Fix IpConfigStore dependencies on framework-connectivity This change fixes IpConfigStore dependencies on framework-connectivity hidden APIs. - Use the version of SystemApi to new RouteInfo. - Inline the implementation of isIPv4Default() directly because isDefaultRoute() is a public API so it can be used in this class. Bug: 178777253 Test: FrameworksServicesTests:IpConfigStoreTest Change-Id: I5ed1bc8bc8bee5b0c795fd8577a2d64628998e51 --- .../java/com/android/server/net/IpConfigStore.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 512d2192b9..df1eb6d9fe 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -22,7 +22,6 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.ProxyInfo; -import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.net.Uri; import android.util.ArrayMap; @@ -322,11 +321,14 @@ public class IpConfigStore { if (in.readInt() == 1) { gateway = InetAddresses.parseNumericAddress(in.readUTF()); } - RouteInfo route = new RouteInfo(dest, gateway); - if (route.isIPv4Default() && gatewayAddress == null) { + // If the destination is a default IPv4 route, use the gateway + // address unless already set. + if (dest.getAddress() instanceof Inet4Address + && dest.getPrefixLength() == 0 && gatewayAddress == null) { gatewayAddress = gateway; } else { - loge("Non-IPv4 default or duplicate route: " + route); + loge("Non-IPv4 default or duplicate route: " + + dest.getAddress()); } } } else if (key.equals(DNS_KEY)) { From 00f7776ec2a4cb4082032de8eb14ca136eb7e848 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 10:33:16 +0800 Subject: [PATCH 0900/1150] [SP28] Add API for set data warning To have better control and race-free of set data warning to tether offload hardware, an interface of set warning and limit at the same time in the NetworkStatsProvider is needed. This is a no-op change which expose such interface with minimum changes in service side to get build pass. The implementation would be included in follow-up patches. Test: atest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest Test: atest GtsNetworkStackHostTestCases Test: m doc-comment-check-docs Bug: 149467454 Bug: 170699770 Bug: 170179169 Ignore-AOSP-First: avoid long automerger delay Change-Id: I6ee661497f7dedb871c85786d1950cab951d8aa2 --- .../provider/INetworkStatsProvider.aidl | 2 +- .../INetworkStatsProviderCallback.aidl | 2 +- .../provider/NetworkStatsProvider.java | 58 ++++++++++++++++--- .../server/net/NetworkStatsService.java | 10 ++-- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 4078b24921..74c3ba44b6 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -23,6 +23,6 @@ package android.net.netstats.provider; */ oneway interface INetworkStatsProvider { void onRequestStatsUpdate(int token); - void onSetLimit(String iface, long quotaBytes); void onSetAlert(long quotaBytes); + void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index bd336dd348..7eaa01e262 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,6 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyLimitReached(); + void notifyWarningOrLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 7639d2244c..65b336ad6f 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -29,7 +29,8 @@ import android.os.RemoteException; @SystemApi public abstract class NetworkStatsProvider { /** - * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} + * indicates there is no limit. */ public static final int QUOTA_UNLIMITED = -1; @@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider { } @Override - public void onSetLimit(String iface, long quotaBytes) { - NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); } @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); + public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { + NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); } }; @@ -145,11 +146,28 @@ public abstract class NetworkStatsProvider { } /** - * Notify system that the quota set by {@code onSetLimit} has been reached. + * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. + * + * @hide + */ + // TODO: Expose as system API. + public void notifyWarningReached() { + try { + // Reuse the code path to notify warning reached with limit reached + // since framework handles them in the same way. + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@link #onSetLimit} or limit set by + * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -180,8 +198,34 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ + // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + /** + * Called by {@code NetworkStatsService} when setting the interface quotas for the specified + * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system + * will not call {@link #onSetLimit}. When this method is called, the implementation + * should behave as follows: + * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. + * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param warningBytes the warning defined as the number of bytes, starting from zero and + * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates + * there is no warning. + * @param limitBytes the limit defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + * + * @hide + */ + // TODO: Expose as system API. + public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { + // Backward compatibility for those who didn't override this function. + onSetLimit(iface, limitBytes); + } + /** * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index fe43c311da..785e487ed1 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1676,7 +1676,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); + // TODO: Set warning accordingly. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, + NetworkStatsProvider.QUOTA_UNLIMITED, quota)); } } @@ -2071,10 +2073,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": onLimitReached"); + public void notifyWarningOrLimitReached() { + Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderLimitReached(mTag); + .onStatsProviderWarningOrLimitReached(mTag); } @Override From 0141e8f8f8cfa0a935a9fd892f706d42dcc346d6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 24 Mar 2021 14:17:19 +0800 Subject: [PATCH 0901/1150] [SP29] Send interface warning bytes to NetworkStatsProvider This change contains necessary modification in NPMS and NSS to send warning bytes to NetworkStatsProvider. But since no any provider has been upgraded to handle such parameter. Thus, no behavior change is made in this patch. Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest#testStatsProviderWarningAndLimitReached Bug: 149467454 Bug: 170699770 Bug: 170179169 Ignore-AOSP-First: avoid long automerger delay Change-Id: I6c4863030c36328db571294fd12a40e59864def5 --- .../com/android/server/net/NetworkStatsService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 785e487ed1..de5aae07d6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1674,11 +1674,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - // TODO: Set warning accordingly. + public void setStatsProviderWarningAndLimitAsync( + @NonNull String iface, long warning, long limit) { + if (LOGV) { + Slog.v(TAG, "setStatsProviderWarningAndLimitAsync(" + + iface + "," + warning + "," + limit + ")"); + } invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - NetworkStatsProvider.QUOTA_UNLIMITED, quota)); + warning, limit)); } } From a22175603b1d3ce3486b2b61e611b4b062799ff9 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 19:45:05 +0800 Subject: [PATCH 0902/1150] [SP31] Expose onSetWarningAndLimit System API Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Bug: 149467454 CTS-Coverage-Bug: 183598414 Ignore-AOSP-First: avoid long automerger delay Change-Id: I6f5e22e3a7b80a38cae9f3c5d7296a1dff34facf --- .../net/netstats/provider/NetworkStatsProvider.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 65b336ad6f..23fc06927e 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -147,10 +147,7 @@ public abstract class NetworkStatsProvider { /** * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. - * - * @hide */ - // TODO: Expose as system API. public void notifyWarningReached() { try { // Reuse the code path to notify warning reached with limit reached @@ -198,7 +195,6 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ - // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); /** @@ -217,10 +213,7 @@ public abstract class NetworkStatsProvider { * there is no warning. * @param limitBytes the limit defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - * - * @hide */ - // TODO: Expose as system API. public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { // Backward compatibility for those who didn't override this function. onSetLimit(iface, limitBytes); From 8482bac84f334452f30e55ce4efa143271ced841 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 10:33:16 +0800 Subject: [PATCH 0903/1150] [SP28] Add API for set data warning To have better control and race-free of set data warning to tether offload hardware, an interface of set warning and limit at the same time in the NetworkStatsProvider is needed. This is a no-op change which expose such interface with minimum changes in service side to get build pass. The implementation would be included in follow-up patches. Test: atest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest Test: atest GtsNetworkStackHostTestCases Test: m doc-comment-check-docs Bug: 149467454 Bug: 170699770 Bug: 170179169 Merged-In: I6ee661497f7dedb871c85786d1950cab951d8aa2 Change-Id: I6ee661497f7dedb871c85786d1950cab951d8aa2 (cherry-picked from ag/13959436) --- .../provider/INetworkStatsProvider.aidl | 2 +- .../INetworkStatsProviderCallback.aidl | 2 +- .../provider/NetworkStatsProvider.java | 58 ++++++++++++++++--- .../server/net/NetworkStatsService.java | 10 ++-- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 4078b24921..74c3ba44b6 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -23,6 +23,6 @@ package android.net.netstats.provider; */ oneway interface INetworkStatsProvider { void onRequestStatsUpdate(int token); - void onSetLimit(String iface, long quotaBytes); void onSetAlert(long quotaBytes); + void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index bd336dd348..7eaa01e262 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,6 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyLimitReached(); + void notifyWarningOrLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 7639d2244c..65b336ad6f 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -29,7 +29,8 @@ import android.os.RemoteException; @SystemApi public abstract class NetworkStatsProvider { /** - * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} + * indicates there is no limit. */ public static final int QUOTA_UNLIMITED = -1; @@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider { } @Override - public void onSetLimit(String iface, long quotaBytes) { - NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); } @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); + public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { + NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); } }; @@ -145,11 +146,28 @@ public abstract class NetworkStatsProvider { } /** - * Notify system that the quota set by {@code onSetLimit} has been reached. + * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. + * + * @hide + */ + // TODO: Expose as system API. + public void notifyWarningReached() { + try { + // Reuse the code path to notify warning reached with limit reached + // since framework handles them in the same way. + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@link #onSetLimit} or limit set by + * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -180,8 +198,34 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ + // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + /** + * Called by {@code NetworkStatsService} when setting the interface quotas for the specified + * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system + * will not call {@link #onSetLimit}. When this method is called, the implementation + * should behave as follows: + * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. + * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param warningBytes the warning defined as the number of bytes, starting from zero and + * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates + * there is no warning. + * @param limitBytes the limit defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + * + * @hide + */ + // TODO: Expose as system API. + public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { + // Backward compatibility for those who didn't override this function. + onSetLimit(iface, limitBytes); + } + /** * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7b376847fd..d878347104 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1675,7 +1675,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); + // TODO: Set warning accordingly. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, + NetworkStatsProvider.QUOTA_UNLIMITED, quota)); } } @@ -2070,10 +2072,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": onLimitReached"); + public void notifyWarningOrLimitReached() { + Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderLimitReached(mTag); + .onStatsProviderWarningOrLimitReached(mTag); } @Override From 49642c1eae19e4bc5104b5845facd1dbee823ca1 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 24 Mar 2021 14:17:19 +0800 Subject: [PATCH 0904/1150] [SP29] Send interface warning bytes to NetworkStatsProvider This change contains necessary modification in NPMS and NSS to send warning bytes to NetworkStatsProvider. But since no any provider has been upgraded to handle such parameter. Thus, no behavior change is made in this patch. Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest#testStatsProviderWarningAndLimitReached Bug: 149467454 Bug: 170699770 Bug: 170179169 Merged-In: I6c4863030c36328db571294fd12a40e59864def5 Change-Id: I6c4863030c36328db571294fd12a40e59864def5 (cherry-picked from ag/13982166) --- .../com/android/server/net/NetworkStatsService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index d878347104..600f53b9b3 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1673,11 +1673,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - // TODO: Set warning accordingly. + public void setStatsProviderWarningAndLimitAsync( + @NonNull String iface, long warning, long limit) { + if (LOGV) { + Slog.v(TAG, "setStatsProviderWarningAndLimitAsync(" + + iface + "," + warning + "," + limit + ")"); + } invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - NetworkStatsProvider.QUOTA_UNLIMITED, quota)); + warning, limit)); } } From 46ecccc4d4a510726803f7af6057d0c04be9dd70 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 19:45:05 +0800 Subject: [PATCH 0905/1150] [SP31] Expose onSetWarningAndLimit System API Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Bug: 149467454 CTS-Coverage-Bug: 183598414 Merged-In: I6f5e22e3a7b80a38cae9f3c5d7296a1dff34facf Change-Id: I6f5e22e3a7b80a38cae9f3c5d7296a1dff34facf (cherry-picked from ag/13981689) --- .../net/netstats/provider/NetworkStatsProvider.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 65b336ad6f..23fc06927e 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -147,10 +147,7 @@ public abstract class NetworkStatsProvider { /** * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. - * - * @hide */ - // TODO: Expose as system API. public void notifyWarningReached() { try { // Reuse the code path to notify warning reached with limit reached @@ -198,7 +195,6 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ - // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); /** @@ -217,10 +213,7 @@ public abstract class NetworkStatsProvider { * there is no warning. * @param limitBytes the limit defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - * - * @hide */ - // TODO: Expose as system API. public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { // Backward compatibility for those who didn't override this function. onSetLimit(iface, limitBytes); From bd7052a00a557cf41c9c1ac2de38e47f8cced0f3 Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 23:08:33 +0800 Subject: [PATCH 0906/1150] Use getAllInterfaceNames to get all interface names The current design is using hidden API - getStackedLinks() to get LinkProperties then call getInterfaceName() to get the interface name. In fact, this behavior could be replaced by system API - getAllInterfaceNames(). Bug: 182963397 Test: atest FrameworksNetTests Test: atest CtsNetTestCases Change-Id: Id2b19dc5099355af69d23a6d99d2b7e6c0e1e88a Merged-In: Id2b19dc5099355af69d23a6d99d2b7e6c0e1e88a (cherry-picked from ag/13927660) --- .../server/net/NetworkStatsService.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 7b376847fd..fe43c311da 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -92,7 +92,6 @@ import android.net.DataUsageRequest; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; -import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; @@ -131,6 +130,7 @@ import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -1358,17 +1358,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // (or non eBPF offloaded) TX they would appear on both, however egress interface // accounting is explicitly bypassed for traffic from the clat uid. // - final List stackedLinks = snapshot.linkProperties.getStackedLinks(); - for (LinkProperties stackedLink : stackedLinks) { - final String stackedIface = stackedLink.getInterfaceName(); - if (stackedIface != null) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); + // TODO: This code might be combined to above code. + for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + // baseIface has been handled, so ignore it. + if (TextUtils.equals(baseIface, iface)) continue; + if (iface != null) { + findOrCreateNetworkIdentitySet(mActiveIfaces, iface).add(ident); + findOrCreateNetworkIdentitySet(mActiveUidIfaces, iface).add(ident); if (isMobile) { - mobileIfaces.add(stackedIface); + mobileIfaces.add(iface); } - mStatsFactory.noteStackedIface(stackedIface, baseIface); + mStatsFactory.noteStackedIface(iface, baseIface); } } } From a3bf03ed4007dc4890360a3f2662cd00fef86d5f Mon Sep 17 00:00:00 2001 From: lucaslin Date: Fri, 19 Mar 2021 16:06:33 +0800 Subject: [PATCH 0907/1150] Use public API Network#getNetId() to get netid Network class will be a part of mainline module, external callers cannot call its hidden constant. Use public API - getNetId() to get netid instead. Bug: 182963397 Test: m Change-Id: I6d5dd0a8c3879df7bdc1d58e36022045c303bb40 Merged-In: I6d5dd0a8c3879df7bdc1d58e36022045c303bb40 (cherry-picked from ag/13927649) --- services/core/java/com/android/server/IpSecService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 4c3c6ef21f..794cb9301d 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1651,7 +1651,7 @@ public class IpSecService extends IIpSecService.Stub { c.getMode(), c.getSourceAddress(), c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().netId : 0, + (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, spiRecord.getSpi(), c.getMarkValue(), c.getMarkMask(), From b0e21ab9af58e65eea042898468fa9139d5ff2dc Mon Sep 17 00:00:00 2001 From: lesl Date: Tue, 9 Mar 2021 23:50:11 +0800 Subject: [PATCH 0908/1150] Fix Wi-Fi SSID null handling When Wi-Fi SSID is null in NetworkCapabilities, get Wi-Fi SSID from connection info (WifiInfo) which is non-null design. Bug: 176396812 Test: FrameworksNetTests NetworkPolicyManagerServiceTest Change-Id: I59c7d8f7e176d0c6bb100721269f3f6165f0ca21 --- core/java/android/net/NetworkIdentity.java | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b037261f0b..1eef7d9a53 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -198,15 +198,11 @@ public class NetworkIdentity implements Comparable { final int oemManaged = getOemBitfield(snapshot.networkCapabilities); if (legacyType == TYPE_WIFI) { - if (snapshot.networkCapabilities.getSsid() != null) { - networkId = snapshot.networkCapabilities.getSsid(); - if (networkId == null) { - // TODO: Figure out if this code path never runs. If so, remove them. - final WifiManager wifi = (WifiManager) context.getSystemService( - Context.WIFI_SERVICE); - final WifiInfo info = wifi.getConnectionInfo(); - networkId = info != null ? info.getSSID() : null; - } + networkId = snapshot.networkCapabilities.getSsid(); + if (networkId == null) { + final WifiManager wifi = context.getSystemService(WifiManager.class); + final WifiInfo info = wifi.getConnectionInfo(); + networkId = info != null ? info.getSSID() : null; } } From 481a85d41f2c9ae41cb2861df0abcba1495e6e95 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 3 Feb 2021 00:51:29 +0800 Subject: [PATCH 0909/1150] Migrate hidden API in IpConfigStore to formal API IpConfiguration and StaticIpConfiguration are included in framework-connectivity which cannot have external hidden API usages dependencies on them. IpConfiguration and StaticIpConfiguration provide builder and getter methods for the fields of the objects which are formal APIs. So, replace the usages in IpConfigStore with those formal APIs to remove the dependencies. (cherry-picked from ag/13929104) Bug: 178777253 Test: FrameworksServicesTests:IpConfigStoreTest Merged-In: Ie9e6af0efe2c39667bb8faa1e3a498b1f61e1432 Change-Id: Ie9e6af0efe2c39667bb8faa1e3a498b1f61e1432 --- .../com/android/server/net/IpConfigStore.java | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index cc3a002adc..512d2192b9 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -42,6 +42,8 @@ import java.io.IOException; import java.io.InputStream; import java.net.Inet4Address; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; public class IpConfigStore { private static final String TAG = "IpConfigStore"; @@ -83,25 +85,25 @@ public class IpConfigStore { boolean written = false; try { - switch (config.ipAssignment) { + switch (config.getIpAssignment()) { case STATIC: out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); - StaticIpConfiguration staticIpConfiguration = config.staticIpConfiguration; + out.writeUTF(config.getIpAssignment().toString()); + StaticIpConfiguration staticIpConfiguration = config.getStaticIpConfiguration(); if (staticIpConfiguration != null) { - if (staticIpConfiguration.ipAddress != null) { - LinkAddress ipAddress = staticIpConfiguration.ipAddress; + if (staticIpConfiguration.getIpAddress() != null) { + LinkAddress ipAddress = staticIpConfiguration.getIpAddress(); out.writeUTF(LINK_ADDRESS_KEY); out.writeUTF(ipAddress.getAddress().getHostAddress()); out.writeInt(ipAddress.getPrefixLength()); } - if (staticIpConfiguration.gateway != null) { + if (staticIpConfiguration.getGateway() != null) { out.writeUTF(GATEWAY_KEY); out.writeInt(0); // Default route. out.writeInt(1); // Have a gateway. - out.writeUTF(staticIpConfiguration.gateway.getHostAddress()); + out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); } - for (InetAddress inetAddr : staticIpConfiguration.dnsServers) { + for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) { out.writeUTF(DNS_KEY); out.writeUTF(inetAddr.getHostAddress()); } @@ -110,7 +112,7 @@ public class IpConfigStore { break; case DHCP: out.writeUTF(IP_ASSIGNMENT_KEY); - out.writeUTF(config.ipAssignment.toString()); + out.writeUTF(config.getIpAssignment().toString()); written = true; break; case UNASSIGNED: @@ -121,13 +123,13 @@ public class IpConfigStore { break; } - switch (config.proxySettings) { + switch (config.getProxySettings()) { case STATIC: - ProxyInfo proxyProperties = config.httpProxy; + ProxyInfo proxyProperties = config.getHttpProxy(); String exclusionList = ProxyUtils.exclusionListAsString( proxyProperties.getExclusionList()); out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); out.writeUTF(PROXY_HOST_KEY); out.writeUTF(proxyProperties.getHost()); out.writeUTF(PROXY_PORT_KEY); @@ -139,16 +141,16 @@ public class IpConfigStore { written = true; break; case PAC: - ProxyInfo proxyPacProperties = config.httpProxy; + ProxyInfo proxyPacProperties = config.getHttpProxy(); out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); out.writeUTF(PROXY_PAC_FILE); out.writeUTF(proxyPacProperties.getPacFileUrl().toString()); written = true; break; case NONE: out.writeUTF(PROXY_SETTINGS_KEY); - out.writeUTF(config.proxySettings.toString()); + out.writeUTF(config.getProxySettings().toString()); written = true; break; case UNASSIGNED: @@ -267,11 +269,14 @@ public class IpConfigStore { IpAssignment ipAssignment = IpAssignment.DHCP; ProxySettings proxySettings = ProxySettings.NONE; StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); + LinkAddress linkAddress = null; + InetAddress gatewayAddress = null; String proxyHost = null; String pacFileUrl = null; int proxyPort = -1; String exclusionList = null; String key; + final List dnsServers = new ArrayList<>(); do { key = in.readUTF(); @@ -286,15 +291,15 @@ public class IpConfigStore { } else if (key.equals(IP_ASSIGNMENT_KEY)) { ipAssignment = IpAssignment.valueOf(in.readUTF()); } else if (key.equals(LINK_ADDRESS_KEY)) { - LinkAddress linkAddr = + LinkAddress parsedLinkAddress = new LinkAddress( InetAddresses.parseNumericAddress(in.readUTF()), in.readInt()); - if (linkAddr.getAddress() instanceof Inet4Address && - staticIpConfiguration.ipAddress == null) { - staticIpConfiguration.ipAddress = linkAddr; + if (parsedLinkAddress.getAddress() instanceof Inet4Address + && linkAddress == null) { + linkAddress = parsedLinkAddress; } else { - loge("Non-IPv4 or duplicate address: " + linkAddr); + loge("Non-IPv4 or duplicate address: " + parsedLinkAddress); } } else if (key.equals(GATEWAY_KEY)) { LinkAddress dest = null; @@ -302,8 +307,8 @@ public class IpConfigStore { if (version == 1) { // only supported default gateways - leave the dest/prefix empty gateway = InetAddresses.parseNumericAddress(in.readUTF()); - if (staticIpConfiguration.gateway == null) { - staticIpConfiguration.gateway = gateway; + if (gatewayAddress == null) { + gatewayAddress = gateway; } else { loge("Duplicate gateway: " + gateway.getHostAddress()); } @@ -318,16 +323,14 @@ public class IpConfigStore { gateway = InetAddresses.parseNumericAddress(in.readUTF()); } RouteInfo route = new RouteInfo(dest, gateway); - if (route.isIPv4Default() && - staticIpConfiguration.gateway == null) { - staticIpConfiguration.gateway = gateway; + if (route.isIPv4Default() && gatewayAddress == null) { + gatewayAddress = gateway; } else { loge("Non-IPv4 default or duplicate route: " + route); } } } else if (key.equals(DNS_KEY)) { - staticIpConfiguration.dnsServers.add( - InetAddresses.parseNumericAddress(in.readUTF())); + dnsServers.add(InetAddresses.parseNumericAddress(in.readUTF())); } else if (key.equals(PROXY_SETTINGS_KEY)) { proxySettings = ProxySettings.valueOf(in.readUTF()); } else if (key.equals(PROXY_HOST_KEY)) { @@ -348,25 +351,31 @@ public class IpConfigStore { } } while (true); + staticIpConfiguration = new StaticIpConfiguration.Builder() + .setIpAddress(linkAddress) + .setGateway(gatewayAddress) + .setDnsServers(dnsServers) + .build(); + if (uniqueToken != null) { IpConfiguration config = new IpConfiguration(); networks.put(uniqueToken, config); switch (ipAssignment) { case STATIC: - config.staticIpConfiguration = staticIpConfiguration; - config.ipAssignment = ipAssignment; + config.setStaticIpConfiguration(staticIpConfiguration); + config.setIpAssignment(ipAssignment); break; case DHCP: - config.ipAssignment = ipAssignment; + config.setIpAssignment(ipAssignment); break; case UNASSIGNED: loge("BUG: Found UNASSIGNED IP on file, use DHCP"); - config.ipAssignment = IpAssignment.DHCP; + config.setIpAssignment(IpAssignment.DHCP); break; default: loge("Ignore invalid ip assignment while reading."); - config.ipAssignment = IpAssignment.UNASSIGNED; + config.setIpAssignment(IpAssignment.UNASSIGNED); break; } @@ -374,25 +383,25 @@ public class IpConfigStore { case STATIC: ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy(proxyHost, proxyPort, ProxyUtils.exclusionStringAsList(exclusionList)); - config.proxySettings = proxySettings; - config.httpProxy = proxyInfo; + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyInfo); break; case PAC: ProxyInfo proxyPacProperties = ProxyInfo.buildPacProxy(Uri.parse(pacFileUrl)); - config.proxySettings = proxySettings; - config.httpProxy = proxyPacProperties; + config.setProxySettings(proxySettings); + config.setHttpProxy(proxyPacProperties); break; case NONE: - config.proxySettings = proxySettings; + config.setProxySettings(proxySettings); break; case UNASSIGNED: loge("BUG: Found UNASSIGNED proxy on file, use NONE"); - config.proxySettings = ProxySettings.NONE; + config.setProxySettings(ProxySettings.NONE); break; default: loge("Ignore invalid proxy settings while reading"); - config.proxySettings = ProxySettings.UNASSIGNED; + config.setProxySettings(ProxySettings.UNASSIGNED); break; } } else { From c6cb931f32e6b953c368159484ded548819b4a80 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 18 Mar 2021 21:35:45 +0800 Subject: [PATCH 0910/1150] Fix IpConfigStore dependencies on framework-connectivity This change fixes IpConfigStore dependencies on framework-connectivity hidden APIs. - Use the version of SystemApi to new RouteInfo. - Inline the implementation of isIPv4Default() directly because isDefaultRoute() is a public API so it can be used in this class. (cherry-picked from ag/13945685) Bug: 178777253 Test: FrameworksServicesTests:IpConfigStoreTest Merged-In: I5ed1bc8bc8bee5b0c795fd8577a2d64628998e51 Change-Id: I5ed1bc8bc8bee5b0c795fd8577a2d64628998e51 --- .../java/com/android/server/net/IpConfigStore.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index 512d2192b9..df1eb6d9fe 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -22,7 +22,6 @@ import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; import android.net.LinkAddress; import android.net.ProxyInfo; -import android.net.RouteInfo; import android.net.StaticIpConfiguration; import android.net.Uri; import android.util.ArrayMap; @@ -322,11 +321,14 @@ public class IpConfigStore { if (in.readInt() == 1) { gateway = InetAddresses.parseNumericAddress(in.readUTF()); } - RouteInfo route = new RouteInfo(dest, gateway); - if (route.isIPv4Default() && gatewayAddress == null) { + // If the destination is a default IPv4 route, use the gateway + // address unless already set. + if (dest.getAddress() instanceof Inet4Address + && dest.getPrefixLength() == 0 && gatewayAddress == null) { gatewayAddress = gateway; } else { - loge("Non-IPv4 default or duplicate route: " + route); + loge("Non-IPv4 default or duplicate route: " + + dest.getAddress()); } } } else if (key.equals(DNS_KEY)) { From 5b5b782644999b5c2cc7f1204444b09faef80d89 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 8 Apr 2021 15:32:08 +0900 Subject: [PATCH 0911/1150] Add documentation on EthernetNetworkSpecifier API Add javadoc on the constructor and getInterfaceName method. Fixes: 182979732 Test: m Change-Id: Iced805149a8344b953331501b48184661be0053a --- core/java/android/net/EthernetNetworkSpecifier.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/core/java/android/net/EthernetNetworkSpecifier.java index e1685887e8..62c5761442 100644 --- a/core/java/android/net/EthernetNetworkSpecifier.java +++ b/core/java/android/net/EthernetNetworkSpecifier.java @@ -42,15 +42,22 @@ public final class EthernetNetworkSpecifier extends NetworkSpecifier implements @NonNull private final String mInterfaceName; + /** + * Create a new EthernetNetworkSpecifier. + * @param interfaceName Name of the ethernet interface the specifier refers to. + */ public EthernetNetworkSpecifier(@NonNull String interfaceName) { Preconditions.checkStringNotEmpty(interfaceName); mInterfaceName = interfaceName; } - // This may be null in the future to support specifiers based on data other than the interface - // name. + /** + * Get the name of the ethernet interface the specifier refers to. + */ @Nullable public String getInterfaceName() { + // This may be null in the future to support specifiers based on data other than the + // interface name. return mInterfaceName; } From 4e878ad3f3e2a49b4295e508725bcb0f1b17a64a Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 9 Apr 2021 15:47:36 +0800 Subject: [PATCH 0912/1150] Rename FIRST_SDK_INT to DEVICE_INITIAL_SDK_INT As API review feedback, rename Build#VERSION#FIRST_SDK_INT to Build#VERSION#DEVICE_INITIAL_SDK_INT. As well as update all usage in frameworks and tests. Bug: 184735771 Test: m Change-Id: I72660959cb4e638a8e80fcf2f4e96ea172969f44 --- core/java/android/net/IpSecAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 8f1e2defd2..7ef5bac092 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -354,7 +354,7 @@ public final class IpSecAlgorithm implements Parcelable { } for (Entry entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { - if (Build.VERSION.FIRST_SDK_INT >= entry.getValue()) { + if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) { enabledAlgos.add(entry.getKey()); } } From ae6367012acf56f7dc998a9a03f0079694b93e1d Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Thu, 8 Apr 2021 19:42:30 +0800 Subject: [PATCH 0913/1150] Resolve hidden connectivity methods dependency This commit resolves the dependency under batterystatstests, servicestests and coretests with hidden connectivity module codes. Because of connectivity modularization work, the hidden connectivity methods are not accessible outside modules. Update tests with alternative ways. Bug: 182859030 Test: atest Change-Id: I8294ae4167ee5f95137e0be0f7464429ed3f3322 --- .../android/server/net/IpConfigStoreTest.java | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java index 401d6e30df..2f771260ac 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java @@ -39,6 +39,8 @@ import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.InetAddress; +import java.util.ArrayList; import java.util.Arrays; /** @@ -53,8 +55,8 @@ public class IpConfigStoreTest { ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(byteStream); - IpConfiguration expectedConfig = new IpConfiguration(IpAssignment.DHCP, - ProxySettings.NONE, null, null); + final IpConfiguration expectedConfig = + newIpConfiguration(IpAssignment.DHCP, ProxySettings.NONE, null, null); // Emulate writing to old format. writeDhcpConfigV2(outputStream, KEY_CONFIG, expectedConfig); @@ -78,18 +80,23 @@ public class IpConfigStoreTest { final String DNS_IP_ADDR_1 = "1.2.3.4"; final String DNS_IP_ADDR_2 = "5.6.7.8"; - StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration(); - staticIpConfiguration.ipAddress = new LinkAddress(IP_ADDR_1); - staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); - staticIpConfiguration.dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); + final ArrayList dnsServers = new ArrayList<>(); + dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); + dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); + final StaticIpConfiguration staticIpConfiguration1 = new StaticIpConfiguration.Builder() + .setIpAddress(new LinkAddress(IP_ADDR_1)) + .setDnsServers(dnsServers).build(); + final StaticIpConfiguration staticIpConfiguration2 = new StaticIpConfiguration.Builder() + .setIpAddress(new LinkAddress(IP_ADDR_2)) + .setDnsServers(dnsServers).build(); ProxyInfo proxyInfo = ProxyInfo.buildDirectProxy("10.10.10.10", 88, Arrays.asList("host1", "host2")); - IpConfiguration expectedConfig1 = new IpConfiguration(IpAssignment.STATIC, - ProxySettings.STATIC, staticIpConfiguration, proxyInfo); - IpConfiguration expectedConfig2 = new IpConfiguration(expectedConfig1); - expectedConfig2.getStaticIpConfiguration().ipAddress = new LinkAddress(IP_ADDR_2); + IpConfiguration expectedConfig1 = newIpConfiguration(IpAssignment.STATIC, + ProxySettings.STATIC, staticIpConfiguration1, proxyInfo); + IpConfiguration expectedConfig2 = newIpConfiguration(IpAssignment.STATIC, + ProxySettings.STATIC, staticIpConfiguration2, proxyInfo); ArrayMap expectedNetworks = new ArrayMap<>(); expectedNetworks.put(IFACE_1, expectedConfig1); @@ -107,14 +114,24 @@ public class IpConfigStoreTest { assertEquals(expectedNetworks.get(IFACE_2), actualNetworks.get(IFACE_2)); } + private IpConfiguration newIpConfiguration(IpAssignment ipAssignment, + ProxySettings proxySettings, StaticIpConfiguration staticIpConfig, ProxyInfo info) { + final IpConfiguration config = new IpConfiguration(); + config.setIpAssignment(ipAssignment); + config.setProxySettings(proxySettings); + config.setStaticIpConfiguration(staticIpConfig); + config.setHttpProxy(info); + return config; + } + // This is simplified snapshot of code that was used to store values in V2 format (key as int). private static void writeDhcpConfigV2(DataOutputStream out, int configKey, IpConfiguration config) throws IOException { out.writeInt(2); // VERSION 2 - switch (config.ipAssignment) { + switch (config.getIpAssignment()) { case DHCP: out.writeUTF("ipAssignment"); - out.writeUTF(config.ipAssignment.toString()); + out.writeUTF(config.getIpAssignment().toString()); break; default: fail("Not supported in test environment"); From f9707258edcdd478fe92a3ba6f2c4d35cc8b1ba4 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 31 Dec 2020 17:26:28 +0800 Subject: [PATCH 0914/1150] wifi data usage: support to get carrier merged wifi network. Carrier merged wifi network is a specific cerrier wifi network which provides the same user experience as mobile. To support data usage accounting for carrier merged wifi, the change provide several APIs in NetworkTemplate: 1. extend buildTemplateWifi so it could be used for matching wifi networks with subscriber Id (IMSI). 2. add buildTemplateCarrier to let NetworkPolicyManagerService creates a single policy for a given carrier regardless of network type. Bug: 176396812 Test: atest -c NetworkTemplateTest Test: atest -c NetworkStatsServiceTest Test: Manual Test with test code on mobile and wifi network. 1. buildTemplateCarrier includes the carrier wifi and mobile usage 2. buildTemplateWifi can get carrier wifi usage and support the filter via subscriberId Change-Id: I667b4adf3eec0bdd3a7385109dd8c1fae8e7be32 --- core/java/android/net/NetworkTemplate.java | 160 +++++++++++++++++++-- 1 file changed, 147 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c83dd99c2a..d3c8957494 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -82,6 +82,24 @@ public class NetworkTemplate implements Parcelable { public static final int MATCH_WIFI_WILDCARD = 7; public static final int MATCH_BLUETOOTH = 8; public static final int MATCH_PROXY = 9; + public static final int MATCH_CARRIER = 10; + + /** + * Value of the match rule of the subscriberId to match networks with specific subscriberId. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; + /** + * Value of the match rule of the subscriberId to match networks with any subscriberId which + * includes null and non-null. + */ + public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; + + /** + * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that + * should be fixed), so it's not possible to want to match null vs + * non-null. Therefore it's fine to use null as a sentinel for Network ID. + */ + public static final String WIFI_NETWORKID_ALL = null; /** * Include all network types when filtering. This is meant to merge in with the @@ -125,6 +143,7 @@ public class NetworkTemplate implements Parcelable { case MATCH_WIFI_WILDCARD: case MATCH_BLUETOOTH: case MATCH_PROXY: + case MATCH_CARRIER: return true; default: @@ -168,10 +187,12 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL); + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -189,6 +210,8 @@ public class NetworkTemplate implements Parcelable { */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { + // TODO: Consider replace this with MATCH_WIFI with NETWORK_ID_ALL + // and SUBSCRIBER_ID_MATCH_RULE_ALL. return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } @@ -202,8 +225,27 @@ public class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. */ - public static NetworkTemplate buildTemplateWifi(String networkId) { - return new NetworkTemplate(MATCH_WIFI, null, networkId); + public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { + Objects.requireNonNull(networkId); + return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, + new String[] { null } /* matchSubscriberIds */, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_ALL); + } + + /** + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, + * and IMSI. + * + * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + */ + public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, + @Nullable String subscriberId) { + return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, + networkId, METERED_ALL, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -231,6 +273,14 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_PROXY, null, null); } + /** + * Template to match all carrier networks with the given IMSI. + */ + public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + Objects.requireNonNull(subscriberId); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + } + private final int mMatchRule; private final String mSubscriberId; @@ -251,10 +301,26 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; private final int mSubType; + private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; + private void checkValidSubscriberIdMatchRule() { + switch (mMatchRule) { + case MATCH_MOBILE: + case MATCH_CARRIER: + // MOBILE and CARRIER templates must always specify a subscriber ID. + if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" + + "on match rule: " + getMatchRuleName(mMatchRule)); + } + return; + default: + return; + } + } + @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -263,14 +329,25 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL); + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); + } + + // TODO: Remove it after updating all of the caller. + public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, + String networkId, int metered, int roaming, int defaultNetwork, int subType, + int oemManaged) { + this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, + defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); } public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, - int oemManaged) { + int oemManaged, int subscriberIdMatchRule) { mMatchRule = matchRule; mSubscriberId = subscriberId; + // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when + // mSubscriberId is null mMatchSubscriberIds = matchSubscriberIds; mNetworkId = networkId; mMetered = metered; @@ -278,7 +355,8 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = defaultNetwork; mSubType = subType; mOemManaged = oemManaged; - + mSubscriberIdMatchRule = subscriberIdMatchRule; + checkValidSubscriberIdMatchRule(); if (!isKnownMatchRule(matchRule)) { Log.e(TAG, "Unknown network template rule " + matchRule + " will not match any identity."); @@ -295,6 +373,7 @@ public class NetworkTemplate implements Parcelable { mDefaultNetwork = in.readInt(); mSubType = in.readInt(); mOemManaged = in.readInt(); + mSubscriberIdMatchRule = in.readInt(); } @Override @@ -308,6 +387,7 @@ public class NetworkTemplate implements Parcelable { dest.writeInt(mDefaultNetwork); dest.writeInt(mSubType); dest.writeInt(mOemManaged); + dest.writeInt(mSubscriberIdMatchRule); } @Override @@ -346,13 +426,15 @@ public class NetworkTemplate implements Parcelable { if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(mOemManaged); } + builder.append(", subscriberIdMatchRule=") + .append(subscriberIdMatchRuleToString(mSubscriberIdMatchRule)); return builder.toString(); } @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType, mOemManaged); + mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -366,11 +448,23 @@ public class NetworkTemplate implements Parcelable { && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mSubType == other.mSubType - && mOemManaged == other.mOemManaged; + && mOemManaged == other.mOemManaged + && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; } return false; } + private String subscriberIdMatchRuleToString(int rule) { + switch (rule) { + case SUBSCRIBER_ID_MATCH_RULE_EXACT: + return "EXACT_MATCH"; + case SUBSCRIBER_ID_MATCH_RULE_ALL: + return "ALL"; + default: + return "Unknown rule " + rule; + } + } + public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -386,6 +480,14 @@ public class NetworkTemplate implements Parcelable { case MATCH_MOBILE_WILDCARD: case MATCH_WIFI_WILDCARD: return false; + case MATCH_CARRIER: + return mSubscriberId != null; + case MATCH_WIFI: + if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + return false; + } + return true; default: return true; } @@ -405,6 +507,10 @@ public class NetworkTemplate implements Parcelable { return mNetworkId; } + public int getSubscriberIdMatchRule() { + return mSubscriberIdMatchRule; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ @@ -429,6 +535,8 @@ public class NetworkTemplate implements Parcelable { return matchesBluetooth(ident); case MATCH_PROXY: return matchesProxy(ident); + case MATCH_CARRIER: + return matchesCarrier(ident); default: // We have no idea what kind of network template we are, so we // just claim not to match anything. @@ -466,8 +574,23 @@ public class NetworkTemplate implements Parcelable { || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); } - public boolean matchesSubscriberId(String subscriberId) { - return ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + /** + * Check if this template matches {@code subscriberId}. Returns true if this + * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a + * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + */ + public boolean matchesSubscriberId(@Nullable String subscriberId) { + return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL + || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + } + + /** + * Check if network with matching SSID. Returns true when the SSID matches, or when + * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + */ + private boolean matchesWifiNetworkId(@Nullable String networkId) { + return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } /** @@ -566,8 +689,8 @@ public class NetworkTemplate implements Parcelable { private boolean matchesWifi(NetworkIdentity ident) { switch (ident.mType) { case TYPE_WIFI: - return Objects.equals( - sanitizeSsid(mNetworkId), sanitizeSsid(ident.mNetworkId)); + return matchesSubscriberId(ident.mSubscriberId) + && matchesWifiNetworkId(ident.mNetworkId); default: return false; } @@ -583,6 +706,15 @@ public class NetworkTemplate implements Parcelable { return false; } + /** + * Check if matches carrier network. The carrier networks means it includes the subscriberId. + */ + private boolean matchesCarrier(NetworkIdentity ident) { + return ident.mSubscriberId != null + && !ArrayUtils.isEmpty(mMatchSubscriberIds) + && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + } + private boolean matchesMobileWildcard(NetworkIdentity ident) { if (ident.mType == TYPE_WIMAX) { return true; @@ -635,6 +767,8 @@ public class NetworkTemplate implements Parcelable { return "BLUETOOTH"; case MATCH_PROXY: return "PROXY"; + case MATCH_CARRIER: + return "CARRIER"; default: return "UNKNOWN(" + matchRule + ")"; } From 69c1f216b11d002fc2719e8167942f3fbcc8c6b5 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 16 Apr 2021 23:20:23 +0800 Subject: [PATCH 0915/1150] Add getters to UnderlyingNetworkInfo Address API review feedback, add getters to UnderlyingNetworkInfo instead of exposing fields. Instead of wasting memory by converting this into an array, have migrateTun take a List. In turn, tunAdjustmentInit should also take a List. Bug: 183972554 Test: atest android.net.UnderlyingNetworkInfoTest Change-Id: Id59744097208d91298a25ef110ade91a9cf291a1 --- core/java/android/net/NetworkStats.java | 31 +++++----- .../android/net/UnderlyingNetworkInfo.java | 60 ++++++++++++------- .../server/net/NetworkStatsFactory.java | 4 +- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index d42beae601..6ccbab7ed8 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -38,6 +38,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; @@ -1423,11 +1424,11 @@ public final class NetworkStats implements Parcelable { * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces) { + @NonNull List underlyingIfaces) { // Combined usage by all apps using VPN. final Entry tunIfaceTotal = new Entry(); // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()]; // Usage by VPN, summed across all its {@code underlyingIfaces}. final Entry underlyingIfacesTotal = new Entry(); @@ -1468,7 +1469,7 @@ public final class NetworkStats implements Parcelable { * {@code underlyingIfaces} */ private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { @@ -1488,8 +1489,8 @@ public final class NetworkStats implements Parcelable { if (recycle.uid == tunUid) { // Add up traffic through tunUid's underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + for (int j = 0; j < underlyingIfaces.size(); j++) { + if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { perInterfaceTotal[j].add(recycle); underlyingIfacesTotal.add(recycle); break; @@ -1515,12 +1516,12 @@ public final class NetworkStats implements Parcelable { * underlyingIfaces} */ private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { // Traffic that should be moved off of each underlying interface for tunUid (see // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.length]; - for (int i = 0; i < underlyingIfaces.length; i++) { + final Entry[] moved = new Entry[underlyingIfaces.size()]; + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i] = new Entry(); } @@ -1582,8 +1583,8 @@ public final class NetworkStats implements Parcelable { } // In a second pass, distribute these values across interfaces in the proportion that // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - tmpEntry.iface = underlyingIfaces[j]; + for (int j = 0; j < underlyingIfaces.size(); j++) { + tmpEntry.iface = underlyingIfaces.get(j); tmpEntry.rxBytes = 0; // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; @@ -1638,14 +1639,14 @@ public final class NetworkStats implements Parcelable { private void deductTrafficFromVpnApp( int tunUid, - @NonNull String[] underlyingIfaces, + @NonNull List underlyingIfaces, @NonNull Entry[] moved) { - for (int i = 0; i < underlyingIfaces.length; i++) { + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i].uid = tunUid; // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces[i]; + moved[i].iface = underlyingIfaces.get(i); moved[i].metered = METERED_ALL; moved[i].roaming = ROAMING_ALL; moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; @@ -1658,7 +1659,7 @@ public final class NetworkStats implements Parcelable { // METERED_NO, which should be the case as it comes directly from the /proc file. // We only blend in the roaming data after applying these adjustments, by checking the // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnBackground != -1) { // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed @@ -1666,7 +1667,7 @@ public final class NetworkStats implements Parcelable { tunSubtract(idxVpnBackground, this, moved[i]); } - final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved[i]); diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 7bf9231239..459fdacef8 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -37,36 +37,56 @@ import java.util.Objects; @SystemApi(client = MODULE_LIBRARIES) public final class UnderlyingNetworkInfo implements Parcelable { /** The owner of this network. */ - public final int ownerUid; + private final int mOwnerUid; + /** The interface name of this network. */ @NonNull - public final String iface; + private final String mIface; + /** The names of the interfaces underlying this network. */ @NonNull - public final List underlyingIfaces; + private final List mUnderlyingIfaces; public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, @NonNull List underlyingIfaces) { Objects.requireNonNull(iface); Objects.requireNonNull(underlyingIfaces); - this.ownerUid = ownerUid; - this.iface = iface; - this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); + mOwnerUid = ownerUid; + mIface = iface; + mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); } private UnderlyingNetworkInfo(@NonNull Parcel in) { - this.ownerUid = in.readInt(); - this.iface = in.readString(); - this.underlyingIfaces = new ArrayList<>(); - in.readList(this.underlyingIfaces, null /*classLoader*/); + mOwnerUid = in.readInt(); + mIface = in.readString(); + List underlyingIfaces = new ArrayList<>(); + in.readList(underlyingIfaces, null /*classLoader*/); + mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); + } + + /** Get the owner of this network. */ + public int getOwnerUid() { + return mOwnerUid; + } + + /** Get the interface name of this network. */ + @NonNull + public String getIface() { + return mIface; + } + + /** Get the names of the interfaces underlying this network. */ + @NonNull + public List getUnderlyingIfaces() { + return mUnderlyingIfaces; } @Override public String toString() { return "UnderlyingNetworkInfo{" - + "ownerUid=" + ownerUid - + ", iface='" + iface + '\'' - + ", underlyingIfaces='" + underlyingIfaces.toString() + '\'' + + "ownerUid=" + mOwnerUid + + ", iface='" + mIface + '\'' + + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\'' + '}'; } @@ -77,9 +97,9 @@ public final class UnderlyingNetworkInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(ownerUid); - dest.writeString(iface); - dest.writeList(underlyingIfaces); + dest.writeInt(mOwnerUid); + dest.writeString(mIface); + dest.writeList(mUnderlyingIfaces); } @NonNull @@ -103,13 +123,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (this == o) return true; if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; - return ownerUid == that.ownerUid - && Objects.equals(iface, that.iface) - && Objects.equals(underlyingIfaces, that.underlyingIfaces); + return mOwnerUid == that.getOwnerUid() + && Objects.equals(mIface, that.getIface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingIfaces()); } @Override public int hashCode() { - return Objects.hash(ownerUid, iface, underlyingIfaces); + return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index d042b882fe..e7c0a50163 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.iface, - info.underlyingIfaces.toArray(new String[0])); + delta.migrateTun(info.getOwnerUid(), info.getIface(), + info.getUnderlyingIfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } From 80a4d561a344c4e19578c3e0d5951c0baf16f6ee Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 20 Apr 2021 17:19:46 +0800 Subject: [PATCH 0916/1150] Add getters to NetworkStateSnapshot Address API council feedback, add getters to NetworkStateSnapshot instead of exposing the bare fields directly. Bug: 183972826 Test: FrameworksNetTests Change-Id: Id1707753b42ae88d2b95e4bd00a792609434e4f5 --- core/java/android/net/NetworkIdentity.java | 12 +-- .../android/net/NetworkStateSnapshot.java | 92 ++++++++++++------- .../server/net/NetworkStatsService.java | 21 ++--- 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1eef7d9a53..3bde6fa691 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -186,19 +186,19 @@ public class NetworkIdentity implements Comparable { */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { - final int legacyType = snapshot.legacyType; + final int legacyType = snapshot.getLegacyType(); - final String subscriberId = snapshot.subscriberId; + final String subscriberId = snapshot.getSubscriberId(); String networkId = null; - boolean roaming = !snapshot.networkCapabilities.hasCapability( + boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.networkCapabilities.hasCapability( + boolean metered = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - final int oemManaged = getOemBitfield(snapshot.networkCapabilities); + final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); if (legacyType == TYPE_WIFI) { - networkId = snapshot.networkCapabilities.getSsid(); + networkId = snapshot.getNetworkCapabilities().getSsid(); if (networkId == null) { final WifiManager wifi = context.getSystemService(WifiManager.class); final WifiInfo info = wifi.getConnectionInfo(); diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 0d26c2de86..9df861a6ff 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -37,47 +37,76 @@ import java.util.Objects; public final class NetworkStateSnapshot implements Parcelable { /** The network associated with this snapshot. */ @NonNull - public final Network network; + private final Network mNetwork; /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ @NonNull - public final NetworkCapabilities networkCapabilities; + private final NetworkCapabilities mNetworkCapabilities; /** The {@link LinkProperties} of the network associated with this snapshot. */ @NonNull - public final LinkProperties linkProperties; + private final LinkProperties mLinkProperties; /** * The Subscriber Id of the network associated with this snapshot. See * {@link android.telephony.TelephonyManager#getSubscriberId()}. */ @Nullable - public final String subscriberId; + private final String mSubscriberId; /** * The legacy type of the network associated with this snapshot. See * {@code ConnectivityManager#TYPE_*}. */ - public final int legacyType; + private final int mLegacyType; public NetworkStateSnapshot(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, @Nullable String subscriberId, int legacyType) { - this.network = Objects.requireNonNull(network); - this.networkCapabilities = Objects.requireNonNull(networkCapabilities); - this.linkProperties = Objects.requireNonNull(linkProperties); - this.subscriberId = subscriberId; - this.legacyType = legacyType; + mNetwork = Objects.requireNonNull(network); + mNetworkCapabilities = Objects.requireNonNull(networkCapabilities); + mLinkProperties = Objects.requireNonNull(linkProperties); + mSubscriberId = subscriberId; + mLegacyType = legacyType; } /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - network = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); - linkProperties = in.readParcelable(null); - subscriberId = in.readString(); - legacyType = in.readInt(); + mNetwork = in.readParcelable(null); + mNetworkCapabilities = in.readParcelable(null); + mLinkProperties = in.readParcelable(null); + mSubscriberId = in.readString(); + mLegacyType = in.readInt(); + } + + /** Get the network associated with this snapshot */ + @NonNull + public Network getNetwork() { + return mNetwork; + } + + /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + /** Get the {@link LinkProperties} of the network associated with this snapshot. */ + @NonNull + public LinkProperties getLinkProperties() { + return mLinkProperties; + } + + /** Get the Subscriber Id of the network associated with this snapshot. */ + @Nullable + public String getSubscriberId() { + return mSubscriberId; + } + + /** Get the legacy type of the network associated with this snapshot. */ + public int getLegacyType() { + return mLegacyType; } @Override @@ -87,11 +116,11 @@ public final class NetworkStateSnapshot implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(network, flags); - out.writeParcelable(networkCapabilities, flags); - out.writeParcelable(linkProperties, flags); - out.writeString(subscriberId); - out.writeInt(legacyType); + out.writeParcelable(mNetwork, flags); + out.writeParcelable(mNetworkCapabilities, flags); + out.writeParcelable(mLinkProperties, flags); + out.writeString(mSubscriberId); + out.writeInt(mLegacyType); } @NonNull @@ -115,26 +144,27 @@ public final class NetworkStateSnapshot implements Parcelable { if (this == o) return true; if (!(o instanceof NetworkStateSnapshot)) return false; NetworkStateSnapshot that = (NetworkStateSnapshot) o; - return legacyType == that.legacyType - && Objects.equals(network, that.network) - && Objects.equals(networkCapabilities, that.networkCapabilities) - && Objects.equals(linkProperties, that.linkProperties) - && Objects.equals(subscriberId, that.subscriberId); + return mLegacyType == that.mLegacyType + && Objects.equals(mNetwork, that.mNetwork) + && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities) + && Objects.equals(mLinkProperties, that.mLinkProperties) + && Objects.equals(mSubscriberId, that.mSubscriberId); } @Override public int hashCode() { - return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); + return Objects.hash(mNetwork, + mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType); } @Override public String toString() { return "NetworkStateSnapshot{" - + "network=" + network - + ", networkCapabilities=" + networkCapabilities - + ", linkProperties=" + linkProperties - + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\'' - + ", legacyType=" + legacyType + + "network=" + mNetwork + + ", networkCapabilities=" + mNetworkCapabilities + + ", linkProperties=" + mLinkProperties + + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\'' + + ", legacyType=" + mLegacyType + '}'; } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 19f5e3cd5d..3c14440c64 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,6 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -97,12 +96,12 @@ import android.net.INetworkStatsSession; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; +import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; -import android.net.NetworkSpecifier; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; @@ -1296,9 +1295,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { final int displayTransport = - getDisplayTransport(snapshot.networkCapabilities.getTransportTypes()); + getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork()); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, @@ -1306,7 +1305,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Traffic occurring on the base interface is always counted for // both total usage and UID details. - final String baseIface = snapshot.linkProperties.getInterfaceName(); + final String baseIface = snapshot.getLinkProperties().getInterfaceName(); if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); @@ -1316,7 +1315,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // If IMS is metered, then the IMS network usage has already included VT usage. // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. - if (snapshot.networkCapabilities.hasCapability( + if (snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { // Copy the identify from IMS one but mark it as metered. @@ -1364,7 +1363,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // accounting is explicitly bypassed for traffic from the clat uid. // // TODO: This code might be combined to above code. - for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { // baseIface has been handled, so ignore it. if (TextUtils.equals(baseIface, iface)) continue; if (iface != null) { @@ -1383,11 +1382,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); } - final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); + final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); if (spec instanceof TelephonyNetworkSpecifier) { return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } else { @@ -1402,11 +1401,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * transport types do not actually fill this value. */ private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } - return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From 9ea496b0ae81ec03e68674b4650e018fee941102 Mon Sep 17 00:00:00 2001 From: Nazanin Date: Thu, 15 Apr 2021 14:18:15 -0700 Subject: [PATCH 0917/1150] Security fix: enforce read privilege permission to check package privileges in TelephonyManager Bug: 180938364 Test: cts Change-Id: I08c346c46b9e87dceaa1faf35fa36b954d88f9b0 --- .../com/android/server/net/NetworkStatsAccess.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/services/core/java/com/android/server/net/NetworkStatsAccess.java index 7cdc4cc747..d25eae409d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsAccess.java +++ b/services/core/java/com/android/server/net/NetworkStatsAccess.java @@ -27,6 +27,7 @@ import android.app.AppOpsManager; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.pm.PackageManager; +import android.os.Binder; import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; @@ -108,9 +109,16 @@ public final class NetworkStatsAccess { DevicePolicyManagerInternal.class); final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); - boolean hasCarrierPrivileges = tm != null && - tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) == - TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + boolean hasCarrierPrivileges; + final long token = Binder.clearCallingIdentity(); + try { + hasCarrierPrivileges = tm != null + && tm.checkCarrierPrivilegesForPackageAnyPhone(callingPackage) + == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS; + } finally { + Binder.restoreCallingIdentity(token); + } + final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); final int appId = UserHandle.getAppId(callingUid); if (hasCarrierPrivileges || isDeviceOwner From 57d1c1bf53eb0bc8995252a0f90c474fcb3b9922 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 10:33:16 +0800 Subject: [PATCH 0918/1150] [SP28] Add API for set data warning To have better control and race-free of set data warning to tether offload hardware, an interface of set warning and limit at the same time in the NetworkStatsProvider is needed. This is a no-op change which expose such interface with minimum changes in service side to get build pass. The implementation would be included in follow-up patches. Test: atest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest Test: atest GtsNetworkStackHostTestCases Test: m doc-comment-check-docs Bug: 149467454 Bug: 170699770 Bug: 170179169 Merged-In: I6ee661497f7dedb871c85786d1950cab951d8aa2 Change-Id: I6ee661497f7dedb871c85786d1950cab951d8aa2 (cherry-picked from ag/13959436) --- .../provider/INetworkStatsProvider.aidl | 2 +- .../INetworkStatsProviderCallback.aidl | 2 +- .../provider/NetworkStatsProvider.java | 58 ++++++++++++++++--- .../server/net/NetworkStatsService.java | 10 ++-- 4 files changed, 59 insertions(+), 13 deletions(-) diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl index 4078b24921..74c3ba44b6 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl @@ -23,6 +23,6 @@ package android.net.netstats.provider; */ oneway interface INetworkStatsProvider { void onRequestStatsUpdate(int token); - void onSetLimit(String iface, long quotaBytes); void onSetAlert(long quotaBytes); + void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes); } diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index bd336dd348..7eaa01e262 100644 --- a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,6 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyLimitReached(); + void notifyWarningOrLimitReached(); void unregister(); } diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 7639d2244c..65b336ad6f 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -29,7 +29,8 @@ import android.os.RemoteException; @SystemApi public abstract class NetworkStatsProvider { /** - * A value used by {@link #onSetLimit} and {@link #onSetAlert} indicates there is no limit. + * A value used by {@link #onSetLimit}, {@link #onSetAlert} and {@link #onSetWarningAndLimit} + * indicates there is no limit. */ public static final int QUOTA_UNLIMITED = -1; @@ -42,13 +43,13 @@ public abstract class NetworkStatsProvider { } @Override - public void onSetLimit(String iface, long quotaBytes) { - NetworkStatsProvider.this.onSetLimit(iface, quotaBytes); + public void onSetAlert(long quotaBytes) { + NetworkStatsProvider.this.onSetAlert(quotaBytes); } @Override - public void onSetAlert(long quotaBytes) { - NetworkStatsProvider.this.onSetAlert(quotaBytes); + public void onSetWarningAndLimit(String iface, long warningBytes, long limitBytes) { + NetworkStatsProvider.this.onSetWarningAndLimit(iface, warningBytes, limitBytes); } }; @@ -145,11 +146,28 @@ public abstract class NetworkStatsProvider { } /** - * Notify system that the quota set by {@code onSetLimit} has been reached. + * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. + * + * @hide + */ + // TODO: Expose as system API. + public void notifyWarningReached() { + try { + // Reuse the code path to notify warning reached with limit reached + // since framework handles them in the same way. + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Notify system that the quota set by {@link #onSetLimit} or limit set by + * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } @@ -180,8 +198,34 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ + // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); + /** + * Called by {@code NetworkStatsService} when setting the interface quotas for the specified + * upstream interface. If a provider implements {@link #onSetWarningAndLimit}, the system + * will not call {@link #onSetLimit}. When this method is called, the implementation + * should behave as follows: + * 1. If {@code warningBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider@notifyWarningReached()}. + * 2. If {@code limitBytes} is reached on {@code iface}, block all further traffic on + * {@code iface} and call {@link NetworkStatsProvider#notifyLimitReached()}. + * + * @param iface the interface requiring the operation. + * @param warningBytes the warning defined as the number of bytes, starting from zero and + * counting from now. A value of {@link #QUOTA_UNLIMITED} indicates + * there is no warning. + * @param limitBytes the limit defined as the number of bytes, starting from zero and counting + * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. + * + * @hide + */ + // TODO: Expose as system API. + public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { + // Backward compatibility for those who didn't override this function. + onSetLimit(iface, limitBytes); + } + /** * Called by {@code NetworkStatsService} when setting the alert bytes. Custom implementations * MUST call {@link NetworkStatsProvider#notifyAlertReached()} when {@code quotaBytes} bytes diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index ba9f486092..191ff096c8 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1660,7 +1660,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetLimit(iface, quota)); + // TODO: Set warning accordingly. + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, + NetworkStatsProvider.QUOTA_UNLIMITED, quota)); } } @@ -2051,10 +2053,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyLimitReached() { - Log.d(TAG, mTag + ": onLimitReached"); + public void notifyWarningOrLimitReached() { + Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderLimitReached(mTag); + .onStatsProviderWarningOrLimitReached(mTag); } @Override From 7d627db6612792d5c2cc0e56e3d00293ba357ad2 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 24 Mar 2021 14:17:19 +0800 Subject: [PATCH 0919/1150] [SP29] Send interface warning bytes to NetworkStatsProvider This change contains necessary modification in NPMS and NSS to send warning bytes to NetworkStatsProvider. But since no any provider has been upgraded to handle such parameter. Thus, no behavior change is made in this patch. Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Test: atest NetworkPolicyManagerServiceTest#testStatsProviderWarningAndLimitReached Bug: 149467454 Bug: 170699770 Bug: 170179169 Merged-In: I6c4863030c36328db571294fd12a40e59864def5 Change-Id: I6c4863030c36328db571294fd12a40e59864def5 (cherry-picked from ag/13982166) --- .../com/android/server/net/NetworkStatsService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 191ff096c8..0bc20540a7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1658,11 +1658,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void setStatsProviderLimitAsync(@NonNull String iface, long quota) { - if (LOGV) Slog.v(TAG, "setStatsProviderLimitAsync(" + iface + "," + quota + ")"); - // TODO: Set warning accordingly. + public void setStatsProviderWarningAndLimitAsync( + @NonNull String iface, long warning, long limit) { + if (LOGV) { + Slog.v(TAG, "setStatsProviderWarningAndLimitAsync(" + + iface + "," + warning + "," + limit + ")"); + } invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - NetworkStatsProvider.QUOTA_UNLIMITED, quota)); + warning, limit)); } } From 32631f5a6ca72a900f6eef5b026b83ae3a40683c Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 10 Mar 2021 19:45:05 +0800 Subject: [PATCH 0920/1150] [SP31] Expose onSetWarningAndLimit System API Test: atest NetworkPolicyManagerServiceTest NetworkStatsServiceTest Bug: 149467454 CTS-Coverage-Bug: 183598414 Merged-In: I6f5e22e3a7b80a38cae9f3c5d7296a1dff34facf Change-Id: I6f5e22e3a7b80a38cae9f3c5d7296a1dff34facf (cherry-picked from ag/13981689 with fixed merged conflict) --- .../net/netstats/provider/NetworkStatsProvider.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/core/java/android/net/netstats/provider/NetworkStatsProvider.java index 65b336ad6f..23fc06927e 100644 --- a/core/java/android/net/netstats/provider/NetworkStatsProvider.java +++ b/core/java/android/net/netstats/provider/NetworkStatsProvider.java @@ -147,10 +147,7 @@ public abstract class NetworkStatsProvider { /** * Notify system that the warning set by {@link #onSetWarningAndLimit} has been reached. - * - * @hide */ - // TODO: Expose as system API. public void notifyWarningReached() { try { // Reuse the code path to notify warning reached with limit reached @@ -198,7 +195,6 @@ public abstract class NetworkStatsProvider { * @param quotaBytes the quota defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. */ - // TODO: deprecate this once onSetWarningAndLimit is ready. public abstract void onSetLimit(@NonNull String iface, long quotaBytes); /** @@ -217,10 +213,7 @@ public abstract class NetworkStatsProvider { * there is no warning. * @param limitBytes the limit defined as the number of bytes, starting from zero and counting * from now. A value of {@link #QUOTA_UNLIMITED} indicates there is no limit. - * - * @hide */ - // TODO: Expose as system API. public void onSetWarningAndLimit(@NonNull String iface, long warningBytes, long limitBytes) { // Backward compatibility for those who didn't override this function. onSetLimit(iface, limitBytes); From 484e857368608f5d0d01787cb793b46b15934c88 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 20 Apr 2021 17:19:46 +0800 Subject: [PATCH 0921/1150] Add getters to NetworkStateSnapshot Address API council feedback, add getters to NetworkStateSnapshot instead of exposing the bare fields directly. (cherry picked from ag/14233655) Bug: 183972826 Test: FrameworksNetTests Merged-In: Id1707753b42ae88d2b95e4bd00a792609434e4f5 Change-Id: Id1707753b42ae88d2b95e4bd00a792609434e4f5 --- core/java/android/net/NetworkIdentity.java | 12 +-- .../android/net/NetworkStateSnapshot.java | 92 ++++++++++++------- .../server/net/NetworkStatsService.java | 21 ++--- 3 files changed, 77 insertions(+), 48 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1eef7d9a53..3bde6fa691 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -186,19 +186,19 @@ public class NetworkIdentity implements Comparable { */ public static NetworkIdentity buildNetworkIdentity(Context context, NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { - final int legacyType = snapshot.legacyType; + final int legacyType = snapshot.getLegacyType(); - final String subscriberId = snapshot.subscriberId; + final String subscriberId = snapshot.getSubscriberId(); String networkId = null; - boolean roaming = !snapshot.networkCapabilities.hasCapability( + boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.networkCapabilities.hasCapability( + boolean metered = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_METERED); - final int oemManaged = getOemBitfield(snapshot.networkCapabilities); + final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); if (legacyType == TYPE_WIFI) { - networkId = snapshot.networkCapabilities.getSsid(); + networkId = snapshot.getNetworkCapabilities().getSsid(); if (networkId == null) { final WifiManager wifi = context.getSystemService(WifiManager.class); final WifiInfo info = wifi.getConnectionInfo(); diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 0d26c2de86..9df861a6ff 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -37,47 +37,76 @@ import java.util.Objects; public final class NetworkStateSnapshot implements Parcelable { /** The network associated with this snapshot. */ @NonNull - public final Network network; + private final Network mNetwork; /** The {@link NetworkCapabilities} of the network associated with this snapshot. */ @NonNull - public final NetworkCapabilities networkCapabilities; + private final NetworkCapabilities mNetworkCapabilities; /** The {@link LinkProperties} of the network associated with this snapshot. */ @NonNull - public final LinkProperties linkProperties; + private final LinkProperties mLinkProperties; /** * The Subscriber Id of the network associated with this snapshot. See * {@link android.telephony.TelephonyManager#getSubscriberId()}. */ @Nullable - public final String subscriberId; + private final String mSubscriberId; /** * The legacy type of the network associated with this snapshot. See * {@code ConnectivityManager#TYPE_*}. */ - public final int legacyType; + private final int mLegacyType; public NetworkStateSnapshot(@NonNull Network network, @NonNull NetworkCapabilities networkCapabilities, @NonNull LinkProperties linkProperties, @Nullable String subscriberId, int legacyType) { - this.network = Objects.requireNonNull(network); - this.networkCapabilities = Objects.requireNonNull(networkCapabilities); - this.linkProperties = Objects.requireNonNull(linkProperties); - this.subscriberId = subscriberId; - this.legacyType = legacyType; + mNetwork = Objects.requireNonNull(network); + mNetworkCapabilities = Objects.requireNonNull(networkCapabilities); + mLinkProperties = Objects.requireNonNull(linkProperties); + mSubscriberId = subscriberId; + mLegacyType = legacyType; } /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - network = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); - linkProperties = in.readParcelable(null); - subscriberId = in.readString(); - legacyType = in.readInt(); + mNetwork = in.readParcelable(null); + mNetworkCapabilities = in.readParcelable(null); + mLinkProperties = in.readParcelable(null); + mSubscriberId = in.readString(); + mLegacyType = in.readInt(); + } + + /** Get the network associated with this snapshot */ + @NonNull + public Network getNetwork() { + return mNetwork; + } + + /** Get {@link NetworkCapabilities} of the network associated with this snapshot. */ + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities; + } + + /** Get the {@link LinkProperties} of the network associated with this snapshot. */ + @NonNull + public LinkProperties getLinkProperties() { + return mLinkProperties; + } + + /** Get the Subscriber Id of the network associated with this snapshot. */ + @Nullable + public String getSubscriberId() { + return mSubscriberId; + } + + /** Get the legacy type of the network associated with this snapshot. */ + public int getLegacyType() { + return mLegacyType; } @Override @@ -87,11 +116,11 @@ public final class NetworkStateSnapshot implements Parcelable { @Override public void writeToParcel(@NonNull Parcel out, int flags) { - out.writeParcelable(network, flags); - out.writeParcelable(networkCapabilities, flags); - out.writeParcelable(linkProperties, flags); - out.writeString(subscriberId); - out.writeInt(legacyType); + out.writeParcelable(mNetwork, flags); + out.writeParcelable(mNetworkCapabilities, flags); + out.writeParcelable(mLinkProperties, flags); + out.writeString(mSubscriberId); + out.writeInt(mLegacyType); } @NonNull @@ -115,26 +144,27 @@ public final class NetworkStateSnapshot implements Parcelable { if (this == o) return true; if (!(o instanceof NetworkStateSnapshot)) return false; NetworkStateSnapshot that = (NetworkStateSnapshot) o; - return legacyType == that.legacyType - && Objects.equals(network, that.network) - && Objects.equals(networkCapabilities, that.networkCapabilities) - && Objects.equals(linkProperties, that.linkProperties) - && Objects.equals(subscriberId, that.subscriberId); + return mLegacyType == that.mLegacyType + && Objects.equals(mNetwork, that.mNetwork) + && Objects.equals(mNetworkCapabilities, that.mNetworkCapabilities) + && Objects.equals(mLinkProperties, that.mLinkProperties) + && Objects.equals(mSubscriberId, that.mSubscriberId); } @Override public int hashCode() { - return Objects.hash(network, networkCapabilities, linkProperties, subscriberId, legacyType); + return Objects.hash(mNetwork, + mNetworkCapabilities, mLinkProperties, mSubscriberId, mLegacyType); } @Override public String toString() { return "NetworkStateSnapshot{" - + "network=" + network - + ", networkCapabilities=" + networkCapabilities - + ", linkProperties=" + linkProperties - + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(subscriberId) + '\'' - + ", legacyType=" + legacyType + + "network=" + mNetwork + + ", networkCapabilities=" + mNetworkCapabilities + + ", linkProperties=" + mLinkProperties + + ", subscriberId='" + NetworkIdentityUtils.scrubSubscriberId(mSubscriberId) + '\'' + + ", legacyType=" + mLegacyType + '}'; } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 19f5e3cd5d..3c14440c64 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -24,7 +24,6 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; @@ -97,12 +96,12 @@ import android.net.INetworkStatsSession; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; +import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; import android.net.NetworkStatsHistory; -import android.net.NetworkSpecifier; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; import android.net.TrafficStats; @@ -1296,9 +1295,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final ArraySet mobileIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { final int displayTransport = - getDisplayTransport(snapshot.networkCapabilities.getTransportTypes()); + getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.network); + final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork()); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, @@ -1306,7 +1305,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Traffic occurring on the base interface is always counted for // both total usage and UID details. - final String baseIface = snapshot.linkProperties.getInterfaceName(); + final String baseIface = snapshot.getLinkProperties().getInterfaceName(); if (baseIface != null) { findOrCreateNetworkIdentitySet(mActiveIfaces, baseIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, baseIface).add(ident); @@ -1316,7 +1315,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // If IMS is metered, then the IMS network usage has already included VT usage. // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. - if (snapshot.networkCapabilities.hasCapability( + if (snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { // Copy the identify from IMS one but mark it as metered. @@ -1364,7 +1363,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // accounting is explicitly bypassed for traffic from the clat uid. // // TODO: This code might be combined to above code. - for (String iface : snapshot.linkProperties.getAllInterfaceNames()) { + for (String iface : snapshot.getLinkProperties().getAllInterfaceNames()) { // baseIface has been handled, so ignore it. if (TextUtils.equals(baseIface, iface)) continue; if (iface != null) { @@ -1383,11 +1382,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { throw new IllegalArgumentException("Mobile state need capability TRANSPORT_CELLULAR"); } - final NetworkSpecifier spec = state.networkCapabilities.getNetworkSpecifier(); + final NetworkSpecifier spec = state.getNetworkCapabilities().getNetworkSpecifier(); if (spec instanceof TelephonyNetworkSpecifier) { return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } else { @@ -1402,11 +1401,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * transport types do not actually fill this value. */ private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { - if (!state.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { + if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } - return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.subscriberId); + return mNetworkStatsSubscriptionsMonitor.getRatTypeForSubscriberId(state.getSubscriberId()); } private static NetworkIdentitySet findOrCreateNetworkIdentitySet( From 2b24a738ee12d1e4e0ead9ed6def97c143966004 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 16 Apr 2021 23:20:23 +0800 Subject: [PATCH 0922/1150] Add getters to UnderlyingNetworkInfo Address API review feedback, add getters to UnderlyingNetworkInfo instead of exposing fields. Instead of wasting memory by converting this into an array, have migrateTun take a List. In turn, tunAdjustmentInit should also take a List. (cherry picked from ag/14211075) Bug: 183972554 Test: atest android.net.UnderlyingNetworkInfoTest Merged-In: Id59744097208d91298a25ef110ade91a9cf291a1 Change-Id: Id59744097208d91298a25ef110ade91a9cf291a1 --- core/java/android/net/NetworkStats.java | 31 +++++----- .../android/net/UnderlyingNetworkInfo.java | 60 ++++++++++++------- .../server/net/NetworkStatsFactory.java | 4 +- 3 files changed, 58 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index d42beae601..6ccbab7ed8 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -38,6 +38,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Predicate; @@ -1423,11 +1424,11 @@ public final class NetworkStats implements Parcelable { * @hide */ public void migrateTun(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces) { + @NonNull List underlyingIfaces) { // Combined usage by all apps using VPN. final Entry tunIfaceTotal = new Entry(); // Usage by VPN, grouped by its {@code underlyingIfaces}. - final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.length]; + final Entry[] perInterfaceTotal = new Entry[underlyingIfaces.size()]; // Usage by VPN, summed across all its {@code underlyingIfaces}. final Entry underlyingIfacesTotal = new Entry(); @@ -1468,7 +1469,7 @@ public final class NetworkStats implements Parcelable { * {@code underlyingIfaces} */ private void tunAdjustmentInit(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { final Entry recycle = new Entry(); for (int i = 0; i < size; i++) { @@ -1488,8 +1489,8 @@ public final class NetworkStats implements Parcelable { if (recycle.uid == tunUid) { // Add up traffic through tunUid's underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - if (Objects.equals(underlyingIfaces[j], recycle.iface)) { + for (int j = 0; j < underlyingIfaces.size(); j++) { + if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { perInterfaceTotal[j].add(recycle); underlyingIfacesTotal.add(recycle); break; @@ -1515,12 +1516,12 @@ public final class NetworkStats implements Parcelable { * underlyingIfaces} */ private Entry[] addTrafficToApplications(int tunUid, @NonNull String tunIface, - @NonNull String[] underlyingIfaces, @NonNull Entry tunIfaceTotal, + @NonNull List underlyingIfaces, @NonNull Entry tunIfaceTotal, @NonNull Entry[] perInterfaceTotal, @NonNull Entry underlyingIfacesTotal) { // Traffic that should be moved off of each underlying interface for tunUid (see // deductTrafficFromVpnApp below). - final Entry[] moved = new Entry[underlyingIfaces.length]; - for (int i = 0; i < underlyingIfaces.length; i++) { + final Entry[] moved = new Entry[underlyingIfaces.size()]; + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i] = new Entry(); } @@ -1582,8 +1583,8 @@ public final class NetworkStats implements Parcelable { } // In a second pass, distribute these values across interfaces in the proportion that // each interface represents of the total traffic of the underlying interfaces. - for (int j = 0; j < underlyingIfaces.length; j++) { - tmpEntry.iface = underlyingIfaces[j]; + for (int j = 0; j < underlyingIfaces.size(); j++) { + tmpEntry.iface = underlyingIfaces.get(j); tmpEntry.rxBytes = 0; // Reset 'set' to correct value since it gets updated when adding debug info below. tmpEntry.set = set[i]; @@ -1638,14 +1639,14 @@ public final class NetworkStats implements Parcelable { private void deductTrafficFromVpnApp( int tunUid, - @NonNull String[] underlyingIfaces, + @NonNull List underlyingIfaces, @NonNull Entry[] moved) { - for (int i = 0; i < underlyingIfaces.length; i++) { + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i].uid = tunUid; // Add debug info moved[i].set = SET_DBG_VPN_OUT; moved[i].tag = TAG_NONE; - moved[i].iface = underlyingIfaces[i]; + moved[i].iface = underlyingIfaces.get(i); moved[i].metered = METERED_ALL; moved[i].roaming = ROAMING_ALL; moved[i].defaultNetwork = DEFAULT_NETWORK_ALL; @@ -1658,7 +1659,7 @@ public final class NetworkStats implements Parcelable { // METERED_NO, which should be the case as it comes directly from the /proc file. // We only blend in the roaming data after applying these adjustments, by checking the // NetworkIdentity of the underlying iface. - final int idxVpnBackground = findIndex(underlyingIfaces[i], tunUid, SET_DEFAULT, + final int idxVpnBackground = findIndex(underlyingIfaces.get(i), tunUid, SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnBackground != -1) { // Note - tunSubtract also updates moved[i]; whatever traffic that's left is removed @@ -1666,7 +1667,7 @@ public final class NetworkStats implements Parcelable { tunSubtract(idxVpnBackground, this, moved[i]); } - final int idxVpnForeground = findIndex(underlyingIfaces[i], tunUid, SET_FOREGROUND, + final int idxVpnForeground = findIndex(underlyingIfaces.get(i), tunUid, SET_FOREGROUND, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO); if (idxVpnForeground != -1) { tunSubtract(idxVpnForeground, this, moved[i]); diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 7bf9231239..459fdacef8 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -37,36 +37,56 @@ import java.util.Objects; @SystemApi(client = MODULE_LIBRARIES) public final class UnderlyingNetworkInfo implements Parcelable { /** The owner of this network. */ - public final int ownerUid; + private final int mOwnerUid; + /** The interface name of this network. */ @NonNull - public final String iface; + private final String mIface; + /** The names of the interfaces underlying this network. */ @NonNull - public final List underlyingIfaces; + private final List mUnderlyingIfaces; public UnderlyingNetworkInfo(int ownerUid, @NonNull String iface, @NonNull List underlyingIfaces) { Objects.requireNonNull(iface); Objects.requireNonNull(underlyingIfaces); - this.ownerUid = ownerUid; - this.iface = iface; - this.underlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); + mOwnerUid = ownerUid; + mIface = iface; + mUnderlyingIfaces = Collections.unmodifiableList(new ArrayList<>(underlyingIfaces)); } private UnderlyingNetworkInfo(@NonNull Parcel in) { - this.ownerUid = in.readInt(); - this.iface = in.readString(); - this.underlyingIfaces = new ArrayList<>(); - in.readList(this.underlyingIfaces, null /*classLoader*/); + mOwnerUid = in.readInt(); + mIface = in.readString(); + List underlyingIfaces = new ArrayList<>(); + in.readList(underlyingIfaces, null /*classLoader*/); + mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); + } + + /** Get the owner of this network. */ + public int getOwnerUid() { + return mOwnerUid; + } + + /** Get the interface name of this network. */ + @NonNull + public String getIface() { + return mIface; + } + + /** Get the names of the interfaces underlying this network. */ + @NonNull + public List getUnderlyingIfaces() { + return mUnderlyingIfaces; } @Override public String toString() { return "UnderlyingNetworkInfo{" - + "ownerUid=" + ownerUid - + ", iface='" + iface + '\'' - + ", underlyingIfaces='" + underlyingIfaces.toString() + '\'' + + "ownerUid=" + mOwnerUid + + ", iface='" + mIface + '\'' + + ", underlyingIfaces='" + mUnderlyingIfaces.toString() + '\'' + '}'; } @@ -77,9 +97,9 @@ public final class UnderlyingNetworkInfo implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(ownerUid); - dest.writeString(iface); - dest.writeList(underlyingIfaces); + dest.writeInt(mOwnerUid); + dest.writeString(mIface); + dest.writeList(mUnderlyingIfaces); } @NonNull @@ -103,13 +123,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (this == o) return true; if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; - return ownerUid == that.ownerUid - && Objects.equals(iface, that.iface) - && Objects.equals(underlyingIfaces, that.underlyingIfaces); + return mOwnerUid == that.getOwnerUid() + && Objects.equals(mIface, that.getIface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingIfaces()); } @Override public int hashCode() { - return Objects.hash(ownerUid, iface, underlyingIfaces); + return Objects.hash(mOwnerUid, mIface, mUnderlyingIfaces); } } diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index d042b882fe..e7c0a50163 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.ownerUid, info.iface, - info.underlyingIfaces.toArray(new String[0])); + delta.migrateTun(info.getOwnerUid(), info.getIface(), + info.getUnderlyingIfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } From 4ddc7c782f09a5c41c8037407749dd411a35930f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 28 Apr 2021 17:21:21 +0800 Subject: [PATCH 0923/1150] Rename *Iface* APIs to *Interface* Address API review feedback, other APIs have been refering to these as "interface" instead of "iface" so migrate the APIs named *Iface* to *Interface*. Bug: 183972554 Test: atest android.net.UnderlyingNetworkInfoTest Change-Id: I38b476e762fb57fa88c4a789092d0af6f5330d80 --- core/java/android/net/UnderlyingNetworkInfo.java | 8 ++++---- .../java/com/android/server/net/NetworkStatsFactory.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 459fdacef8..33f9375c03 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -71,13 +71,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { /** Get the interface name of this network. */ @NonNull - public String getIface() { + public String getInterface() { return mIface; } /** Get the names of the interfaces underlying this network. */ @NonNull - public List getUnderlyingIfaces() { + public List getUnderlyingInterfaces() { return mUnderlyingIfaces; } @@ -124,8 +124,8 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; return mOwnerUid == that.getOwnerUid() - && Objects.equals(mIface, that.getIface()) - && Objects.equals(mUnderlyingIfaces, that.getUnderlyingIfaces()); + && Objects.equals(mIface, that.getInterface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); } @Override diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index e7c0a50163..431b00914f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.getOwnerUid(), info.getIface(), - info.getUnderlyingIfaces()); + delta.migrateTun(info.getOwnerUid(), info.getInterface(), + info.getUnderlyingInterfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } From 0492286d6fbe0c5281286c08315e5220b682aa41 Mon Sep 17 00:00:00 2001 From: Chris Weir Date: Fri, 12 Mar 2021 12:51:00 -0800 Subject: [PATCH 0924/1150] Print human-readable OEM managed states For NetworkTemplate and NetworkIdentity, print human-readable representations of the OEM managed state in the classes' respective toString() functions. Bug: 180557699 Test: Manual - run atest NetworkTemplateTest NetworkIdentityTest and verify that the logcat output shows the String representation of the OEM managed state correctly. Change-Id: Ia180b911f91f41937ac713e6b3691d82f682e146 --- core/java/android/net/NetworkIdentity.java | 32 ++++++++++++++++++++-- core/java/android/net/NetworkTemplate.java | 15 +++++++++- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index b037261f0b..13408bf2cd 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -26,8 +26,10 @@ import android.service.NetworkIdentityProto; import android.telephony.Annotation.NetworkType; import android.util.proto.ProtoOutputStream; +import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.NetworkIdentityUtils; +import java.util.ArrayList; import java.util.Objects; /** @@ -121,11 +123,37 @@ public class NetworkIdentity implements Comparable { } builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); - // TODO(180557699): Print a human readable string for OEM managed state. - builder.append(", oemManaged=").append(mOemManaged); + builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); return builder.append("}").toString(); } + /** + * Get the human readable representation of a bitfield representing the OEM managed state of a + * network. + */ + static String getOemManagedNames(int oemManaged) { + if (oemManaged == OEM_NONE) { + return "OEM_NONE"; + } + final int[] bitPositions = NetworkCapabilitiesUtils.unpackBits(oemManaged); + final ArrayList oemManagedNames = new ArrayList(); + for (int position : bitPositions) { + oemManagedNames.add(nameOfOemManaged(1 << position)); + } + return String.join(",", oemManagedNames); + } + + private static String nameOfOemManaged(int oemManagedBit) { + switch (oemManagedBit) { + case OEM_PAID: + return "OEM_PAID"; + case OEM_PRIVATE: + return "OEM_PRIVATE"; + default: + return "Invalid(" + oemManagedBit + ")"; + } + } + public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index c83dd99c2a..755e8fda4f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -344,7 +344,7 @@ public class NetworkTemplate implements Parcelable { builder.append(", subType=").append(mSubType); } if (mOemManaged != OEM_MANAGED_ALL) { - builder.append(", oemManaged=").append(mOemManaged); + builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); } return builder.toString(); } @@ -640,6 +640,19 @@ public class NetworkTemplate implements Parcelable { } } + private static String getOemManagedNames(int oemManaged) { + switch (oemManaged) { + case OEM_MANAGED_ALL: + return "OEM_MANAGED_ALL"; + case OEM_MANAGED_NO: + return "OEM_MANAGED_NO"; + case OEM_MANAGED_YES: + return "OEM_MANAGED_YES"; + default: + return NetworkIdentity.getOemManagedNames(oemManaged); + } + } + /** * Examine the given template and normalize if it refers to a "merged" * mobile subscriber. We pick the "lowest" merged subscriber as the primary From 1684f790d94cef14603dfa6f71ee87872eb51498 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 15 Apr 2021 11:59:16 -0700 Subject: [PATCH 0925/1150] Add internal support for IPsec forward policies This change adds support for IPsec forward policies, which are necessary for packets to be allowed to be forwarded to another interface, as is the case with tethering. This is necessary and useful only within the system server, and as such is not exposed as a public API. This change is safe, since the addition of a FWD policy on IPsec tunnel interfaces will by default block forwarded traffic (as would be the case without this patch). In the event that the (system) owner of the tunnel requires support for forwarded packets (eg tethering), this patch allows application of transforms in the FWD direction as well. This will be used to ensure that the VCN can be used as the underlying network for the purposes of tethering. Bug: 185495453 Test: atest IpSecServiceTest Test: atest IpSecServiceParameterizedTest Test: manual testing with tethering over VCN Change-Id: I74ecea71f1954029f6fbdbe34598c82e0aac386b --- core/java/android/net/IpSecManager.java | 10 ++++++++ .../java/com/android/server/IpSecService.java | 23 +++++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 98acd98cc4..01d1aa533a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -78,6 +78,16 @@ public final class IpSecManager { */ public static final int DIRECTION_OUT = 1; + /** + * Used when applying a transform to direct traffic through an {@link IpSecTransform} for + * forwarding between interfaces. + * + *

            See {@link #applyTransportModeTransform(Socket, int, IpSecTransform)}. + * + * @hide + */ + public static final int DIRECTION_FWD = 2; + /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index 794cb9301d..d574e74d39 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -49,6 +49,7 @@ import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.system.ErrnoException; @@ -65,6 +66,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.net.module.util.NetdUtils; +import com.android.net.module.util.PermissionUtils; import libcore.io.IoUtils; @@ -466,8 +468,7 @@ public class IpSecService extends IIpSecService.Stub { /** Safety method; guards against access of other user's UserRecords */ private void checkCallerUid(int uid) { - if (uid != Binder.getCallingUid() - && android.os.Process.SYSTEM_UID != Binder.getCallingUid()) { + if (uid != Binder.getCallingUid() && Process.SYSTEM_UID != Binder.getCallingUid()) { throw new SecurityException("Attempted access of unowned resources"); } } @@ -1105,11 +1106,15 @@ public class IpSecService extends IIpSecService.Stub { * Checks the user-provided direction field and throws an IllegalArgumentException if it is not * DIRECTION_IN or DIRECTION_OUT */ - private static void checkDirection(int direction) { + private void checkDirection(int direction) { switch (direction) { case IpSecManager.DIRECTION_OUT: case IpSecManager.DIRECTION_IN: return; + case IpSecManager.DIRECTION_FWD: + // Only NETWORK_STACK or PERMISSION_NETWORK_STACK allowed to use forward policies + PermissionUtils.enforceNetworkStackPermission(mContext); + return; } throw new IllegalArgumentException("Invalid Direction: " + direction); } @@ -1353,6 +1358,16 @@ public class IpSecService extends IIpSecService.Stub { ikey, 0xffffffff, resourceId); + netd.ipSecAddSecurityPolicy( + callerUid, + selAddrFamily, + IpSecManager.DIRECTION_FWD, + remoteAddr, + localAddr, + 0, + ikey, + 0xffffffff, + resourceId); } userRecord.mTunnelInterfaceRecords.put( @@ -1820,7 +1835,7 @@ public class IpSecService extends IIpSecService.Stub { int mark = (direction == IpSecManager.DIRECTION_OUT) ? tunnelInterfaceInfo.getOkey() - : tunnelInterfaceInfo.getIkey(); + : tunnelInterfaceInfo.getIkey(); // Ikey also used for FWD policies try { // Default to using the invalid SPI of 0 for inbound SAs. This allows policies to skip From 3f1b6f2aaaa9a18b8ebe3b320e1f94b90a0c51ac Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 10 May 2021 23:09:44 +0800 Subject: [PATCH 0926/1150] Add return type javadoc to NetworkStateSnapshot#getLegacyType Add javadoc to document the return type is the legacy network type in getLegacyType. Bug: 183972826 Test: only update javadoc Change-Id: I7757253af5955f7d489d6349c090dcba146cfd7f --- core/java/android/net/NetworkStateSnapshot.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkStateSnapshot.java b/core/java/android/net/NetworkStateSnapshot.java index 9df861a6ff..3915634392 100644 --- a/core/java/android/net/NetworkStateSnapshot.java +++ b/core/java/android/net/NetworkStateSnapshot.java @@ -104,7 +104,10 @@ public final class NetworkStateSnapshot implements Parcelable { return mSubscriberId; } - /** Get the legacy type of the network associated with this snapshot. */ + /** + * Get the legacy type of the network associated with this snapshot. + * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. + */ public int getLegacyType() { return mLegacyType; } From 0c8ff5c720941fef2b861771d278e01bf0e932b9 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Mon, 10 May 2021 18:26:02 -0700 Subject: [PATCH 0927/1150] Add clarifying comments on for IPsec forward policies This change adds clarifying comments for the usage of the forward policies in IPsec, and corrects a comment to properly specify the permissions allowed. Bug: 185495453 Test: Comment-only changes Change-Id: I6d36522c344c41b0ebd90d46b216d115b678dd31 --- .../core/java/com/android/server/IpSecService.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d574e74d39..d6ee95131e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -1112,7 +1112,7 @@ public class IpSecService extends IIpSecService.Stub { case IpSecManager.DIRECTION_IN: return; case IpSecManager.DIRECTION_FWD: - // Only NETWORK_STACK or PERMISSION_NETWORK_STACK allowed to use forward policies + // Only NETWORK_STACK or MAINLINE_NETWORK_STACK allowed to use forward policies PermissionUtils.enforceNetworkStackPermission(mContext); return; } @@ -1358,6 +1358,16 @@ public class IpSecService extends IIpSecService.Stub { ikey, 0xffffffff, resourceId); + + // Add a forwarding policy on the tunnel interface. In order to support forwarding + // the IpSecTunnelInterface must have a forwarding policy matching the incoming SA. + // + // Unless a IpSecTransform is also applied against this interface in DIRECTION_FWD, + // forwarding will be blocked by default (as would be the case if this policy was + // absent). + // + // This is necessary only on the tunnel interface, and not any the interface to + // which traffic will be forwarded to. netd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, From 249507940f5cd49b8601b7faa3f859686eb8fc85 Mon Sep 17 00:00:00 2001 From: lesl Date: Fri, 7 May 2021 18:15:17 +0800 Subject: [PATCH 0928/1150] Add metered filter for API: buildTemplateCarrier This CL modifies NetworkTemplate#buildTemplateCarrier to force on metered carrier network and rename to buildTemplateCarrierMetered. This method was introduced recently and has no callers. This method will be used in Settings and NetworkPolicyManagerService to display and manage data usage on carrier metered networks. Settings/NetworkPolicyManagerService will use it instead of the existing method buildTemplateMobileAll method, which only matches metered networks. That code will change from matching metered mobile networks to matching metered carrier networks. Note: The carrier metered network includes metered mobile network and metered "merged carrier wifi network" that is a specific cerrier wifi network which provides the same user experience as mobile. Bug: 176396812 Test: atest -c NetworkTemplateTest Change-Id: I7196d62bb60844458a6c4b1d94e2baccb71e15cd --- core/java/android/net/NetworkTemplate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d3c8957494..fd446cdf5c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -274,11 +274,14 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all carrier networks with the given IMSI. + * Template to match all metered carrier networks with the given IMSI. */ - public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { Objects.requireNonNull(subscriberId); - return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, + new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } private final int mMatchRule; From fb5fbaba3304b6e33c34dfeb12df10fdc37b8003 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 28 Apr 2021 17:21:21 +0800 Subject: [PATCH 0929/1150] Rename *Iface* APIs to *Interface* Address API review feedback, other APIs have been refering to these as "interface" instead of "iface" so migrate the APIs named *Iface* to *Interface*. (cherry-picked from ag/14326779) Bug: 183972554 Test: atest android.net.UnderlyingNetworkInfoTest Merged-In: I38b476e762fb57fa88c4a789092d0af6f5330d80 Change-Id: I38b476e762fb57fa88c4a789092d0af6f5330d80 --- core/java/android/net/UnderlyingNetworkInfo.java | 8 ++++---- .../java/com/android/server/net/NetworkStatsFactory.java | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/core/java/android/net/UnderlyingNetworkInfo.java index 459fdacef8..33f9375c03 100644 --- a/core/java/android/net/UnderlyingNetworkInfo.java +++ b/core/java/android/net/UnderlyingNetworkInfo.java @@ -71,13 +71,13 @@ public final class UnderlyingNetworkInfo implements Parcelable { /** Get the interface name of this network. */ @NonNull - public String getIface() { + public String getInterface() { return mIface; } /** Get the names of the interfaces underlying this network. */ @NonNull - public List getUnderlyingIfaces() { + public List getUnderlyingInterfaces() { return mUnderlyingIfaces; } @@ -124,8 +124,8 @@ public final class UnderlyingNetworkInfo implements Parcelable { if (!(o instanceof UnderlyingNetworkInfo)) return false; final UnderlyingNetworkInfo that = (UnderlyingNetworkInfo) o; return mOwnerUid == that.getOwnerUid() - && Objects.equals(mIface, that.getIface()) - && Objects.equals(mUnderlyingIfaces, that.getUnderlyingIfaces()); + && Objects.equals(mIface, that.getInterface()) + && Objects.equals(mUnderlyingIfaces, that.getUnderlyingInterfaces()); } @Override diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index e7c0a50163..431b00914f 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -382,8 +382,8 @@ public class NetworkStatsFactory { // Migrate data usage over a VPN to the TUN network. for (UnderlyingNetworkInfo info : vpnArray) { - delta.migrateTun(info.getOwnerUid(), info.getIface(), - info.getUnderlyingIfaces()); + delta.migrateTun(info.getOwnerUid(), info.getInterface(), + info.getUnderlyingInterfaces()); // Filter out debug entries as that may lead to over counting. delta.filterDebugEntries(); } From b679f00398c439ef639d47ef27acab8a0d04a0f6 Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 5 Mar 2021 10:35:11 +0800 Subject: [PATCH 0930/1150] [FUI27] Fix internal naming of notifyNetworkStatus Test: TH Bug: 174123988 Change-Id: I970ee365ca221956ee85788005d331374b5fa71a --- .../app/usage/NetworkStatsManager.java | 15 ++++---- .../android/net/INetworkStatsService.aidl | 4 +-- .../server/net/NetworkStatsService.java | 36 ++++++++++--------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f1132b605..6cb4b5e9b3 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -655,14 +655,14 @@ public class NetworkStatsManager { } /** - * Notify {@code NetworkStatsService} about network status changed. + * Notify {@code NetworkStatsService} about network status changed. * - * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. * - * To avoid races that attribute data usage to wrong network, such as new network with - * the same interface after SIM hot-swap, this function will not return until - * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from - * all data sources. + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. * * @param defaultNetworks the list of all networks that could be used by network traffic that * does not explicitly select a network. @@ -689,8 +689,7 @@ public class NetworkStatsManager { Objects.requireNonNull(defaultNetworks); Objects.requireNonNull(networkStateSnapshots); Objects.requireNonNull(underlyingNetworkInfos); - // TODO: Change internal namings after the name is decided. - mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]), networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); } catch (RemoteException e) { diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index dc3b88a7c3..12937b5cb2 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -65,8 +65,8 @@ interface INetworkStatsService { /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); - /** Force update of ifaces. */ - void forceUpdateIfaces( + /** Notify {@code NetworkStatsService} about network status changed. */ + void notifyNetworkStatus( in Network[] defaultNetworks, in NetworkStateSnapshot[] snapshots, in String activeIface, diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3c14440c64..4ee867b7d0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -181,7 +181,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; - private static final int MSG_UPDATE_IFACES = 3; + private static final int MSG_NOTIFY_NETWORK_STATUS = 3; // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent // deadlock. private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; @@ -379,11 +379,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } - case MSG_UPDATE_IFACES: { + case MSG_NOTIFY_NETWORK_STATUS: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. - updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); + handleNotifyNetworkStatus( + mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } case MSG_PERFORM_POLL_REGISTER_ALERT: { @@ -474,7 +475,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull Looper looper, @NonNull Executor executor, @NonNull NetworkStatsService service) { // TODO: Update RatType passively in NSS, instead of querying into the monitor - // when forceUpdateIface. + // when notifyNetworkStatus. return new NetworkStatsSubscriptionsMonitor(context, looper, executor, (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } @@ -971,16 +972,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public void forceUpdateIfaces( - Network[] defaultNetworks, - NetworkStateSnapshot[] networkStates, - String activeIface, - UnderlyingNetworkInfo[] underlyingNetworkInfos) { + /** + * Notify {@code NetworkStatsService} about network status changed. + */ + public void notifyNetworkStatus( + @NonNull Network[] defaultNetworks, + @NonNull NetworkStateSnapshot[] networkStates, + @Nullable String activeIface, + @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks, networkStates, activeIface); + handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1244,12 +1248,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting public void handleOnCollapsedRatTypeChanged() { // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); + mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay()); } - private void updateIfaces( + private void handleNotifyNetworkStatus( Network[] defaultNetworks, NetworkStateSnapshot[] snapshots, String activeIface) { @@ -1257,7 +1261,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mWakeLock.acquire(); try { mActiveIface = activeIface; - updateIfacesLocked(defaultNetworks, snapshots); + handleNotifyNetworkStatusLocked(defaultNetworks, snapshots); } finally { mWakeLock.release(); } @@ -1270,10 +1274,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@NonNull Network[] defaultNetworks, + private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; - if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()"); // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from From dfc72377430e758cda679acb2b15ff1ed37eda51 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 25 Feb 2021 23:15:07 +0800 Subject: [PATCH 0931/1150] Support to query TYPE_WIFI usage with subscriberId Previous the API ignores subscriberId when network type is WIFI. Allow caller to call querySummaryXXXX with TYPE: WIFI + subscriberId: IMSI to get carrier merged wifi usage which matches the wifi network with the given IMSI. Bug: 176396812 Test: atest -c NetworkStatsServiceTest Change-Id: Ia033521a24e2bb56182d74a41bb2b39710571782 --- core/java/android/app/usage/NetworkStatsManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 6cb4b5e9b3..fe99f8532a 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -644,7 +644,10 @@ public class NetworkStatsManager { : NetworkTemplate.buildTemplateMobileAll(subscriberId); break; case ConnectivityManager.TYPE_WIFI: - template = NetworkTemplate.buildTemplateWifiWildcard(); + template = subscriberId == null + ? NetworkTemplate.buildTemplateWifiWildcard() + : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, + subscriberId); break; default: throw new IllegalArgumentException("Cannot create template for network type " From 5f8c0b0b6b69d4f267f8d8585fd594edf3fb5a3a Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 5 Mar 2021 10:35:11 +0800 Subject: [PATCH 0932/1150] [FUI27] Fix internal naming of notifyNetworkStatus Test: TH Bug: 174123988 Merged-In: I970ee365ca221956ee85788005d331374b5fa71a Change-Id: I970ee365ca221956ee85788005d331374b5fa71a (cherry-picked from aosp/1620539) --- .../app/usage/NetworkStatsManager.java | 15 ++++---- .../android/net/INetworkStatsService.aidl | 4 +-- .../server/net/NetworkStatsService.java | 36 ++++++++++--------- 3 files changed, 29 insertions(+), 26 deletions(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f1132b605..6cb4b5e9b3 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -655,14 +655,14 @@ public class NetworkStatsManager { } /** - * Notify {@code NetworkStatsService} about network status changed. + * Notify {@code NetworkStatsService} about network status changed. * - * Notifies NetworkStatsService of network state changes for data usage accounting purposes. + * Notifies NetworkStatsService of network state changes for data usage accounting purposes. * - * To avoid races that attribute data usage to wrong network, such as new network with - * the same interface after SIM hot-swap, this function will not return until - * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from - * all data sources. + * To avoid races that attribute data usage to wrong network, such as new network with + * the same interface after SIM hot-swap, this function will not return until + * {@code NetworkStatsService} finishes its work of retrieving traffic statistics from + * all data sources. * * @param defaultNetworks the list of all networks that could be used by network traffic that * does not explicitly select a network. @@ -689,8 +689,7 @@ public class NetworkStatsManager { Objects.requireNonNull(defaultNetworks); Objects.requireNonNull(networkStateSnapshots); Objects.requireNonNull(underlyingNetworkInfos); - // TODO: Change internal namings after the name is decided. - mService.forceUpdateIfaces(defaultNetworks.toArray(new Network[0]), + mService.notifyNetworkStatus(defaultNetworks.toArray(new Network[0]), networkStateSnapshots.toArray(new NetworkStateSnapshot[0]), activeIface, underlyingNetworkInfos.toArray(new UnderlyingNetworkInfo[0])); } catch (RemoteException e) { diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index dc3b88a7c3..12937b5cb2 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -65,8 +65,8 @@ interface INetworkStatsService { /** Increment data layer count of operations performed for UID and tag. */ void incrementOperationCount(int uid, int tag, int operationCount); - /** Force update of ifaces. */ - void forceUpdateIfaces( + /** Notify {@code NetworkStatsService} about network status changed. */ + void notifyNetworkStatus( in Network[] defaultNetworks, in NetworkStateSnapshot[] snapshots, in String activeIface, diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 3c14440c64..4ee867b7d0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -181,7 +181,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int MSG_PERFORM_POLL = 1; // Perform polling, persist network, and register the global alert again. private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; - private static final int MSG_UPDATE_IFACES = 3; + private static final int MSG_NOTIFY_NETWORK_STATUS = 3; // A message for broadcasting ACTION_NETWORK_STATS_UPDATED in handler thread to prevent // deadlock. private static final int MSG_BROADCAST_NETWORK_STATS_UPDATED = 4; @@ -379,11 +379,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { performPoll(FLAG_PERSIST_ALL); break; } - case MSG_UPDATE_IFACES: { + case MSG_NOTIFY_NETWORK_STATUS: { // If no cached states, ignore. if (mLastNetworkStateSnapshots == null) break; // TODO (b/181642673): Protect mDefaultNetworks from concurrent accessing. - updateIfaces(mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); + handleNotifyNetworkStatus( + mDefaultNetworks, mLastNetworkStateSnapshots, mActiveIface); break; } case MSG_PERFORM_POLL_REGISTER_ALERT: { @@ -474,7 +475,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull Looper looper, @NonNull Executor executor, @NonNull NetworkStatsService service) { // TODO: Update RatType passively in NSS, instead of querying into the monitor - // when forceUpdateIface. + // when notifyNetworkStatus. return new NetworkStatsSubscriptionsMonitor(context, looper, executor, (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } @@ -971,16 +972,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public void forceUpdateIfaces( - Network[] defaultNetworks, - NetworkStateSnapshot[] networkStates, - String activeIface, - UnderlyingNetworkInfo[] underlyingNetworkInfos) { + /** + * Notify {@code NetworkStatsService} about network status changed. + */ + public void notifyNetworkStatus( + @NonNull Network[] defaultNetworks, + @NonNull NetworkStateSnapshot[] networkStates, + @Nullable String activeIface, + @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { checkNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks, networkStates, activeIface); + handleNotifyNetworkStatus(defaultNetworks, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1244,12 +1248,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @VisibleForTesting public void handleOnCollapsedRatTypeChanged() { // Protect service from frequently updating. Remove pending messages if any. - mHandler.removeMessages(MSG_UPDATE_IFACES); + mHandler.removeMessages(MSG_NOTIFY_NETWORK_STATUS); mHandler.sendMessageDelayed( - mHandler.obtainMessage(MSG_UPDATE_IFACES), mSettings.getPollDelay()); + mHandler.obtainMessage(MSG_NOTIFY_NETWORK_STATUS), mSettings.getPollDelay()); } - private void updateIfaces( + private void handleNotifyNetworkStatus( Network[] defaultNetworks, NetworkStateSnapshot[] snapshots, String activeIface) { @@ -1257,7 +1261,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mWakeLock.acquire(); try { mActiveIface = activeIface; - updateIfacesLocked(defaultNetworks, snapshots); + handleNotifyNetworkStatusLocked(defaultNetworks, snapshots); } finally { mWakeLock.release(); } @@ -1270,10 +1274,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * they are combined under a single {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(@NonNull Network[] defaultNetworks, + private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; - if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); + if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()"); // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from From ee39c8deeccb845ea2b2a160c817071870308e87 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 25 Feb 2021 23:15:07 +0800 Subject: [PATCH 0933/1150] Support to query TYPE_WIFI usage with subscriberId Previous the API ignores subscriberId when network type is WIFI. Allow caller to call querySummaryXXXX with TYPE: WIFI + subscriberId: IMSI to get carrier merged wifi usage which matches the wifi network with the given IMSI. Bug: 176396812 Test: atest -c NetworkStatsServiceTest Change-Id: Ia033521a24e2bb56182d74a41bb2b39710571782 Merged-In: Ia033521a24e2bb56182d74a41bb2b39710571782 --- core/java/android/app/usage/NetworkStatsManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index 9f1132b605..65b9facc86 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -644,7 +644,10 @@ public class NetworkStatsManager { : NetworkTemplate.buildTemplateMobileAll(subscriberId); break; case ConnectivityManager.TYPE_WIFI: - template = NetworkTemplate.buildTemplateWifiWildcard(); + template = subscriberId == null + ? NetworkTemplate.buildTemplateWifiWildcard() + : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, + subscriberId); break; default: throw new IllegalArgumentException("Cannot create template for network type " From 067a1d2448ad21a53799741c6a6c8df841ead11a Mon Sep 17 00:00:00 2001 From: lesl Date: Fri, 7 May 2021 18:15:17 +0800 Subject: [PATCH 0934/1150] Add metered filter for API: buildTemplateCarrier This CL modifies NetworkTemplate#buildTemplateCarrier to force on metered carrier network and rename to buildTemplateCarrierMetered. This method was introduced recently and has no callers. This method will be used in Settings and NetworkPolicyManagerService to display and manage data usage on carrier metered networks. Settings/NetworkPolicyManagerService will use it instead of the existing method buildTemplateMobileAll method, which only matches metered networks. That code will change from matching metered mobile networks to matching metered carrier networks. Note: The carrier metered network includes metered mobile network and metered "merged carrier wifi network" that is a specific cerrier wifi network which provides the same user experience as mobile. Bug: 176396812 Test: atest -c NetworkTemplateTest Change-Id: I7196d62bb60844458a6c4b1d94e2baccb71e15cd Merged-In: I7196d62bb60844458a6c4b1d94e2baccb71e15cd --- core/java/android/net/NetworkTemplate.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index d3c8957494..fd446cdf5c 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -274,11 +274,14 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match all carrier networks with the given IMSI. + * Template to match all metered carrier networks with the given IMSI. */ - public static NetworkTemplate buildTemplateCarrier(@NonNull String subscriberId) { + public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { Objects.requireNonNull(subscriberId); - return new NetworkTemplate(MATCH_CARRIER, subscriberId, null); + return new NetworkTemplate(MATCH_CARRIER, subscriberId, + new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL, + DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + SUBSCRIBER_ID_MATCH_RULE_EXACT); } private final int mMatchRule; From 41e74f4334d5191b3e0c69ce1a710da40b356870 Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 28 Jan 2021 15:58:23 +0800 Subject: [PATCH 0935/1150] carrier data usage: Use carrier template as default policy The carrier network means any network which linked with sepcific subscriberId (for instances: merged Wifi or mobile). Update default policy to use carrier network template to replace mobile template. No impact for current AOSP user because no any wifi network is merged wifi. (Because the merged wifi network requires to support from the wifi module). Also this change convert all of the old policies which template is TYEP_MOBILE to TYPE_CARRIER to match the default policy. Bug: 176396812 Test: atest -c NetworkPolicyManagerServiceTest Test: atest -c CtsHostsideNetworkTests Test: Manual Test with test code (Force wifi to merged wifi). The data will limit when using merged wifi. And mobile policy also work normally. Change-Id: I33c10f7549e713c52ce9afd5b8c4cce2abbda616 --- core/java/android/net/NetworkTemplate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 352f2e99aa..68917a8288 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -514,6 +514,10 @@ public class NetworkTemplate implements Parcelable { return mSubscriberIdMatchRule; } + public int getMeteredness() { + return mMetered; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ From 4ccd2e2d87fd3029c434c04bafc328cb0fad1ac8 Mon Sep 17 00:00:00 2001 From: Treehugger Robot Date: Thu, 20 May 2021 21:47:50 +0000 Subject: [PATCH 0936/1150] Improve documentation of IpSecTunnelInterface#setUnderlyingNetwork Clarify the consequence of adding IpSecTunnelInterface to the underlying network. Bug: 169855650 Test: builds Change-Id: I2e3c4fe735b3374b2ff6d23850970e36c0aafda5 Merged-In: I2e3c4fe735b3374b2ff6d23850970e36c0aafda5 --- core/java/android/net/IpSecManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index 01d1aa533a..c10680761f 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -810,7 +810,9 @@ public final class IpSecManager { * * @param underlyingNetwork the new {@link Network} that will carry traffic for this tunnel. * This network MUST never be the network exposing this IpSecTunnelInterface, otherwise - * this method will throw an {@link IllegalArgumentException}. + * this method will throw an {@link IllegalArgumentException}. If the + * IpSecTunnelInterface is later added to this network, all outbound traffic will be + * blackholed. */ // TODO: b/169171001 Update the documentation when transform migration is supported. // The purpose of making updating network and applying transforms separate is to leave open From 1c5ecec86dad7b764e81c8425f65bdf819f3dd0d Mon Sep 17 00:00:00 2001 From: Pavan Kumar M Date: Mon, 24 May 2021 00:28:41 +0530 Subject: [PATCH 0937/1150] Gracefully handle integer overflows. Avoid recording negative data by doing integer-based math as much as possible, but switch to double-based math if we detect that we'd end up causing an overflow. Test : - Builds, Boots - High data throughput scenarios - NetworkStatsHistoryTest, NetworkStatsCollectionTest, NetworkStatsTest Bug: 119527458 Change-Id: I355fc9bd127da83c1dc70ab3b1261346d4fa5de0 --- core/java/android/net/NetworkStats.java | 47 ++++++++++++++----------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6ccbab7ed8..710a8c65ea 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,6 +16,8 @@ package android.net; +import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; + import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1553,32 +1555,37 @@ public final class NetworkStats implements Parcelable { // processes this every time device has transmitted/received amount equivalent to // global threshold alert (~ 2MB) across all interfaces. final long rxBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxBytes * rxBytes[i] / tunIfaceTotal.rxBytes; + multiplySafeByRational(underlyingIfacesTotal.rxBytes, + rxBytes[i], tunIfaceTotal.rxBytes); // app must not be blamed for more than it consumed on tunIface totalRxBytes = Math.min(rxBytes[i], rxBytesAcrossUnderlyingIfaces); } long totalRxPackets = 0; if (tunIfaceTotal.rxPackets > 0) { final long rxPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.rxPackets * rxPackets[i] / tunIfaceTotal.rxPackets; + multiplySafeByRational(underlyingIfacesTotal.rxPackets, + rxPackets[i], tunIfaceTotal.rxPackets); totalRxPackets = Math.min(rxPackets[i], rxPacketsAcrossUnderlyingIfaces); } long totalTxBytes = 0; if (tunIfaceTotal.txBytes > 0) { final long txBytesAcrossUnderlyingIfaces = - underlyingIfacesTotal.txBytes * txBytes[i] / tunIfaceTotal.txBytes; + multiplySafeByRational(underlyingIfacesTotal.txBytes, + txBytes[i], tunIfaceTotal.txBytes); totalTxBytes = Math.min(txBytes[i], txBytesAcrossUnderlyingIfaces); } long totalTxPackets = 0; if (tunIfaceTotal.txPackets > 0) { final long txPacketsAcrossUnderlyingIfaces = - underlyingIfacesTotal.txPackets * txPackets[i] / tunIfaceTotal.txPackets; + multiplySafeByRational(underlyingIfacesTotal.txPackets, + txPackets[i], tunIfaceTotal.txPackets); totalTxPackets = Math.min(txPackets[i], txPacketsAcrossUnderlyingIfaces); } long totalOperations = 0; if (tunIfaceTotal.operations > 0) { final long operationsAcrossUnderlyingIfaces = - underlyingIfacesTotal.operations * operations[i] / tunIfaceTotal.operations; + multiplySafeByRational(underlyingIfacesTotal.operations, + operations[i], tunIfaceTotal.operations); totalOperations = Math.min(operations[i], operationsAcrossUnderlyingIfaces); } // In a second pass, distribute these values across interfaces in the proportion that @@ -1590,37 +1597,37 @@ public final class NetworkStats implements Parcelable { tmpEntry.set = set[i]; if (underlyingIfacesTotal.rxBytes > 0) { tmpEntry.rxBytes = - totalRxBytes - * perInterfaceTotal[j].rxBytes - / underlyingIfacesTotal.rxBytes; + multiplySafeByRational(totalRxBytes, + perInterfaceTotal[j].rxBytes, + underlyingIfacesTotal.rxBytes); } tmpEntry.rxPackets = 0; if (underlyingIfacesTotal.rxPackets > 0) { tmpEntry.rxPackets = - totalRxPackets - * perInterfaceTotal[j].rxPackets - / underlyingIfacesTotal.rxPackets; + multiplySafeByRational(totalRxPackets, + perInterfaceTotal[j].rxPackets, + underlyingIfacesTotal.rxPackets); } tmpEntry.txBytes = 0; if (underlyingIfacesTotal.txBytes > 0) { tmpEntry.txBytes = - totalTxBytes - * perInterfaceTotal[j].txBytes - / underlyingIfacesTotal.txBytes; + multiplySafeByRational(totalTxBytes, + perInterfaceTotal[j].txBytes, + underlyingIfacesTotal.txBytes); } tmpEntry.txPackets = 0; if (underlyingIfacesTotal.txPackets > 0) { tmpEntry.txPackets = - totalTxPackets - * perInterfaceTotal[j].txPackets - / underlyingIfacesTotal.txPackets; + multiplySafeByRational(totalTxPackets, + perInterfaceTotal[j].txPackets, + underlyingIfacesTotal.txPackets); } tmpEntry.operations = 0; if (underlyingIfacesTotal.operations > 0) { tmpEntry.operations = - totalOperations - * perInterfaceTotal[j].operations - / underlyingIfacesTotal.operations; + multiplySafeByRational(totalOperations, + perInterfaceTotal[j].operations, + underlyingIfacesTotal.operations); } // tmpEntry now contains the migrated data of the i-th entry for the j-th underlying // interface. Add that data usage to this object. From 35a6e5507e271c28375287d7ed9e87b75700082f Mon Sep 17 00:00:00 2001 From: lesl Date: Thu, 28 Jan 2021 15:58:23 +0800 Subject: [PATCH 0938/1150] carrier data usage: Use carrier template as default policy The carrier network means any network which linked with sepcific subscriberId (for instances: merged Wifi or mobile). Update default policy to use carrier network template to replace mobile template. No impact for current AOSP user because no any wifi network is merged wifi. (Because the merged wifi network requires to support from the wifi module). Also this change convert all of the old policies which template is TYEP_MOBILE to TYPE_CARRIER to match the default policy. Bug: 176396812 Test: atest -c NetworkPolicyManagerServiceTest Test: atest -c CtsHostsideNetworkTests Test: Manual Test with test code (Force wifi to merged wifi). The data will limit when using merged wifi. And mobile policy also work normally. Merged-In: I33c10f7549e713c52ce9afd5b8c4cce2abbda616 Change-Id: I33c10f7549e713c52ce9afd5b8c4cce2abbda616 --- core/java/android/net/NetworkTemplate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index fd446cdf5c..249154aa91 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -514,6 +514,10 @@ public class NetworkTemplate implements Parcelable { return mSubscriberIdMatchRule; } + public int getMeteredness() { + return mMetered; + } + /** * Test if given {@link NetworkIdentity} matches this template. */ From 17df73a1b85a128a5f9a9fda780902bc038ed255 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 26 May 2021 10:17:46 +0800 Subject: [PATCH 0939/1150] Make NsdService only start the native daemon when needed and automatically clean it up. Currently, NsdService starts the native mdnsresponder daemon if any NsdManager connect to it, which results in that when any constant service holds the NsdManager connection, the device would always be in the mdns multicast group whatever the connection is not used or not. This is because mdnsresponder will join the multicast group when it starts. To solve this problem, start the native daemon only when needed, and clean it up after the given idle timeout. 1. Start the native daemon when a new request come. 2. If there is no pending request, clean up the daemon after 3 seconds of idle time. Bug: 181810560 Test: atest NsdManagerTest NsdServiceTest Change-Id: I3eb04552f6cf6c0c68c07abffe751bb4d0669215 --- core/java/android/net/nsd/NsdManager.java | 3 + .../java/com/android/server/NsdService.java | 82 ++++++++++++++----- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 64f20b839a..5a25cfc00c 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -199,6 +199,9 @@ public final class NsdManager { /** @hide */ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; + /** @hide */ + public static final int DAEMON_CLEANUP = BASE + 21; + /** @hide */ public static final int ENABLE = BASE + 24; /** @hide */ diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index d907505481..38f7cf6bf5 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -61,6 +61,7 @@ public class NsdService extends INsdManager.Stub { private static final String MDNS_TAG = "mDnsConnector"; private static final boolean DBG = true; + private static final long CLEANUP_DELAY_MS = 3000; private final Context mContext; private final NsdSettings mNsdSettings; @@ -77,6 +78,7 @@ public class NsdService extends INsdManager.Stub { private final SparseArray mIdToClientInfoMap= new SparseArray<>(); private final AsyncChannel mReplyChannel = new AsyncChannel(); + private final long mCleanupDelayMs; private static final int INVALID_ID = 0; private int mUniqueId = 1; @@ -92,6 +94,22 @@ public class NsdService extends INsdManager.Stub { return NsdManager.nameOf(what); } + void maybeStartDaemon() { + mDaemon.maybeStart(); + maybeScheduleStop(); + } + + void maybeScheduleStop() { + if (!isAnyRequestActive()) { + cancelStop(); + sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + } + } + + void cancelStop() { + this.removeMessages(NsdManager.DAEMON_CLEANUP); + } + /** * Observes the NSD on/off setting, and takes action when changed. */ @@ -151,10 +169,6 @@ public class NsdService extends INsdManager.Stub { cInfo.expungeAllRequests(); mClients.remove(msg.replyTo); } - //Last client - if (mClients.size() == 0) { - mDaemon.stop(); - } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -180,6 +194,9 @@ public class NsdService extends INsdManager.Stub { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); break; + case NsdManager.DAEMON_CLEANUP: + mDaemon.maybeStop(); + break; case NsdManager.NATIVE_DAEMON_EVENT: default: Slog.e(TAG, "Unhandled " + msg); @@ -212,16 +229,13 @@ public class NsdService extends INsdManager.Stub { @Override public void enter() { sendNsdStateChangeBroadcast(true); - if (mClients.size() > 0) { - mDaemon.start(); - } } @Override public void exit() { - if (mClients.size() > 0) { - mDaemon.stop(); - } + // TODO: it is incorrect to stop the daemon without expunging all requests + // and sending error callbacks to clients. + maybeScheduleStop(); } private boolean requestLimitReached(ClientInfo clientInfo) { @@ -236,12 +250,15 @@ public class NsdService extends INsdManager.Stub { clientInfo.mClientIds.put(clientId, globalId); clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); + // Remove the cleanup event because here comes a new request. + cancelStop(); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.delete(clientId); clientInfo.mClientRequests.delete(clientId); mIdToClientInfoMap.remove(globalId); + maybeScheduleStop(); } @Override @@ -251,14 +268,12 @@ public class NsdService extends INsdManager.Stub { int id; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - //First client - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && - mClients.size() == 0) { - mDaemon.start(); - } return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: return NOT_HANDLED; + } + + switch (msg.what) { case NsdManager.DISABLE: //TODO: cleanup clients transitionTo(mDisabledState); @@ -274,6 +289,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (discoverServices(id, servInfo.getServiceType())) { if (DBG) { @@ -316,6 +332,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); @@ -357,6 +374,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); @@ -513,6 +531,10 @@ public class NsdService extends INsdManager.Stub { } } + private boolean isAnyRequestActive() { + return mIdToClientInfoMap.size() != 0; + } + private String unescape(String s) { StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); ++i) { @@ -538,7 +560,9 @@ public class NsdService extends INsdManager.Stub { } @VisibleForTesting - NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) { + NsdService(Context ctx, NsdSettings settings, Handler handler, + DaemonConnectionSupplier fn, long cleanupDelayMs) { + mCleanupDelayMs = cleanupDelayMs; mContext = ctx; mNsdSettings = settings; mNsdStateMachine = new NsdStateMachine(TAG, handler); @@ -552,7 +576,8 @@ public class NsdService extends INsdManager.Stub { HandlerThread thread = new HandlerThread(TAG); thread.start(); Handler handler = new Handler(thread.getLooper()); - NsdService service = new NsdService(context, settings, handler, DaemonConnection::new); + NsdService service = new NsdService(context, settings, handler, + DaemonConnection::new, CLEANUP_DELAY_MS); service.mDaemonCallback.awaitConnection(); return service; } @@ -681,12 +706,16 @@ public class NsdService extends INsdManager.Stub { @VisibleForTesting public static class DaemonConnection { final NativeDaemonConnector mNativeConnector; + boolean mIsStarted = false; DaemonConnection(NativeCallbackReceiver callback) { mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); new Thread(mNativeConnector, MDNS_TAG).start(); } + /** + * Executes the specified cmd on the daemon. + */ public boolean execute(Object... args) { if (DBG) { Slog.d(TAG, "mdnssd " + Arrays.toString(args)); @@ -700,12 +729,26 @@ public class NsdService extends INsdManager.Stub { return true; } - public void start() { + /** + * Starts the daemon if it is not already started. + */ + public void maybeStart() { + if (mIsStarted) { + return; + } execute("start-service"); + mIsStarted = true; } - public void stop() { + /** + * Stops the daemon if it is started. + */ + public void maybeStop() { + if (!mIsStarted) { + return; + } execute("stop-service"); + mIsStarted = false; } } @@ -864,6 +907,7 @@ public class NsdService extends INsdManager.Stub { } mClientIds.clear(); mClientRequests.clear(); + mNsdStateMachine.maybeScheduleStop(); } // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, From 74438ecd5ecf15097810c3eca8d1f18df471f710 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Tue, 8 Jun 2021 03:04:27 +0800 Subject: [PATCH 0940/1150] Fix the comments from aosp/1717479. 1. Increase the cleanup delay from 3s to 10s. 2. Fix the comments from aosp/1717479. Bug: 181810560 Test: atest NsdManagerTest NsdServiceTest Change-Id: I71ebdd011574bd96de16a4248b0e15636418e87c --- .../java/com/android/server/NsdService.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 38f7cf6bf5..a9f3a1b63b 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -61,7 +61,7 @@ public class NsdService extends INsdManager.Stub { private static final String MDNS_TAG = "mDnsConnector"; private static final boolean DBG = true; - private static final long CLEANUP_DELAY_MS = 3000; + private static final long CLEANUP_DELAY_MS = 10000; private final Context mContext; private final NsdSettings mNsdSettings; @@ -94,19 +94,25 @@ public class NsdService extends INsdManager.Stub { return NsdManager.nameOf(what); } - void maybeStartDaemon() { + private void maybeStartDaemon() { mDaemon.maybeStart(); maybeScheduleStop(); } - void maybeScheduleStop() { + private boolean isAnyRequestActive() { + return mIdToClientInfoMap.size() != 0; + } + + private void scheduleStop() { + sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + } + private void maybeScheduleStop() { if (!isAnyRequestActive()) { - cancelStop(); - sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + scheduleStop(); } } - void cancelStop() { + private void cancelStop() { this.removeMessages(NsdManager.DAEMON_CLEANUP); } @@ -164,11 +170,16 @@ public class NsdService extends INsdManager.Stub { if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); break; } + cInfo = mClients.get(msg.replyTo); if (cInfo != null) { cInfo.expungeAllRequests(); mClients.remove(msg.replyTo); } + //Last client + if (mClients.size() == 0) { + scheduleStop(); + } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -235,7 +246,7 @@ public class NsdService extends INsdManager.Stub { public void exit() { // TODO: it is incorrect to stop the daemon without expunging all requests // and sending error callbacks to clients. - maybeScheduleStop(); + scheduleStop(); } private boolean requestLimitReached(ClientInfo clientInfo) { @@ -271,9 +282,6 @@ public class NsdService extends INsdManager.Stub { return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: return NOT_HANDLED; - } - - switch (msg.what) { case NsdManager.DISABLE: //TODO: cleanup clients transitionTo(mDisabledState); @@ -531,10 +539,6 @@ public class NsdService extends INsdManager.Stub { } } - private boolean isAnyRequestActive() { - return mIdToClientInfoMap.size() != 0; - } - private String unescape(String s) { StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); ++i) { @@ -907,7 +911,6 @@ public class NsdService extends INsdManager.Stub { } mClientIds.clear(); mClientRequests.clear(); - mNsdStateMachine.maybeScheduleStop(); } // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, From c873a96dcc4535eb1ee6e4720547301235df1423 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Fri, 4 Jun 2021 18:31:42 +0800 Subject: [PATCH 0941/1150] Fix: query TYPE_WIFI usage with empty string Starting with API level 31, the subscriberId is applicable for the wifi network. Considering applications may use null or an empty string as subscriberId (for instance, cts), frameworks create MATCH_WIFI_WILDCARD NetworkTemplate when querying wifi network with null or an empty string which is the behavior before API level 31. Bug: 188915450 Test: atest -c NetworkStatsManagerTest Change-Id: I084b69903f8ba7a6225b312560752e8508938714 --- .../app/usage/NetworkStatsManager.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fe99f8532a..8a6c85d548 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -48,6 +48,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.DataUnit; import android.util.Log; @@ -214,6 +215,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -255,6 +260,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -300,6 +309,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -388,6 +401,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -450,6 +467,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -531,6 +552,10 @@ public class NetworkStatsManager { * null} value when registering for the mobile network type to receive * notifications for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param thresholdBytes Threshold in bytes to be notified on. * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. @@ -644,7 +669,7 @@ public class NetworkStatsManager { : NetworkTemplate.buildTemplateMobileAll(subscriberId); break; case ConnectivityManager.TYPE_WIFI: - template = subscriberId == null + template = TextUtils.isEmpty(subscriberId) ? NetworkTemplate.buildTemplateWifiWildcard() : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, subscriberId); From e022ea5d80ae6da9d72cf8966150b9f196496dad Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Sun, 13 Jun 2021 16:52:05 +0000 Subject: [PATCH 0942/1150] Make NsdService only start the native daemon when needed and automatically clean it up. Currently, NsdService starts the native mdnsresponder daemon if any NsdManager connect to it, which results in that when any constant service holds the NsdManager connection, the device would always be in the mdns multicast group whatever the connection is not used or not. This is because mdnsresponder will join the multicast group when it starts. To solve this problem, start the native daemon only when needed, and clean it up after the given idle timeout. 1. Start the native daemon when a new request come. 2. If there is no pending request, clean up the daemon after 3 seconds of idle time. Bug: 181810560 Test: atest NsdManagerTest NsdServiceTest Original-Change: https://android-review.googlesource.com/1717479 Merged-In: I3eb04552f6cf6c0c68c07abffe751bb4d0669215 Change-Id: I3eb04552f6cf6c0c68c07abffe751bb4d0669215 --- core/java/android/net/nsd/NsdManager.java | 3 + .../java/com/android/server/NsdService.java | 82 ++++++++++++++----- 2 files changed, 66 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index 64f20b839a..5a25cfc00c 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -199,6 +199,9 @@ public final class NsdManager { /** @hide */ public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; + /** @hide */ + public static final int DAEMON_CLEANUP = BASE + 21; + /** @hide */ public static final int ENABLE = BASE + 24; /** @hide */ diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index 84f40cb4b8..a481a6a5d3 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -61,6 +61,7 @@ public class NsdService extends INsdManager.Stub { private static final String MDNS_TAG = "mDnsConnector"; private static final boolean DBG = true; + private static final long CLEANUP_DELAY_MS = 3000; private final Context mContext; private final NsdSettings mNsdSettings; @@ -77,6 +78,7 @@ public class NsdService extends INsdManager.Stub { private final SparseArray mIdToClientInfoMap= new SparseArray<>(); private final AsyncChannel mReplyChannel = new AsyncChannel(); + private final long mCleanupDelayMs; private static final int INVALID_ID = 0; private int mUniqueId = 1; @@ -92,6 +94,22 @@ public class NsdService extends INsdManager.Stub { return NsdManager.nameOf(what); } + void maybeStartDaemon() { + mDaemon.maybeStart(); + maybeScheduleStop(); + } + + void maybeScheduleStop() { + if (!isAnyRequestActive()) { + cancelStop(); + sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + } + } + + void cancelStop() { + this.removeMessages(NsdManager.DAEMON_CLEANUP); + } + /** * Observes the NSD on/off setting, and takes action when changed. */ @@ -151,10 +169,6 @@ public class NsdService extends INsdManager.Stub { cInfo.expungeAllRequests(); mClients.remove(msg.replyTo); } - //Last client - if (mClients.size() == 0) { - mDaemon.stop(); - } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -180,6 +194,9 @@ public class NsdService extends INsdManager.Stub { replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, NsdManager.FAILURE_INTERNAL_ERROR); break; + case NsdManager.DAEMON_CLEANUP: + mDaemon.maybeStop(); + break; case NsdManager.NATIVE_DAEMON_EVENT: default: Slog.e(TAG, "Unhandled " + msg); @@ -212,16 +229,13 @@ public class NsdService extends INsdManager.Stub { @Override public void enter() { sendNsdStateChangeBroadcast(true); - if (mClients.size() > 0) { - mDaemon.start(); - } } @Override public void exit() { - if (mClients.size() > 0) { - mDaemon.stop(); - } + // TODO: it is incorrect to stop the daemon without expunging all requests + // and sending error callbacks to clients. + maybeScheduleStop(); } private boolean requestLimitReached(ClientInfo clientInfo) { @@ -236,12 +250,15 @@ public class NsdService extends INsdManager.Stub { clientInfo.mClientIds.put(clientId, globalId); clientInfo.mClientRequests.put(clientId, what); mIdToClientInfoMap.put(globalId, clientInfo); + // Remove the cleanup event because here comes a new request. + cancelStop(); } private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) { clientInfo.mClientIds.delete(clientId); clientInfo.mClientRequests.delete(clientId); mIdToClientInfoMap.remove(globalId); + maybeScheduleStop(); } @Override @@ -251,14 +268,12 @@ public class NsdService extends INsdManager.Stub { int id; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - //First client - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL && - mClients.size() == 0) { - mDaemon.start(); - } return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: return NOT_HANDLED; + } + + switch (msg.what) { case NsdManager.DISABLE: //TODO: cleanup clients transitionTo(mDisabledState); @@ -274,6 +289,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (discoverServices(id, servInfo.getServiceType())) { if (DBG) { @@ -316,6 +332,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (registerService(id, (NsdServiceInfo) msg.obj)) { if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); @@ -357,6 +374,7 @@ public class NsdService extends INsdManager.Stub { break; } + maybeStartDaemon(); id = getUniqueId(); if (resolveService(id, servInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); @@ -513,6 +531,10 @@ public class NsdService extends INsdManager.Stub { } } + private boolean isAnyRequestActive() { + return mIdToClientInfoMap.size() != 0; + } + private String unescape(String s) { StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); ++i) { @@ -538,7 +560,9 @@ public class NsdService extends INsdManager.Stub { } @VisibleForTesting - NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) { + NsdService(Context ctx, NsdSettings settings, Handler handler, + DaemonConnectionSupplier fn, long cleanupDelayMs) { + mCleanupDelayMs = cleanupDelayMs; mContext = ctx; mNsdSettings = settings; mNsdStateMachine = new NsdStateMachine(TAG, handler); @@ -552,7 +576,8 @@ public class NsdService extends INsdManager.Stub { HandlerThread thread = new HandlerThread(TAG); thread.start(); Handler handler = new Handler(thread.getLooper()); - NsdService service = new NsdService(context, settings, handler, DaemonConnection::new); + NsdService service = new NsdService(context, settings, handler, + DaemonConnection::new, CLEANUP_DELAY_MS); service.mDaemonCallback.awaitConnection(); return service; } @@ -681,12 +706,16 @@ public class NsdService extends INsdManager.Stub { @VisibleForTesting public static class DaemonConnection { final NativeDaemonConnector mNativeConnector; + boolean mIsStarted = false; DaemonConnection(NativeCallbackReceiver callback) { mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null); new Thread(mNativeConnector, MDNS_TAG).start(); } + /** + * Executes the specified cmd on the daemon. + */ public boolean execute(Object... args) { if (DBG) { Slog.d(TAG, "mdnssd " + Arrays.toString(args)); @@ -700,12 +729,26 @@ public class NsdService extends INsdManager.Stub { return true; } - public void start() { + /** + * Starts the daemon if it is not already started. + */ + public void maybeStart() { + if (mIsStarted) { + return; + } execute("start-service"); + mIsStarted = true; } - public void stop() { + /** + * Stops the daemon if it is started. + */ + public void maybeStop() { + if (!mIsStarted) { + return; + } execute("stop-service"); + mIsStarted = false; } } @@ -864,6 +907,7 @@ public class NsdService extends INsdManager.Stub { } mClientIds.clear(); mClientRequests.clear(); + mNsdStateMachine.maybeScheduleStop(); } // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, From 6e1e9ef22222853800c06f03aa4b687381fb6b66 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Fri, 4 Jun 2021 18:31:42 +0800 Subject: [PATCH 0943/1150] Fix: query TYPE_WIFI usage with empty string Starting with API level 31, the subscriberId is applicable for the wifi network. Considering applications may use null or an empty string as subscriberId (for instance, cts), frameworks create MATCH_WIFI_WILDCARD NetworkTemplate when querying wifi network with null or an empty string which is the behavior before API level 31. Bug: 188915450 Test: atest -c NetworkStatsManagerTest Test: atest -c NetworkUsageStatsTest Merged-In: I084b69903f8ba7a6225b312560752e8508938714 Change-Id: I084b69903f8ba7a6225b312560752e8508938714 --- .../app/usage/NetworkStatsManager.java | 27 ++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/core/java/android/app/usage/NetworkStatsManager.java index fe99f8532a..8a6c85d548 100644 --- a/core/java/android/app/usage/NetworkStatsManager.java +++ b/core/java/android/app/usage/NetworkStatsManager.java @@ -48,6 +48,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; import android.telephony.TelephonyManager; +import android.text.TextUtils; import android.util.DataUnit; import android.util.Log; @@ -214,6 +215,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -255,6 +260,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -300,6 +309,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -388,6 +401,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -450,6 +467,10 @@ public class NetworkStatsManager { * null} value when querying for the mobile network type to receive usage * for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param startTime Start of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param endTime End of period. Defined in terms of "Unix time", see @@ -531,6 +552,10 @@ public class NetworkStatsManager { * null} value when registering for the mobile network type to receive * notifications for all mobile networks. For additional details see {@link * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. * @param thresholdBytes Threshold in bytes to be notified on. * @param callback The {@link UsageCallback} that the system will call when data usage * has exceeded the specified threshold. @@ -644,7 +669,7 @@ public class NetworkStatsManager { : NetworkTemplate.buildTemplateMobileAll(subscriberId); break; case ConnectivityManager.TYPE_WIFI: - template = subscriberId == null + template = TextUtils.isEmpty(subscriberId) ? NetworkTemplate.buildTemplateWifiWildcard() : NetworkTemplate.buildTemplateWifi(NetworkTemplate.WIFI_NETWORKID_ALL, subscriberId); From ac4f1912cfb15e85242c35ce9cfbaa9e3464f5bd Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Wed, 23 Jun 2021 06:29:30 +0000 Subject: [PATCH 0944/1150] Fix the comments from aosp/1717479. 1. Increase the cleanup delay from 3s to 10s. 2. Fix the comments from aosp/1717479. Bug: 181810560 Test: atest NsdManagerTest NsdServiceTest Original-Change: https://android-review.googlesource.com/1730170 Merged-In: I71ebdd011574bd96de16a4248b0e15636418e87c Change-Id: I71ebdd011574bd96de16a4248b0e15636418e87c --- .../java/com/android/server/NsdService.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index a481a6a5d3..f440ee8c4e 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -61,7 +61,7 @@ public class NsdService extends INsdManager.Stub { private static final String MDNS_TAG = "mDnsConnector"; private static final boolean DBG = true; - private static final long CLEANUP_DELAY_MS = 3000; + private static final long CLEANUP_DELAY_MS = 10000; private final Context mContext; private final NsdSettings mNsdSettings; @@ -94,19 +94,25 @@ public class NsdService extends INsdManager.Stub { return NsdManager.nameOf(what); } - void maybeStartDaemon() { + private void maybeStartDaemon() { mDaemon.maybeStart(); maybeScheduleStop(); } - void maybeScheduleStop() { + private boolean isAnyRequestActive() { + return mIdToClientInfoMap.size() != 0; + } + + private void scheduleStop() { + sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + } + private void maybeScheduleStop() { if (!isAnyRequestActive()) { - cancelStop(); - sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs); + scheduleStop(); } } - void cancelStop() { + private void cancelStop() { this.removeMessages(NsdManager.DAEMON_CLEANUP); } @@ -164,11 +170,16 @@ public class NsdService extends INsdManager.Stub { if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); break; } + cInfo = mClients.get(msg.replyTo); if (cInfo != null) { cInfo.expungeAllRequests(); mClients.remove(msg.replyTo); } + //Last client + if (mClients.size() == 0) { + scheduleStop(); + } break; case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: AsyncChannel ac = new AsyncChannel(); @@ -235,7 +246,7 @@ public class NsdService extends INsdManager.Stub { public void exit() { // TODO: it is incorrect to stop the daemon without expunging all requests // and sending error callbacks to clients. - maybeScheduleStop(); + scheduleStop(); } private boolean requestLimitReached(ClientInfo clientInfo) { @@ -271,9 +282,6 @@ public class NsdService extends INsdManager.Stub { return NOT_HANDLED; case AsyncChannel.CMD_CHANNEL_DISCONNECTED: return NOT_HANDLED; - } - - switch (msg.what) { case NsdManager.DISABLE: //TODO: cleanup clients transitionTo(mDisabledState); @@ -531,10 +539,6 @@ public class NsdService extends INsdManager.Stub { } } - private boolean isAnyRequestActive() { - return mIdToClientInfoMap.size() != 0; - } - private String unescape(String s) { StringBuilder sb = new StringBuilder(s.length()); for (int i = 0; i < s.length(); ++i) { @@ -907,7 +911,6 @@ public class NsdService extends INsdManager.Stub { } mClientIds.clear(); mClientRequests.clear(); - mNsdStateMachine.maybeScheduleStop(); } // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id, From 788a98192260d396417687877b88e9ace8103338 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Thu, 24 Jun 2021 14:43:09 -0700 Subject: [PATCH 0945/1150] Add support for app data accounting for in-kernel dataplanes This change ensures that app data accounting works correctly within the confines of in-kernel dataplanes, as used by platform VPNs and the VCN. Notably, the VCN MUST NOT specify the IMSI, as that would lead to double counting of the interface statistics. Bug: 175853498 Bug: 190620024 Test: atest NetworkStatsTest FrameworksVcnTests Change-Id: I768907cd3dd2028c7040cddd81fc71a5ce69bbdb --- core/java/android/net/NetworkStats.java | 42 ++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6ccbab7ed8..288b06ee52 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -24,6 +24,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.SystemClock; import android.util.SparseBooleanArray; @@ -1487,8 +1488,31 @@ public final class NetworkStats implements Parcelable { continue; } - if (recycle.uid == tunUid) { - // Add up traffic through tunUid's underlying interfaces. + if (tunUid == Process.SYSTEM_UID) { + // Kernel-based VPN or VCN, traffic sent by apps on the VPN/VCN network + // + // Since the data is not UID-accounted on underlying networks, just use VPN/VCN + // network usage as ground truth. Encrypted traffic on the underlying networks will + // never be processed here because encrypted traffic on the underlying interfaces + // is not present in UID stats, and this method is only called on UID stats. + if (tunIface.equals(recycle.iface)) { + tunIfaceTotal.add(recycle); + underlyingIfacesTotal.add(recycle); + + // In steady state, there should always be one network, but edge cases may + // result in the network being null (network lost), and thus no underlying + // ifaces is possible. + if (perInterfaceTotal.length > 0) { + // While platform VPNs and VCNs have exactly one underlying network, that + // network may have multiple interfaces (eg for 464xlat). This layer does + // not have the required information to identify which of the interfaces + // were used. Select "any" of the interfaces. Since overhead is already + // lost, this number is an approximation anyways. + perInterfaceTotal[0].add(recycle); + } + } + } else if (recycle.uid == tunUid) { + // VpnService VPN, traffic sent by the VPN app over underlying networks for (int j = 0; j < underlyingIfaces.size(); j++) { if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { perInterfaceTotal[j].add(recycle); @@ -1497,7 +1521,7 @@ public final class NetworkStats implements Parcelable { } } } else if (tunIface.equals(recycle.iface)) { - // Add up all tunIface traffic excluding traffic from the vpn app itself. + // VpnService VPN; traffic sent by apps on the VPN network tunIfaceTotal.add(recycle); } } @@ -1532,9 +1556,13 @@ public final class NetworkStats implements Parcelable { // Consider only entries that go onto the VPN interface. continue; } - if (uid[i] == tunUid) { + + if (uid[i] == tunUid && tunUid != Process.SYSTEM_UID) { // Exclude VPN app from the redistribution, as it can choose to create packet // streams by writing to itself. + // + // However, for platform VPNs, do not exclude the system's usage of the VPN network, + // since it is never local-only, and never double counted continue; } tmpEntry.uid = uid[i]; @@ -1641,6 +1669,12 @@ public final class NetworkStats implements Parcelable { int tunUid, @NonNull List underlyingIfaces, @NonNull Entry[] moved) { + if (tunUid == Process.SYSTEM_UID) { + // No traffic recorded on a per-UID basis for in-kernel VPN/VCNs over underlying + // networks; thus no traffic to deduct. + return; + } + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i].uid = tunUid; // Add debug info From 9f97237115caa29539ef2d2d2466bbce8fb866a5 Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 2 Jul 2021 19:12:24 +0000 Subject: [PATCH 0946/1150] Add support for app data accounting for in-kernel dataplanes This change ensures that app data accounting works correctly within the confines of in-kernel dataplanes, as used by platform VPNs and the VCN. Notably, the VCN MUST NOT specify the IMSI, as that would lead to double counting of the interface statistics. Bug: 175853498 Bug: 190620024 Test: atest NetworkStatsTest FrameworksVcnTests Original-Change: https://android-review.googlesource.com/1749070 Merged-In: I768907cd3dd2028c7040cddd81fc71a5ce69bbdb Change-Id: I768907cd3dd2028c7040cddd81fc71a5ce69bbdb --- core/java/android/net/NetworkStats.java | 42 ++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 6ccbab7ed8..288b06ee52 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -24,6 +24,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; +import android.os.Process; import android.os.SystemClock; import android.util.SparseBooleanArray; @@ -1487,8 +1488,31 @@ public final class NetworkStats implements Parcelable { continue; } - if (recycle.uid == tunUid) { - // Add up traffic through tunUid's underlying interfaces. + if (tunUid == Process.SYSTEM_UID) { + // Kernel-based VPN or VCN, traffic sent by apps on the VPN/VCN network + // + // Since the data is not UID-accounted on underlying networks, just use VPN/VCN + // network usage as ground truth. Encrypted traffic on the underlying networks will + // never be processed here because encrypted traffic on the underlying interfaces + // is not present in UID stats, and this method is only called on UID stats. + if (tunIface.equals(recycle.iface)) { + tunIfaceTotal.add(recycle); + underlyingIfacesTotal.add(recycle); + + // In steady state, there should always be one network, but edge cases may + // result in the network being null (network lost), and thus no underlying + // ifaces is possible. + if (perInterfaceTotal.length > 0) { + // While platform VPNs and VCNs have exactly one underlying network, that + // network may have multiple interfaces (eg for 464xlat). This layer does + // not have the required information to identify which of the interfaces + // were used. Select "any" of the interfaces. Since overhead is already + // lost, this number is an approximation anyways. + perInterfaceTotal[0].add(recycle); + } + } + } else if (recycle.uid == tunUid) { + // VpnService VPN, traffic sent by the VPN app over underlying networks for (int j = 0; j < underlyingIfaces.size(); j++) { if (Objects.equals(underlyingIfaces.get(j), recycle.iface)) { perInterfaceTotal[j].add(recycle); @@ -1497,7 +1521,7 @@ public final class NetworkStats implements Parcelable { } } } else if (tunIface.equals(recycle.iface)) { - // Add up all tunIface traffic excluding traffic from the vpn app itself. + // VpnService VPN; traffic sent by apps on the VPN network tunIfaceTotal.add(recycle); } } @@ -1532,9 +1556,13 @@ public final class NetworkStats implements Parcelable { // Consider only entries that go onto the VPN interface. continue; } - if (uid[i] == tunUid) { + + if (uid[i] == tunUid && tunUid != Process.SYSTEM_UID) { // Exclude VPN app from the redistribution, as it can choose to create packet // streams by writing to itself. + // + // However, for platform VPNs, do not exclude the system's usage of the VPN network, + // since it is never local-only, and never double counted continue; } tmpEntry.uid = uid[i]; @@ -1641,6 +1669,12 @@ public final class NetworkStats implements Parcelable { int tunUid, @NonNull List underlyingIfaces, @NonNull Entry[] moved) { + if (tunUid == Process.SYSTEM_UID) { + // No traffic recorded on a per-UID basis for in-kernel VPN/VCNs over underlying + // networks; thus no traffic to deduct. + return; + } + for (int i = 0; i < underlyingIfaces.size(); i++) { moved[i].uid = tunUid; // Add debug info From 7c7697890974e1a9041883bfe561d9b82c701f23 Mon Sep 17 00:00:00 2001 From: paulhu Date: Fri, 9 Apr 2021 15:47:36 +0800 Subject: [PATCH 0947/1150] Rename FIRST_SDK_INT to DEVICE_INITIAL_SDK_INT As API review feedback, rename Build#VERSION#FIRST_SDK_INT to Build#VERSION#DEVICE_INITIAL_SDK_INT. As well as update all usage in frameworks and tests. Bug: 184735771 Test: m Merged-In: I72660959cb4e638a8e80fcf2f4e96ea172969f44 (cherry-pick with minor conflicts) Change-Id: I72660959cb4e638a8e80fcf2f4e96ea172969f44 --- core/java/android/net/IpSecAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 8f1e2defd2..7ef5bac092 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -354,7 +354,7 @@ public final class IpSecAlgorithm implements Parcelable { } for (Entry entry : ALGO_TO_REQUIRED_FIRST_SDK.entrySet()) { - if (Build.VERSION.FIRST_SDK_INT >= entry.getValue()) { + if (Build.VERSION.DEVICE_INITIAL_SDK_INT >= entry.getValue()) { enabledAlgos.add(entry.getKey()); } } From 716683f9582da21b8a2ecad0faef931d61ad3613 Mon Sep 17 00:00:00 2001 From: Luke Huang Date: Mon, 12 Jul 2021 21:15:10 +0800 Subject: [PATCH 0948/1150] Keep the native mdns daemon alive for pre-S application Roll back the behavior changes by checking the target SDK to ensure that there are no compatibility issues with the pre-S application. If the target SDK of the application Date: Mon, 12 Jul 2021 21:15:10 +0800 Subject: [PATCH 0949/1150] Keep the native mdns daemon alive for pre-S application Roll back the behavior changes by checking the target SDK to ensure that there are no compatibility issues with the pre-S application. If the target SDK of the application Date: Wed, 14 Jul 2021 06:44:37 +0000 Subject: [PATCH 0950/1150] Fix mMobileIfaces is not protected by lock Currently, mMobileIfaces is accessed from multiple threads, and should be protected from concurrent accessing. However, since the variable could be accessed frequently, holding the mStatsLock would make this be blocked by network stats I/O operations. Thus, protect the variable by making it volatile. Test: Wifi on/off stress test Bug: 192758557 Change-Id: Ie7694a63f5203ee7c83830ca13d97219b7949fd7 --- .../com/android/server/net/NetworkStatsService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4ee867b7d0..f571b35f8c 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -289,8 +289,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ - @GuardedBy("mStatsLock") - private String[] mMobileIfaces = new String[0]; + private volatile String[] mMobileIfaces = new String[0]; /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ @GuardedBy("mStatsLock") @@ -935,7 +934,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public String[] getMobileIfaces() { - return mMobileIfaces; + return mMobileIfaces.clone(); } @Override @@ -1084,7 +1083,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public long getIfaceStats(String iface, int type) { + public long getIfaceStats(@NonNull String iface, int type) { + Objects.requireNonNull(iface); long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); if (nativeIfaceStats == -1) { return nativeIfaceStats; @@ -1382,7 +1382,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); + mMobileIfaces = mobileIfaces.toArray(new String[0]); } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { From f6f106653235f4c3e3dfdef737893e84ae7fa6e4 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 26 Jul 2021 09:16:59 +0000 Subject: [PATCH 0951/1150] Add debug log for tracking NPE of mMobileIfaces Test: TH Bug: 192758557 Change-Id: Ib048c18b1c64627de5a9d2b04d10e084a014ff64 --- .../com/android/server/net/NetworkStatsService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index f571b35f8c..097b0711ef 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -934,6 +934,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public String[] getMobileIfaces() { + // TODO (b/192758557): Remove debug log. + if (ArrayUtils.contains(mMobileIfaces, null)) { + throw new NullPointerException( + "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); + } return mMobileIfaces.clone(); } @@ -1383,6 +1388,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mMobileIfaces = mobileIfaces.toArray(new String[0]); + // TODO (b/192758557): Remove debug log. + if (ArrayUtils.contains(mMobileIfaces, null)) { + throw new NullPointerException( + "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); + } } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { From fe1b6f90d7b8fa1bfe9055c67e47e32f87173c97 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 30 Jul 2021 02:31:26 +0000 Subject: [PATCH 0952/1150] Fix mMobileIfaces is not protected by lock Currently, mMobileIfaces is accessed from multiple threads, and should be protected from concurrent accessing. However, since the variable could be accessed frequently, holding the mStatsLock would make this be blocked by network stats I/O operations. Thus, protect the variable by making it volatile. Test: Wifi on/off stress test Bug: 192758557 Original-Change: https://android-review.googlesource.com/1765686 Merged-In: Ie7694a63f5203ee7c83830ca13d97219b7949fd7 Change-Id: Ie7694a63f5203ee7c83830ca13d97219b7949fd7 --- .../server/net/NetworkStatsService.java | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 4ee867b7d0..097b0711ef 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -289,8 +289,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ - @GuardedBy("mStatsLock") - private String[] mMobileIfaces = new String[0]; + private volatile String[] mMobileIfaces = new String[0]; /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ @GuardedBy("mStatsLock") @@ -935,7 +934,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public String[] getMobileIfaces() { - return mMobileIfaces; + // TODO (b/192758557): Remove debug log. + if (ArrayUtils.contains(mMobileIfaces, null)) { + throw new NullPointerException( + "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); + } + return mMobileIfaces.clone(); } @Override @@ -1084,7 +1088,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public long getIfaceStats(String iface, int type) { + public long getIfaceStats(@NonNull String iface, int type) { + Objects.requireNonNull(iface); long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); if (nativeIfaceStats == -1) { return nativeIfaceStats; @@ -1382,7 +1387,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - mMobileIfaces = mobileIfaces.toArray(new String[mobileIfaces.size()]); + mMobileIfaces = mobileIfaces.toArray(new String[0]); + // TODO (b/192758557): Remove debug log. + if (ArrayUtils.contains(mMobileIfaces, null)) { + throw new NullPointerException( + "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); + } } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { From 10f9bde2395cd89d22310bc8ea16a73857999a4e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 30 Jul 2021 02:31:26 +0000 Subject: [PATCH 0953/1150] Add debug log for tracking NPE of mMobileIfaces Test: TH Bug: 192758557 Original-Change: https://android-review.googlesource.com/1777887 Merged-In: Ib048c18b1c64627de5a9d2b04d10e084a014ff64 Change-Id: Ib048c18b1c64627de5a9d2b04d10e084a014ff64 From 162b047e746e31a74a1944aed9ab52f9f807fb3e Mon Sep 17 00:00:00 2001 From: Tyler Wear Date: Thu, 26 Aug 2021 10:06:28 -0700 Subject: [PATCH 0954/1150] NetworkStats: Avoid Division By 0 RawBytes should always be at least 1 to avoid division by 0 and ArithmeticException resulting in Settings crash. Bug: 197292638 Change-Id: I4e5ac9da7adf707d7f991483555ab5c6d0cc3245 --- .../java/com/android/server/net/NetworkStatsCollection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 6aefe41891..a090c1aab6 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -285,7 +285,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W combined.getValues(augmentStart, augmentEnd, entry); } - final long rawBytes = entry.rxBytes + entry.txBytes; + final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 : + (entry.rxBytes + entry.txBytes); final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; final long targetBytes = augmentPlan.getDataUsageBytes(); From 5a5866cd0b5b2b4fd08166b60d2a5e572ef619cb Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 1 Sep 2021 07:36:14 +0000 Subject: [PATCH 0955/1150] NetworkStats: Avoid Division By 0 RawBytes should always be at least 1 to avoid division by 0 and ArithmeticException resulting in Settings crash. Bug: 197292638 Change-Id: I4e5ac9da7adf707d7f991483555ab5c6d0cc3245 Merged-In: I4e5ac9da7adf707d7f991483555ab5c6d0cc3245 (cherry picked from commit 93581a034784f7473798e836f52c890a265dfc8b) --- .../java/com/android/server/net/NetworkStatsCollection.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index 557fa89444..df372b1459 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -290,7 +290,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W combined.getValues(augmentStart, augmentEnd, entry); } - final long rawBytes = entry.rxBytes + entry.txBytes; + final long rawBytes = (entry.rxBytes + entry.txBytes) == 0 ? 1 : + (entry.rxBytes + entry.txBytes); final long rawRxBytes = entry.rxBytes == 0 ? 1 : entry.rxBytes; final long rawTxBytes = entry.txBytes == 0 ? 1 : entry.txBytes; final long targetBytes = augmentPlan.getDataUsageBytes(); From da213c052e7b210f83891b36aa748cd7e72f96f0 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 10 Sep 2021 03:20:50 +0800 Subject: [PATCH 0956/1150] Remove forceAllNetworkTypes from test A test should test the actual behavior as much as possible. However, if the flag is true, matchesMobile/matchesMobileWildcard will always return true regardless of the network type and metered. Thus, remove this flag would be closer to the actual behavior. Bug: 183776809 Test: atest FrameworksNetTests Change-Id: I0907a08ca1dd8a14a738db4057ea5ff6a0cd925a --- core/java/android/net/NetworkTemplate.java | 23 ++-------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 68917a8288..08f75df5d8 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -47,7 +47,6 @@ import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -151,24 +150,6 @@ public class NetworkTemplate implements Parcelable { } } - private static boolean sForceAllNetworkTypes = false; - - /** - * Results in matching against all mobile network types. - * - *

            See {@link #matchesMobile} and {@link matchesMobileWildcard}. - */ - @VisibleForTesting - public static void forceAllNetworkTypes() { - sForceAllNetworkTypes = true; - } - - /** Resets the affect of {@link #forceAllNetworkTypes}. */ - @VisibleForTesting - public static void resetForceAllNetworkTypes() { - sForceAllNetworkTypes = false; - } - /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -611,7 +592,7 @@ public class NetworkTemplate implements Parcelable { // Only metered mobile network would be matched regardless of metered filter. // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. // TODO: Respect metered filter and remove mMetered condition. - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + return (ident.mType == TYPE_MOBILE && ident.mMetered) && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); @@ -726,7 +707,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + return (ident.mType == TYPE_MOBILE && ident.mMetered) && matchesCollapsedRatType(ident); } } From 81614d90b02392e08a017ec609fa7b415bc49d22 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 10 Sep 2021 03:20:50 +0800 Subject: [PATCH 0957/1150] Remove forceAllNetworkTypes from test A test should test the actual behavior as much as possible. However, if the flag is true, matchesMobile/matchesMobileWildcard will always return true regardless of the network type and metered. Thus, remove this flag would be closer to the actual behavior. Bug: 183776809 Test: atest FrameworksNetTests Change-Id: I0907a08ca1dd8a14a738db4057ea5ff6a0cd925a Merged-In: I0907a08ca1dd8a14a738db4057ea5ff6a0cd925a --- core/java/android/net/NetworkTemplate.java | 23 ++-------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 249154aa91..e6b5081e39 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -47,7 +47,6 @@ import android.text.TextUtils; import android.util.BackupUtils; import android.util.Log; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -151,24 +150,6 @@ public class NetworkTemplate implements Parcelable { } } - private static boolean sForceAllNetworkTypes = false; - - /** - * Results in matching against all mobile network types. - * - *

            See {@link #matchesMobile} and {@link matchesMobileWildcard}. - */ - @VisibleForTesting - public static void forceAllNetworkTypes() { - sForceAllNetworkTypes = true; - } - - /** Resets the affect of {@link #forceAllNetworkTypes}. */ - @VisibleForTesting - public static void resetForceAllNetworkTypes() { - sForceAllNetworkTypes = false; - } - /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. @@ -611,7 +592,7 @@ public class NetworkTemplate implements Parcelable { // Only metered mobile network would be matched regardless of metered filter. // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. // TODO: Respect metered filter and remove mMetered condition. - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + return (ident.mType == TYPE_MOBILE && ident.mMetered) && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); @@ -726,7 +707,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (sForceAllNetworkTypes || (ident.mType == TYPE_MOBILE && ident.mMetered)) + return (ident.mType == TYPE_MOBILE && ident.mMetered) && matchesCollapsedRatType(ident); } } From e844dbe999dc4bbf0a10046fe00c7793565a6b2c Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 26 Jul 2021 19:49:10 +0800 Subject: [PATCH 0958/1150] Respect metered filter in matchesMobile* In old design, only metered mobile network would be matched, which means that only metered stats could be read if callers query the mobile stats. Currently, the caller in NetworkPolicyManagerService was updated to use the NetworkTemplate constructor with metered parameter in aosp/1563312 which means that the template will be created by a given meteredness. Thus, the hardcode metered can be removed. Remove the metered check from matches method will cause a different behavior. Therefore, to keep the original behavior, if the match rule is MATCH_MOBILE or MATCH_MOBILE_WILDCARD, it should pass METERED_YES to the constructor to build a metered template. Also, if a caller creates a template by calling the constructor with metered as a parameter, the behavior will also be changed. Therefore, if the caller expects to get metered stats then it should change to pass METERED_YES. If the caller expects to get both metered and unmetered stats then it should remain METERED_ALL and it would be a bug that been fixed by this patch. Bug: 183776809 Bug: 202092687 Test: atest FrameworksNetTests:NetworkStatsServiceTest manually test by generating traffic and check the data counts from "adb shell dumpsys netstats --uid" almost equal to the result from "adb shell cmd stats pull-source 10082" Change-Id: I66dd51b020f6d895cd002acc05bef6b6315cd447 --- core/java/android/net/NetworkTemplate.java | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index e6b5081e39..9efafe41f4 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -168,11 +168,11 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -305,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -312,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -589,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -707,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } From 0771c88ba9181769ac5b69d6bd74313b557fc7d5 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 27 Jul 2021 17:02:52 +0800 Subject: [PATCH 0959/1150] Have buildTemplateMobileWithRatType take metered parameter To support unmetered 5g, have buildTemplateMobileWithRatType take metered parameter to build a template which could be used to filter an unmetered network. Bug: 183776809 Test: atest FrameworksNetTests:NetworkStatsServiceTest Change-Id: Ia310d90eceeb572a35ce9518de02b198cae16705 --- core/java/android/net/NetworkTemplate.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 9efafe41f4..fee2e2b274 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -160,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } From 88c9babd371c203cbeddca3e51f4072cf1732cc8 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 26 Jul 2021 19:49:10 +0800 Subject: [PATCH 0960/1150] Respect metered filter in matchesMobile* In old design, only metered mobile network would be matched, which means that only metered stats could be read if callers query the mobile stats. Currently, the caller in NetworkPolicyManagerService was updated to use the NetworkTemplate constructor with metered parameter in aosp/1563312 which means that the template will be created by a given meteredness. Thus, the hardcode metered can be removed. Remove the metered check from matches method will cause a different behavior. Therefore, to keep the original behavior, if the match rule is MATCH_MOBILE or MATCH_MOBILE_WILDCARD, it should pass METERED_YES to the constructor to build a metered template. Also, if a caller creates a template by calling the constructor with metered as a parameter, the behavior will also be changed. Therefore, if the caller expects to get metered stats then it should change to pass METERED_YES. If the caller expects to get both metered and unmetered stats then it should remain METERED_ALL and it would be a bug that been fixed by this patch. Bug: 183776809 Bug: 202092687 Test: atest FrameworksNetTests:NetworkStatsServiceTest manually test by generating traffic and check the data counts from "adb shell dumpsys netstats --uid" almost equal to the result from "adb shell cmd stats pull-source 10082" Change-Id: I66dd51b020f6d895cd002acc05bef6b6315cd447 Merged-In: I66dd51b020f6d895cd002acc05bef6b6315cd447 --- core/java/android/net/NetworkTemplate.java | 25 +++++++++++----------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 08f75df5d8..73c26277ff 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -168,11 +168,11 @@ public class NetworkTemplate implements Parcelable { @NetworkType int ratType) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -305,6 +305,7 @@ public class NetworkTemplate implements Parcelable { } } + // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); @@ -312,9 +313,14 @@ public class NetworkTemplate implements Parcelable { public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates + // to metered networks. It is now possible to match mobile with any meteredness, but + // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this + //constructor passes METERED_YES for these types. + this(matchRule, subscriberId, matchSubscriberIds, networkId, + (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES + : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, + OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } // TODO: Remove it after updating all of the caller. @@ -589,11 +595,7 @@ public class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - // Only metered mobile network would be matched regardless of metered filter. - // This is used to exclude non-metered APNs, e.g. IMS. See ag/908650. - // TODO: Respect metered filter and remove mMetered condition. - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && !ArrayUtils.isEmpty(mMatchSubscriberIds) + return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } @@ -707,8 +709,7 @@ public class NetworkTemplate implements Parcelable { if (ident.mType == TYPE_WIMAX) { return true; } else { - return (ident.mType == TYPE_MOBILE && ident.mMetered) - && matchesCollapsedRatType(ident); + return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident); } } From faf2c9e5d62b81cd68bfa5aab9beabe1223275f7 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 27 Jul 2021 17:02:52 +0800 Subject: [PATCH 0961/1150] Have buildTemplateMobileWithRatType take metered parameter To support unmetered 5g, have buildTemplateMobileWithRatType take metered parameter to build a template which could be used to filter an unmetered network. Bug: 183776809 Test: atest FrameworksNetTests:NetworkStatsServiceTest Change-Id: Ia310d90eceeb572a35ce9518de02b198cae16705 Merged-In: Ia310d90eceeb572a35ce9518de02b198cae16705 --- core/java/android/net/NetworkTemplate.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 73c26277ff..74506dae32 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -160,19 +160,19 @@ public class NetworkTemplate implements Parcelable { } /** - * Template to match cellular networks with the given IMSI and {@code ratType}. - * Use {@link #NETWORK_TYPE_ALL} to include all network types when filtering. - * See {@code TelephonyManager.NETWORK_TYPE_*}. + * Template to match cellular networks with the given IMSI, {@code ratType} and + * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when + * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType) { + @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, - METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } From 0aed3102daff90df6895856fea3511f05bb64057 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 4 May 2021 02:58:04 +0800 Subject: [PATCH 0962/1150] Adapt NET_CAPABILITY_TEMPORARILY_NOT_METERED in NetworkIdentity NET_CAPABILITY_TEMPORARILY_NOT_METERED is a capability indicates networks are generally metered, but are currently unmetered. NetworkIdentity currently did not consider it which will cause Settings shows high data usage. To exclude unmetered 5g from the metered usage, NetworkIdentity should consider a network with NET_CAPABILITY_TEMPORARILY_NOT_METERED capabilities as not metered. Bug: 183776809 Test: FrameworksNetTests:NetworkIdentityTest Change-Id: Iadbc082b52f16708207e8aecf0904356bc0898ab --- core/java/android/net/NetworkIdentity.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java index 1d07a0330b..eb8f43e3d0 100644 --- a/core/java/android/net/NetworkIdentity.java +++ b/core/java/android/net/NetworkIdentity.java @@ -220,8 +220,10 @@ public class NetworkIdentity implements Comparable { String networkId = null; boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED); + boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + || snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); From 927a6a7fdcc97d53859da225f07e7807aa4709ae Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 26 Oct 2021 09:00:50 +0000 Subject: [PATCH 0963/1150] Replace @hide APIs in IpSecService - Replace Slog with Log - Replace Binder.withCleanCallingIdentity with BinderUtils.withCleanCallingIdentity Bug: 204153604 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: I63083b3a4e50afe5154b4e8585d0eee46da819c6 --- services/core/java/com/android/server/IpSecService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java index d6ee95131e..aeb814327e 100644 --- a/services/core/java/com/android/server/IpSecService.java +++ b/services/core/java/com/android/server/IpSecService.java @@ -58,13 +58,13 @@ import android.system.OsConstants; import android.text.TextUtils; import android.util.Log; import android.util.Range; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; +import com.android.net.module.util.BinderUtils; import com.android.net.module.util.NetdUtils; import com.android.net.module.util.PermissionUtils; @@ -1056,9 +1056,9 @@ public class IpSecService extends IIpSecService.Stub { public void systemReady() { if (isNetdAlive()) { - Slog.d(TAG, "IpSecService is ready"); + Log.d(TAG, "IpSecService is ready"); } else { - Slog.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); + Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); } } @@ -1332,7 +1332,7 @@ public class IpSecService extends IIpSecService.Stub { final INetd netd = mSrvConfig.getNetdInstance(); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); - Binder.withCleanCallingIdentity(() -> { + BinderUtils.withCleanCallingIdentity(() -> { NetdUtils.setInterfaceUp(netd, intfName); }); From 1e1cd496f694a7c26d2e38b6d6f0006d9250b469 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Wed, 3 Nov 2021 19:57:54 +0800 Subject: [PATCH 0964/1150] Fix normalize doesn't work on carrier template From android 12, the subscriberId is being used for different network types. For instances: The TYPE_WIFI with subscriberId means that it is a merged wifi network. The TYPE_CARRIER means that the network associate to specific carrier network (subscriberId). So remove the check "isMatchRuleMobile" and only check whether subscriberId is being used in NetworkTemplate or not. Bug: 194939211 Test: atest -c NetworkTemplateTest Change-Id: I80c9f887cf8b4714716d657da92ed273a532ce27 --- core/java/android/net/NetworkTemplate.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 74506dae32..ee24084e63 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -777,8 +777,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. *

            @@ -793,8 +793,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -806,7 +806,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { From 3d30b93d609a5889a6c8966e04181c71fc589855 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 9 Sep 2021 17:39:05 +0900 Subject: [PATCH 0965/1150] Remove AsyncChannel usage in NsdManager Replace AsyncChannel with two AIDL interfaces: INsdManagerCallback and INsdServiceConnector. This will be helpful to move NsdManager into a module, avoiding the dependency on the hidden AsyncChannel utility. Bug: 190249673 Test: atest FrameworksNetTests CtsNetTestCases:NsdManagerTest Change-Id: Id9e8feb95cbb5ba16f00893f6c3f37fced3358c1 --- core/java/android/net/nsd/INsdManager.aidl | 13 +- .../android/net/nsd/INsdManagerCallback.aidl | 39 ++ .../android/net/nsd/INsdServiceConnector.aidl | 35 ++ core/java/android/net/nsd/NsdManager.java | 215 +++++---- core/java/android/net/nsd/NsdServiceInfo.aidl | 19 + .../java/com/android/server/NsdService.java | 443 +++++++++++------- 6 files changed, 509 insertions(+), 255 deletions(-) create mode 100644 core/java/android/net/nsd/INsdManagerCallback.aidl create mode 100644 core/java/android/net/nsd/INsdServiceConnector.aidl create mode 100644 core/java/android/net/nsd/NsdServiceInfo.aidl diff --git a/core/java/android/net/nsd/INsdManager.aidl b/core/java/android/net/nsd/INsdManager.aidl index e9e8935a19..89e9cdbd44 100644 --- a/core/java/android/net/nsd/INsdManager.aidl +++ b/core/java/android/net/nsd/INsdManager.aidl @@ -1,5 +1,5 @@ /** - * Copyright (c) 2012, The Android Open Source Project + * Copyright (c) 2021, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,15 @@ package android.net.nsd; +import android.net.nsd.INsdManagerCallback; +import android.net.nsd.INsdServiceConnector; import android.os.Messenger; /** - * Interface that NsdService implements + * Interface that NsdService implements to connect NsdManager clients. * * {@hide} */ -interface INsdManager -{ - @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) - Messenger getMessenger(); - void setEnabled(boolean enable); +interface INsdManager { + INsdServiceConnector connect(INsdManagerCallback cb); } diff --git a/core/java/android/net/nsd/INsdManagerCallback.aidl b/core/java/android/net/nsd/INsdManagerCallback.aidl new file mode 100644 index 0000000000..1a262ec0e9 --- /dev/null +++ b/core/java/android/net/nsd/INsdManagerCallback.aidl @@ -0,0 +1,39 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +import android.os.Messenger; +import android.net.nsd.NsdServiceInfo; + +/** + * Callbacks from NsdService to NsdManager + * @hide + */ +oneway interface INsdManagerCallback { + void onDiscoverServicesStarted(int listenerKey, in NsdServiceInfo info); + void onDiscoverServicesFailed(int listenerKey, int error); + void onServiceFound(int listenerKey, in NsdServiceInfo info); + void onServiceLost(int listenerKey, in NsdServiceInfo info); + void onStopDiscoveryFailed(int listenerKey, int error); + void onStopDiscoverySucceeded(int listenerKey); + void onRegisterServiceFailed(int listenerKey, int error); + void onRegisterServiceSucceeded(int listenerKey, in NsdServiceInfo info); + void onUnregisterServiceFailed(int listenerKey, int error); + void onUnregisterServiceSucceeded(int listenerKey); + void onResolveServiceFailed(int listenerKey, int error); + void onResolveServiceSucceeded(int listenerKey, in NsdServiceInfo info); +} diff --git a/core/java/android/net/nsd/INsdServiceConnector.aidl b/core/java/android/net/nsd/INsdServiceConnector.aidl new file mode 100644 index 0000000000..b06ae55b15 --- /dev/null +++ b/core/java/android/net/nsd/INsdServiceConnector.aidl @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +import android.net.nsd.INsdManagerCallback; +import android.net.nsd.NsdServiceInfo; +import android.os.Messenger; + +/** + * Interface that NsdService implements for each NsdManager client. + * + * {@hide} + */ +interface INsdServiceConnector { + void registerService(int listenerKey, in NsdServiceInfo serviceInfo); + void unregisterService(int listenerKey); + void discoverServices(int listenerKey, in NsdServiceInfo serviceInfo); + void stopDiscovery(int listenerKey); + void resolveService(int listenerKey, in NsdServiceInfo serviceInfo); + void startDaemon(); +} \ No newline at end of file diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java index ae8d010194..6c597e26e0 100644 --- a/core/java/android/net/nsd/NsdManager.java +++ b/core/java/android/net/nsd/NsdManager.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,17 +31,13 @@ import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; -import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; -import java.util.concurrent.CountDownLatch; - /** * The Network Service Discovery Manager class provides the API to discover services * on a network. As an example, if device A and device B are connected over a Wi-Fi @@ -234,6 +230,11 @@ public final class NsdManager { /** @hide */ public static final int NATIVE_DAEMON_EVENT = BASE + 26; + /** @hide */ + public static final int REGISTER_CLIENT = BASE + 27; + /** @hide */ + public static final int UNREGISTER_CLIENT = BASE + 28; + /** Dns based service discovery protocol */ public static final int PROTOCOL_DNS_SD = 0x0001; @@ -274,7 +275,7 @@ public final class NsdManager { private static final int FIRST_LISTENER_KEY = 1; - private final INsdManager mService; + private final INsdServiceConnector mService; private final Context mContext; private int mListenerKey = FIRST_LISTENER_KEY; @@ -282,9 +283,7 @@ public final class NsdManager { private final SparseArray mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); - private final AsyncChannel mAsyncChannel = new AsyncChannel(); - private ServiceHandler mHandler; - private final CountDownLatch mConnected = new CountDownLatch(1); + private final ServiceHandler mHandler; /** * Create a new Nsd instance. Applications use @@ -295,18 +294,108 @@ public final class NsdManager { * is a system private class. */ public NsdManager(Context context, INsdManager service) { - mService = service; mContext = context; - init(); + + HandlerThread t = new HandlerThread("NsdManager"); + t.start(); + mHandler = new ServiceHandler(t.getLooper()); + + try { + mService = service.connect(new NsdCallbackImpl(mHandler)); + } catch (RemoteException e) { + throw new RuntimeException("Failed to connect to NsdService"); + } + + // Only proactively start the daemon if the target SDK < S, otherwise the internal service + // would automatically start/stop the native daemon as needed. + if (!CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) { + try { + mService.startDaemon(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to proactively start daemon"); + // Continue: the daemon can still be started on-demand later + } + } } - /** - * @hide - */ - @VisibleForTesting - public void disconnect() { - mAsyncChannel.disconnect(); - mHandler.getLooper().quitSafely(); + private static class NsdCallbackImpl extends INsdManagerCallback.Stub { + private final Handler mServHandler; + + NsdCallbackImpl(Handler serviceHandler) { + mServHandler = serviceHandler; + } + + private void sendInfo(int message, int listenerKey, NsdServiceInfo info) { + mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey, info)); + } + + private void sendError(int message, int listenerKey, int error) { + mServHandler.sendMessage(mServHandler.obtainMessage(message, error, listenerKey)); + } + + private void sendNoArg(int message, int listenerKey) { + mServHandler.sendMessage(mServHandler.obtainMessage(message, 0, listenerKey)); + } + + @Override + public void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { + sendInfo(DISCOVER_SERVICES_STARTED, listenerKey, info); + } + + @Override + public void onDiscoverServicesFailed(int listenerKey, int error) { + sendError(DISCOVER_SERVICES_FAILED, listenerKey, error); + } + + @Override + public void onServiceFound(int listenerKey, NsdServiceInfo info) { + sendInfo(SERVICE_FOUND, listenerKey, info); + } + + @Override + public void onServiceLost(int listenerKey, NsdServiceInfo info) { + sendInfo(SERVICE_LOST, listenerKey, info); + } + + @Override + public void onStopDiscoveryFailed(int listenerKey, int error) { + sendError(STOP_DISCOVERY_FAILED, listenerKey, error); + } + + @Override + public void onStopDiscoverySucceeded(int listenerKey) { + sendNoArg(STOP_DISCOVERY_SUCCEEDED, listenerKey); + } + + @Override + public void onRegisterServiceFailed(int listenerKey, int error) { + sendError(REGISTER_SERVICE_FAILED, listenerKey, error); + } + + @Override + public void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { + sendInfo(REGISTER_SERVICE_SUCCEEDED, listenerKey, info); + } + + @Override + public void onUnregisterServiceFailed(int listenerKey, int error) { + sendError(UNREGISTER_SERVICE_FAILED, listenerKey, error); + } + + @Override + public void onUnregisterServiceSucceeded(int listenerKey) { + sendNoArg(UNREGISTER_SERVICE_SUCCEEDED, listenerKey); + } + + @Override + public void onResolveServiceFailed(int listenerKey, int error) { + sendError(RESOLVE_SERVICE_FAILED, listenerKey, error); + } + + @Override + public void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { + sendInfo(RESOLVE_SERVICE_SUCCEEDED, listenerKey, info); + } } /** @@ -376,19 +465,6 @@ public final class NsdManager { public void handleMessage(Message message) { final int what = message.what; final int key = message.arg2; - switch (what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); - return; - case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED: - mConnected.countDown(); - return; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - Log.e(TAG, "Channel lost"); - return; - default: - break; - } final Object listener; final NsdServiceInfo ns; synchronized (mMapLock) { @@ -503,36 +579,6 @@ public final class NsdManager { return s.getServiceType(); } - /** - * Initialize AsyncChannel - */ - private void init() { - final Messenger messenger = getMessenger(); - if (messenger == null) { - fatal("Failed to obtain service Messenger"); - } - HandlerThread t = new HandlerThread("NsdManager"); - t.start(); - mHandler = new ServiceHandler(t.getLooper()); - mAsyncChannel.connect(mContext, mHandler, messenger); - try { - mConnected.await(); - } catch (InterruptedException e) { - fatal("Interrupted wait at init"); - } - if (CompatChanges.isChangeEnabled(RUN_NATIVE_NSD_ONLY_IF_LEGACY_APPS)) { - return; - } - // Only proactively start the daemon if the target SDK < S, otherwise the internal service - // would automatically start/stop the native daemon as needed. - mAsyncChannel.sendMessage(DAEMON_STARTUP); - } - - private static void fatal(String msg) { - Log.e(TAG, msg); - throw new RuntimeException(msg); - } - /** * Register a service to be discovered by other services. * @@ -556,7 +602,11 @@ public final class NsdManager { checkServiceInfo(serviceInfo); checkProtocol(protocolType); int key = putListener(listener, serviceInfo); - mAsyncChannel.sendMessage(REGISTER_SERVICE, 0, key, serviceInfo); + try { + mService.registerService(key, serviceInfo); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** @@ -574,7 +624,11 @@ public final class NsdManager { */ public void unregisterService(RegistrationListener listener) { int id = getListenerKey(listener); - mAsyncChannel.sendMessage(UNREGISTER_SERVICE, 0, id); + try { + mService.unregisterService(id); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** @@ -613,7 +667,11 @@ public final class NsdManager { s.setServiceType(serviceType); int key = putListener(listener, s); - mAsyncChannel.sendMessage(DISCOVER_SERVICES, 0, key, s); + try { + mService.discoverServices(key, s); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** @@ -634,7 +692,11 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); - mAsyncChannel.sendMessage(STOP_DISCOVERY, 0, id); + try { + mService.stopDiscovery(id); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } } /** @@ -649,29 +711,10 @@ public final class NsdManager { public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { checkServiceInfo(serviceInfo); int key = putListener(listener, serviceInfo); - mAsyncChannel.sendMessage(RESOLVE_SERVICE, 0, key, serviceInfo); - } - - /** Internal use only @hide */ - public void setEnabled(boolean enabled) { try { - mService.setEnabled(enabled); + mService.resolveService(key, serviceInfo); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Get a reference to NsdService handler. This is used to establish - * an AsyncChannel communication with the service - * - * @return Messenger pointing to the NsdService handler - */ - private Messenger getMessenger() { - try { - return mService.getMessenger(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + e.rethrowFromSystemServer(); } } diff --git a/core/java/android/net/nsd/NsdServiceInfo.aidl b/core/java/android/net/nsd/NsdServiceInfo.aidl new file mode 100644 index 0000000000..657bdd1e87 --- /dev/null +++ b/core/java/android/net/nsd/NsdServiceInfo.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.nsd; + +@JavaOnlyStableParcelable parcelable NsdServiceInfo; \ No newline at end of file diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java index c9608a5517..3e0208411c 100644 --- a/services/core/java/com/android/server/NsdService.java +++ b/services/core/java/com/android/server/NsdService.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,24 +20,27 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.database.ContentObserver; -import android.net.NetworkStack; import android.net.Uri; import android.net.nsd.INsdManager; +import android.net.nsd.INsdManagerCallback; +import android.net.nsd.INsdServiceConnector; import android.net.nsd.NsdManager; import android.net.nsd.NsdServiceInfo; import android.os.Handler; import android.os.HandlerThread; +import android.os.IBinder; import android.os.Message; -import android.os.Messenger; +import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.util.Base64; +import android.util.Log; +import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.AsyncChannel; import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; @@ -72,12 +75,11 @@ public class NsdService extends INsdManager.Stub { /** * Clients receiving asynchronous messages */ - private final HashMap mClients = new HashMap<>(); + private final HashMap mClients = new HashMap<>(); /* A map from unique id to client info */ private final SparseArray mIdToClientInfoMap= new SparseArray<>(); - private final AsyncChannel mReplyChannel = new AsyncChannel(); private final long mCleanupDelayMs; private static final int INVALID_ID = 0; @@ -149,65 +151,66 @@ public class NsdService extends INsdManager.Stub { class DefaultState extends State { @Override public boolean processMessage(Message msg) { - ClientInfo cInfo = null; + final ClientInfo cInfo; + final int clientId = msg.arg2; switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - AsyncChannel c = (AsyncChannel) msg.obj; - if (DBG) Slog.d(TAG, "New client listening to asynchronous messages"); - c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED); - cInfo = new ClientInfo(c, msg.replyTo); - mClients.put(msg.replyTo, cInfo); - } else { - Slog.e(TAG, "Client connection failure, error=" + msg.arg1); + case NsdManager.REGISTER_CLIENT: + final Pair arg = + (Pair) msg.obj; + final INsdManagerCallback cb = arg.second; + try { + cb.asBinder().linkToDeath(arg.first, 0); + cInfo = new ClientInfo(cb); + mClients.put(arg.first, cInfo); + } catch (RemoteException e) { + Log.w(TAG, "Client " + clientId + " has already died"); } break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - switch (msg.arg1) { - case AsyncChannel.STATUS_SEND_UNSUCCESSFUL: - Slog.e(TAG, "Send failed, client connection lost"); - break; - case AsyncChannel.STATUS_REMOTE_DISCONNECTION: - if (DBG) Slog.d(TAG, "Client disconnected"); - break; - default: - if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); - break; - } - - cInfo = mClients.get(msg.replyTo); + case NsdManager.UNREGISTER_CLIENT: + final NsdServiceConnector connector = (NsdServiceConnector) msg.obj; + cInfo = mClients.remove(connector); if (cInfo != null) { cInfo.expungeAllRequests(); - mClients.remove(msg.replyTo); if (cInfo.isLegacy()) { mLegacyClientCount -= 1; } } maybeScheduleStop(); break; - case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, getHandler(), msg.replyTo); - break; case NsdManager.DISCOVER_SERVICES: - replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onDiscoverServicesFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } break; case NsdManager.STOP_DISCOVERY: - replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onStopDiscoveryFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } break; case NsdManager.REGISTER_SERVICE: - replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onRegisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } break; case NsdManager.UNREGISTER_SERVICE: - replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onUnregisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } break; case NsdManager.RESOLVE_SERVICE: - replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + cInfo = getClientInfoForReply(msg); + if (cInfo != null) { + cInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); + } break; case NsdManager.DAEMON_CLEANUP: mDaemon.maybeStop(); @@ -215,7 +218,7 @@ public class NsdService extends INsdManager.Stub { // This event should be only sent by the legacy (target SDK < S) clients. // Mark the sending client as legacy. case NsdManager.DAEMON_STARTUP: - cInfo = mClients.get(msg.replyTo); + cInfo = getClientInfoForReply(msg); if (cInfo != null) { cancelStop(); cInfo.setLegacy(); @@ -230,6 +233,11 @@ public class NsdService extends INsdManager.Stub { } return HANDLED; } + + private ClientInfo getClientInfoForReply(Message msg) { + final ListenerArgs args = (ListenerArgs) msg.obj; + return mClients.get(args.connector); + } } class DisabledState extends State { @@ -289,122 +297,119 @@ public class NsdService extends INsdManager.Stub { @Override public boolean processMessage(Message msg) { - ClientInfo clientInfo; - NsdServiceInfo servInfo; - int id; + final ClientInfo clientInfo; + final int id; + final int clientId = msg.arg2; + final ListenerArgs args; switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - return NOT_HANDLED; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - return NOT_HANDLED; case NsdManager.DISABLE: //TODO: cleanup clients transitionTo(mDisabledState); break; case NsdManager.DISCOVER_SERVICES: if (DBG) Slog.d(TAG, "Discover services"); - servInfo = (NsdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); if (requestLimitReached(clientInfo)) { - replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.FAILURE_MAX_LIMIT); + clientInfo.onDiscoverServicesFailed( + clientId, NsdManager.FAILURE_MAX_LIMIT); break; } maybeStartDaemon(); id = getUniqueId(); - if (discoverServices(id, servInfo.getServiceType())) { + if (discoverServices(id, args.serviceInfo.getServiceType())) { if (DBG) { Slog.d(TAG, "Discover " + msg.arg2 + " " + id + - servInfo.getServiceType()); + args.serviceInfo.getServiceType()); } - storeRequestMap(msg.arg2, id, clientInfo, msg.what); - replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo); + storeRequestMap(clientId, id, clientInfo, msg.what); + clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo); } else { stopServiceDiscovery(id); - replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED, + clientInfo.onDiscoverServicesFailed(clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.STOP_DISCOVERY: if (DBG) Slog.d(TAG, "Stop service discovery"); - clientInfo = mClients.get(msg.replyTo); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); try { - id = clientInfo.mClientIds.get(msg.arg2); + id = clientInfo.mClientIds.get(clientId); } catch (NullPointerException e) { - replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.onStopDiscoveryFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; } - removeRequestMap(msg.arg2, id, clientInfo); + removeRequestMap(clientId, id, clientInfo); if (stopServiceDiscovery(id)) { - replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED); + clientInfo.onStopDiscoverySucceeded(clientId); } else { - replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.onStopDiscoveryFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.REGISTER_SERVICE: if (DBG) Slog.d(TAG, "Register service"); - clientInfo = mClients.get(msg.replyTo); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); if (requestLimitReached(clientInfo)) { - replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.FAILURE_MAX_LIMIT); + clientInfo.onRegisterServiceFailed( + clientId, NsdManager.FAILURE_MAX_LIMIT); break; } maybeStartDaemon(); id = getUniqueId(); - if (registerService(id, (NsdServiceInfo) msg.obj)) { - if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id); - storeRequestMap(msg.arg2, id, clientInfo, msg.what); + if (registerService(id, args.serviceInfo)) { + if (DBG) Slog.d(TAG, "Register " + clientId + " " + id); + storeRequestMap(clientId, id, clientInfo, msg.what); // Return success after mDns reports success } else { unregisterService(id); - replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.onRegisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.UNREGISTER_SERVICE: if (DBG) Slog.d(TAG, "unregister service"); - clientInfo = mClients.get(msg.replyTo); - try { - id = clientInfo.mClientIds.get(msg.arg2); - } catch (NullPointerException e) { - replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); + if (clientInfo == null) { + Slog.e(TAG, "Unknown connector in unregistration"); break; } - removeRequestMap(msg.arg2, id, clientInfo); + id = clientInfo.mClientIds.get(clientId); + removeRequestMap(clientId, id, clientInfo); if (unregisterService(id)) { - replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED); + clientInfo.onUnregisterServiceSucceeded(clientId); } else { - replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.onUnregisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.RESOLVE_SERVICE: if (DBG) Slog.d(TAG, "Resolve service"); - servInfo = (NsdServiceInfo) msg.obj; - clientInfo = mClients.get(msg.replyTo); - + args = (ListenerArgs) msg.obj; + clientInfo = mClients.get(args.connector); if (clientInfo.mResolvedService != null) { - replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_ALREADY_ACTIVE); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_ALREADY_ACTIVE); break; } maybeStartDaemon(); id = getUniqueId(); - if (resolveService(id, servInfo)) { + if (resolveService(id, args.serviceInfo)) { clientInfo.mResolvedService = new NsdServiceInfo(); - storeRequestMap(msg.arg2, id, clientInfo, msg.what); + storeRequestMap(clientId, id, clientInfo, msg.what); } else { - replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); } break; case NsdManager.NATIVE_DAEMON_EVENT: @@ -449,30 +454,27 @@ public class NsdService extends INsdManager.Stub { case NativeResponseCode.SERVICE_FOUND: /* NNN uniqueId serviceName regType domain */ servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0, - clientId, servInfo); + clientInfo.onServiceFound(clientId, servInfo); break; case NativeResponseCode.SERVICE_LOST: /* NNN uniqueId serviceName regType domain */ servInfo = new NsdServiceInfo(cooked[2], cooked[3]); - clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0, - clientId, servInfo); + clientInfo.onServiceLost(clientId, servInfo); break; case NativeResponseCode.SERVICE_DISCOVERY_FAILED: /* NNN uniqueId errorCode */ - clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onDiscoverServicesFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_REGISTERED: /* NNN regId serviceName regType */ servInfo = new NsdServiceInfo(cooked[2], null); - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED, - id, clientId, servInfo); + clientInfo.onRegisterServiceSucceeded(clientId, servInfo); break; case NativeResponseCode.SERVICE_REGISTRATION_FAILED: /* NNN regId errorCode */ - clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onRegisterServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_UPDATED: /* NNN regId */ @@ -511,8 +513,8 @@ public class NsdService extends INsdManager.Stub { if (getAddrInfo(id2, cooked[3])) { storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); clientInfo.mResolvedService = null; } break; @@ -521,26 +523,26 @@ public class NsdService extends INsdManager.Stub { stopResolveService(id); removeRequestMap(clientId, id, clientInfo); clientInfo.mResolvedService = null; - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_GET_ADDR_FAILED: /* NNN resolveId errorCode */ stopGetAddrInfo(id); removeRequestMap(clientId, id, clientInfo); clientInfo.mResolvedService = null; - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: /* NNN resolveId hostname ttl addr */ try { clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED, - 0, clientId, clientInfo.mResolvedService); + clientInfo.onResolveServiceSucceeded( + clientId, clientInfo.mResolvedService); } catch (java.net.UnknownHostException e) { - clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED, - NsdManager.FAILURE_INTERNAL_ERROR, clientId); + clientInfo.onResolveServiceFailed( + clientId, NsdManager.FAILURE_INTERNAL_ERROR); } stopGetAddrInfo(id); removeRequestMap(clientId, id, clientInfo); @@ -601,15 +603,71 @@ public class NsdService extends INsdManager.Stub { return service; } - public Messenger getMessenger() { + @Override + public INsdServiceConnector connect(INsdManagerCallback cb) { mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService"); - return new Messenger(mNsdStateMachine.getHandler()); + final INsdServiceConnector connector = new NsdServiceConnector(); + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.REGISTER_CLIENT, new Pair<>(connector, cb))); + return connector; } - public void setEnabled(boolean isEnabled) { - NetworkStack.checkNetworkStackPermission(mContext); - mNsdSettings.putEnabledStatus(isEnabled); - notifyEnabled(isEnabled); + private static class ListenerArgs { + public final NsdServiceConnector connector; + public final NsdServiceInfo serviceInfo; + ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) { + this.connector = connector; + this.serviceInfo = serviceInfo; + } + } + + private class NsdServiceConnector extends INsdServiceConnector.Stub + implements IBinder.DeathRecipient { + @Override + public void registerService(int listenerKey, NsdServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.REGISTER_SERVICE, 0, listenerKey, + new ListenerArgs(this, serviceInfo))); + } + + @Override + public void unregisterService(int listenerKey) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.UNREGISTER_SERVICE, 0, listenerKey, + new ListenerArgs(this, null))); + } + + @Override + public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.DISCOVER_SERVICES, 0, listenerKey, + new ListenerArgs(this, serviceInfo))); + } + + @Override + public void stopDiscovery(int listenerKey) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null))); + } + + @Override + public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.RESOLVE_SERVICE, 0, listenerKey, + new ListenerArgs(this, serviceInfo))); + } + + @Override + public void startDaemon() { + mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage( + NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null))); + } + + @Override + public void binderDied() { + mNsdStateMachine.sendMessage( + mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this)); + } } private void notifyEnabled(boolean isEnabled) { @@ -832,43 +890,11 @@ public class NsdService extends INsdManager.Stub { mNsdStateMachine.dump(fd, pw, args); } - /* arg2 on the source message has an id that needs to be retained in replies - * see NsdManager for details */ - private Message obtainMessage(Message srcMsg) { - Message msg = Message.obtain(); - msg.arg2 = srcMsg.arg2; - return msg; - } - - private void replyToMessage(Message msg, int what) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, int arg1) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - dstMsg.arg1 = arg1; - mReplyChannel.replyToMessage(msg, dstMsg); - } - - private void replyToMessage(Message msg, int what, Object obj) { - if (msg.replyTo == null) return; - Message dstMsg = obtainMessage(msg); - dstMsg.what = what; - dstMsg.obj = obj; - mReplyChannel.replyToMessage(msg, dstMsg); - } - /* Information tracked per client */ private class ClientInfo { private static final int MAX_LIMIT = 10; - private final AsyncChannel mChannel; - private final Messenger mMessenger; + private final INsdManagerCallback mCb; /* Remembers a resolved service until getaddrinfo completes */ private NsdServiceInfo mResolvedService; @@ -881,17 +907,14 @@ public class NsdService extends INsdManager.Stub { // The target SDK of this client < Build.VERSION_CODES.S private boolean mIsLegacy = false; - private ClientInfo(AsyncChannel c, Messenger m) { - mChannel = c; - mMessenger = m; - if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); + private ClientInfo(INsdManagerCallback cb) { + mCb = cb; + if (DBG) Slog.d(TAG, "New client"); } @Override public String toString() { StringBuilder sb = new StringBuilder(); - sb.append("mChannel ").append(mChannel).append("\n"); - sb.append("mMessenger ").append(mMessenger).append("\n"); sb.append("mResolvedService ").append(mResolvedService).append("\n"); sb.append("mIsLegacy ").append(mIsLegacy).append("\n"); for(int i = 0; i< mClientIds.size(); i++) { @@ -949,6 +972,102 @@ public class NsdService extends INsdManager.Stub { } return mClientIds.keyAt(idx); } + + void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) { + try { + mCb.onDiscoverServicesStarted(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onDiscoverServicesStarted", e); + } + } + + void onDiscoverServicesFailed(int listenerKey, int error) { + try { + mCb.onDiscoverServicesFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onDiscoverServicesFailed", e); + } + } + + void onServiceFound(int listenerKey, NsdServiceInfo info) { + try { + mCb.onServiceFound(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceFound(", e); + } + } + + void onServiceLost(int listenerKey, NsdServiceInfo info) { + try { + mCb.onServiceLost(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onServiceLost(", e); + } + } + + void onStopDiscoveryFailed(int listenerKey, int error) { + try { + mCb.onStopDiscoveryFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onStopDiscoveryFailed", e); + } + } + + void onStopDiscoverySucceeded(int listenerKey) { + try { + mCb.onStopDiscoverySucceeded(listenerKey); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onStopDiscoverySucceeded", e); + } + } + + void onRegisterServiceFailed(int listenerKey, int error) { + try { + mCb.onRegisterServiceFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onRegisterServiceFailed", e); + } + } + + void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) { + try { + mCb.onRegisterServiceSucceeded(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onRegisterServiceSucceeded", e); + } + } + + void onUnregisterServiceFailed(int listenerKey, int error) { + try { + mCb.onUnregisterServiceFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onUnregisterServiceFailed", e); + } + } + + void onUnregisterServiceSucceeded(int listenerKey) { + try { + mCb.onUnregisterServiceSucceeded(listenerKey); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e); + } + } + + void onResolveServiceFailed(int listenerKey, int error) { + try { + mCb.onResolveServiceFailed(listenerKey, error); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onResolveServiceFailed", e); + } + } + + void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) { + try { + mCb.onResolveServiceSucceeded(listenerKey, info); + } catch (RemoteException e) { + Log.e(TAG, "Error calling onResolveServiceSucceeded", e); + } + } } /** From e6498416d6024bce4048c90deb34f1fd4a5364b4 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Wed, 3 Nov 2021 19:57:54 +0800 Subject: [PATCH 0966/1150] Fix normalize doesn't work on carrier template From android 12, the subscriberId is being used for different network types. For instances: The TYPE_WIFI with subscriberId means that it is a merged wifi network. The TYPE_CARRIER means that the network associate to specific carrier network (subscriberId). So remove the check "isMatchRuleMobile" and only check whether subscriberId is being used in NetworkTemplate or not. Bug: 194939211 Test: atest -c NetworkTemplateTest Change-Id: I80c9f887cf8b4714716d657da92ed273a532ce27 Merged-In: I80c9f887cf8b4714716d657da92ed273a532ce27 --- core/java/android/net/NetworkTemplate.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 249154aa91..762816dd9f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -782,8 +782,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. *

            @@ -798,8 +798,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -811,7 +811,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { From 65168935558ca436967b2aa2b5b2dd801ec6b462 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 2 Nov 2021 00:05:55 -0700 Subject: [PATCH 0967/1150] replace R + 1 with S MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger Bug: 170424293 Signed-off-by: Maciej Żenczykowski Change-Id: Ic28aa1a568bbd0b6d4f06abb7294415afd695fff --- core/java/android/net/IpSecAlgorithm.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java index 7ef5bac092..86052484ea 100644 --- a/core/java/android/net/IpSecAlgorithm.java +++ b/core/java/android/net/IpSecAlgorithm.java @@ -232,11 +232,10 @@ public final class IpSecAlgorithm implements Parcelable { ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_HMAC_SHA512, SDK_VERSION_ZERO); ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_AES_GCM, SDK_VERSION_ZERO); - // STOPSHIP: b/170424293 Use Build.VERSION_CODES.S when it is defined - ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.R + 1); - ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.R + 1); + ALGO_TO_REQUIRED_FIRST_SDK.put(CRYPT_AES_CTR, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_XCBC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_AES_CMAC, Build.VERSION_CODES.S); + ALGO_TO_REQUIRED_FIRST_SDK.put(AUTH_CRYPT_CHACHA20_POLY1305, Build.VERSION_CODES.S); } private static final Set ENABLED_ALGOS = From 0b99c46bcde8e607d9233c474035da95ab68a6fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 14 Apr 2021 06:39:33 -0700 Subject: [PATCH 0968/1150] remove qtaguid parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This removes the legacy (and untested) xt_qtaguid non-ebpf code path (ie. dead code). Test: git grep 'QTAGUID_IFACE_STATS|QTAGUID_UID_STATS|parseIfaceStats|parseUidStats' finds nothing Signed-off-by: Maciej Żenczykowski Change-Id: I922910238474f2cfb74eba19b219bc792ce4abc3 --- ...android_server_net_NetworkStatsService.cpp | 109 +----------------- 1 file changed, 3 insertions(+), 106 deletions(-) diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 10b248a70e..6a355e500d 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -38,9 +38,6 @@ using android::bpf::bpfGetIfaceStats; namespace android { -static const char* QTAGUID_IFACE_STATS = "/proc/net/xt_qtaguid/iface_stat_fmt"; -static const char* QTAGUID_UID_STATS = "/proc/net/xt_qtaguid/stats"; - // NOTE: keep these in sync with TrafficStats.java static const uint64_t UNKNOWN = -1; @@ -72,94 +69,10 @@ static uint64_t getStatsType(Stats* stats, StatsType type) { } } -static int parseIfaceStats(const char* iface, Stats* stats) { - FILE *fp = fopen(QTAGUID_IFACE_STATS, "r"); - if (fp == NULL) { - return -1; - } - - char buffer[384]; - char cur_iface[32]; - bool foundTcp = false; - uint64_t rxBytes, rxPackets, txBytes, txPackets, tcpRxPackets, tcpTxPackets; - - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - int matched = sscanf(buffer, "%31s %" SCNu64 " %" SCNu64 " %" SCNu64 - " %" SCNu64 " " "%*u %" SCNu64 " %*u %*u %*u %*u " - "%*u %" SCNu64 " %*u %*u %*u %*u", cur_iface, &rxBytes, - &rxPackets, &txBytes, &txPackets, &tcpRxPackets, &tcpTxPackets); - if (matched >= 5) { - if (matched == 7) { - foundTcp = true; - } - if (!iface || !strcmp(iface, cur_iface)) { - stats->rxBytes += rxBytes; - stats->rxPackets += rxPackets; - stats->txBytes += txBytes; - stats->txPackets += txPackets; - if (matched == 7) { - stats->tcpRxPackets += tcpRxPackets; - stats->tcpTxPackets += tcpTxPackets; - } - } - } - } - - if (!foundTcp) { - stats->tcpRxPackets = UNKNOWN; - stats->tcpTxPackets = UNKNOWN; - } - - if (fclose(fp) != 0) { - return -1; - } - return 0; -} - -static int parseUidStats(const uint32_t uid, Stats* stats) { - FILE *fp = fopen(QTAGUID_UID_STATS, "r"); - if (fp == NULL) { - return -1; - } - - char buffer[384]; - char iface[32]; - uint32_t idx, cur_uid, set; - uint64_t tag, rxBytes, rxPackets, txBytes, txPackets; - - while (fgets(buffer, sizeof(buffer), fp) != NULL) { - if (sscanf(buffer, - "%" SCNu32 " %31s 0x%" SCNx64 " %u %u %" SCNu64 " %" SCNu64 - " %" SCNu64 " %" SCNu64 "", - &idx, iface, &tag, &cur_uid, &set, &rxBytes, &rxPackets, - &txBytes, &txPackets) == 9) { - if (uid == cur_uid && tag == 0L) { - stats->rxBytes += rxBytes; - stats->rxPackets += rxPackets; - stats->txBytes += txBytes; - stats->txPackets += txPackets; - } - } - } - - if (fclose(fp) != 0) { - return -1; - } - return 0; -} - static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) { Stats stats = {}; - if (useBpfStats) { - if (bpfGetIfaceStats(NULL, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } - } - - if (parseIfaceStats(NULL, &stats) == 0) { + if (bpfGetIfaceStats(NULL, &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { return UNKNOWN; @@ -175,15 +88,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, Stats stats = {}; - if (useBpfStats) { - if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } - } - - if (parseIfaceStats(iface8.c_str(), &stats) == 0) { + if (bpfGetIfaceStats(iface8.c_str(), &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { return UNKNOWN; @@ -193,15 +98,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) { Stats stats = {}; - if (useBpfStats) { - if (bpfGetUidStats(uid, &stats) == 0) { - return getStatsType(&stats, (StatsType) type); - } else { - return UNKNOWN; - } - } - - if (parseUidStats(uid, &stats) == 0) { + if (bpfGetUidStats(uid, &stats) == 0) { return getStatsType(&stats, (StatsType) type); } else { return UNKNOWN; From 6976b5996ed4dc0477b5c7dc712a7f83417a0224 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 14 Apr 2021 07:34:00 -0700 Subject: [PATCH 0969/1150] bpf is required - remove checkBpfStatsEnable() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: git grep 'nativeGetTotalStat|nativeGetIfaceStat|nativeGetUidStat' - shows all locations have been updated git grep 'checkBpfStatsEnable' - find nothings relevant (just services/art-profile) Signed-off-by: Maciej Żenczykowski Change-Id: Ib584ea57c39d5ab0605787b05133097fd2c82a39 --- .../android/server/net/NetworkStatsService.java | 16 ++++++---------- ...om_android_server_net_NetworkStatsService.cpp | 13 ++++++------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 097b0711ef..e7b768df99 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1084,13 +1084,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (callingUid != android.os.Process.SYSTEM_UID && callingUid != uid) { return UNSUPPORTED; } - return nativeGetUidStat(uid, type, checkBpfStatsEnable()); + return nativeGetUidStat(uid, type); } @Override public long getIfaceStats(@NonNull String iface, int type) { Objects.requireNonNull(iface); - long nativeIfaceStats = nativeGetIfaceStat(iface, type, checkBpfStatsEnable()); + long nativeIfaceStats = nativeGetIfaceStat(iface, type); if (nativeIfaceStats == -1) { return nativeIfaceStats; } else { @@ -1104,7 +1104,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public long getTotalStats(int type) { - long nativeTotalStats = nativeGetTotalStat(type, checkBpfStatsEnable()); + long nativeTotalStats = nativeGetTotalStat(type); if (nativeTotalStats == -1) { return nativeTotalStats; } else { @@ -1137,10 +1137,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private boolean checkBpfStatsEnable() { - return mUseBpfTrafficStats; - } - /** * Update {@link NetworkStatsRecorder} and {@link #mGlobalAlertBytes} to * reflect current {@link #mPersistThreshold} value. Always defers to @@ -2249,7 +2245,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private static native long nativeGetTotalStat(int type, boolean useBpfStats); - private static native long nativeGetIfaceStat(String iface, int type, boolean useBpfStats); - private static native long nativeGetUidStat(int uid, int type, boolean useBpfStats); + private static native long nativeGetTotalStat(int type); + private static native long nativeGetIfaceStat(String iface, int type); + private static native long nativeGetUidStat(int uid, int type); } diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 6a355e500d..5178132e4a 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -69,7 +69,7 @@ static uint64_t getStatsType(Stats* stats, StatsType type) { } } -static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfStats) { +static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type) { Stats stats = {}; if (bpfGetIfaceStats(NULL, &stats) == 0) { @@ -79,8 +79,7 @@ static jlong getTotalStat(JNIEnv* env, jclass clazz, jint type, jboolean useBpfS } } -static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, - jboolean useBpfStats) { +static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type) { ScopedUtfChars iface8(env, iface); if (iface8.c_str() == NULL) { return UNKNOWN; @@ -95,7 +94,7 @@ static jlong getIfaceStat(JNIEnv* env, jclass clazz, jstring iface, jint type, } } -static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean useBpfStats) { +static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { Stats stats = {}; if (bpfGetUidStats(uid, &stats) == 0) { @@ -106,9 +105,9 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type, jboolean } static const JNINativeMethod gMethods[] = { - {"nativeGetTotalStat", "(IZ)J", (void*) getTotalStat}, - {"nativeGetIfaceStat", "(Ljava/lang/String;IZ)J", (void*) getIfaceStat}, - {"nativeGetUidStat", "(IIZ)J", (void*) getUidStat}, + {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, + {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, + {"nativeGetUidStat", "(II)J", (void*)getUidStat}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { From a2343dcbcc539248a250295fdb126940bdadc67d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 14 Apr 2021 08:14:25 -0700 Subject: [PATCH 0970/1150] bpf is required - remove mUseBpfTrafficStats field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: git grep mUseBpfTrafficStats TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I0be3b802e2ebd175b2a58061bf821aba02a8ec8a --- .../core/java/com/android/server/net/NetworkStatsService.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index e7b768df99..f4b72a15d0 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -215,8 +215,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final PowerManager.WakeLock mWakeLock; - private final boolean mUseBpfTrafficStats; - private final ContentObserver mContentObserver; private final ContentResolver mContentResolver; @@ -438,7 +436,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mStatsObservers = Objects.requireNonNull(statsObservers, "missing NetworkStatsObservers"); mSystemDir = Objects.requireNonNull(systemDir, "missing systemDir"); mBaseDir = Objects.requireNonNull(baseDir, "missing baseDir"); - mUseBpfTrafficStats = new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists(); mDeps = Objects.requireNonNull(deps, "missing Dependencies"); final HandlerThread handlerThread = mDeps.makeHandlerThread(); From 79237fad47eaec43905ca083fa2e78f56d3fde2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 14 Apr 2021 08:22:05 -0700 Subject: [PATCH 0971/1150] bpf is required so /sys/fs/bpf/map_netd_app_uid_stats_map always exists MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (we cannot just remove the argument, since the test code path still goes via the legacy xt_qtaguid code paths with sample data) Test: TreeHugger Signed-off-by: Maciej Żenczykowski Change-Id: I044d0363aaab0dbbb90c40ca466cc48f169d649a --- .../core/java/com/android/server/net/NetworkStatsFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 431b00914f..e6433db11d 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -159,7 +159,7 @@ public class NetworkStatsFactory { } public NetworkStatsFactory() { - this(new File("/proc/"), new File("/sys/fs/bpf/map_netd_app_uid_stats_map").exists()); + this(new File("/proc/"), true); } @VisibleForTesting From e46f8703e3f5a9c5b69096ae81cdde0f7130ff89 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Wed, 3 Nov 2021 19:57:54 +0800 Subject: [PATCH 0972/1150] Fix normalize doesn't work on carrier template From android 12, the subscriberId is being used for different network types. For instances: The TYPE_WIFI with subscriberId means that it is a merged wifi network. The TYPE_CARRIER means that the network associate to specific carrier network (subscriberId). So remove the check "isMatchRuleMobile" and only check whether subscriberId is being used in NetworkTemplate or not. Bug: 194939211 Test: atest -c NetworkTemplateTest Change-Id: I80c9f887cf8b4714716d657da92ed273a532ce27 Merged-In: I80c9f887cf8b4714716d657da92ed273a532ce27 (cherry picked from commit e6498416d6024bce4048c90deb34f1fd4a5364b4) Merged-In:I80c9f887cf8b4714716d657da92ed273a532ce27 --- core/java/android/net/NetworkTemplate.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index 249154aa91..762816dd9f 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -782,8 +782,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. *

            @@ -798,8 +798,8 @@ public class NetworkTemplate implements Parcelable { } /** - * Examine the given template and normalize if it refers to a "merged" - * mobile subscriber. We pick the "lowest" merged subscriber as the primary + * Examine the given template and normalize it. + * We pick the "lowest" merged subscriber as the primary * for key purposes, and expand the template to match all other merged * subscribers. * @@ -811,7 +811,12 @@ public class NetworkTemplate implements Parcelable { * A, but also matches B. */ public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { - if (!template.isMatchRuleMobile()) return template; + // Now there are several types of network which uses SubscriberId to store network + // information. For instances: + // The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network. + // The TYPE_CARRIER means that the network associate to specific carrier network. + + if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { if (ArrayUtils.contains(merged, template.mSubscriberId)) { From 575e81496c9507127a0b2b9a7363f14fb1e8cc9f Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 19 Nov 2021 07:08:10 +0000 Subject: [PATCH 0973/1150] Clear calling identity when notifying alert/limit reached When the NetworkStatsProvider reports alert/limit reached, NetworkStatsService will relay the event to other services such as NPMS or NMS. The identity should be cleared before calling into other services. Test: TH Bug: 181106917 Change-Id: I2a7b273dc30156a84b30566319894ec3a42d4429 --- .../com/android/server/net/NetworkStatsService.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 097b0711ef..f3bbe7c818 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -150,6 +150,7 @@ import com.android.internal.util.ArrayUtils; import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.BinderUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -2104,14 +2105,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void notifyAlertReached() throws RemoteException { - mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */); + // This binder object can only have been obtained by a process that holds + // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required. + BinderUtils.withCleanCallingIdentity(() -> + mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); } @Override public void notifyWarningOrLimitReached() { Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); - LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderWarningOrLimitReached(mTag); + BinderUtils.withCleanCallingIdentity(() -> + LocalServices.getService(NetworkPolicyManagerInternal.class) + .onStatsProviderWarningOrLimitReached(mTag)); } @Override From 4d7813dacc7b68c77361426a74a11c015fdb10bc Mon Sep 17 00:00:00 2001 From: gary-wzl77 Date: Wed, 13 Oct 2021 20:53:00 +0800 Subject: [PATCH 0974/1150] net: fix NPE when reading IP configurations When the default gateway is not used in IP configurations, for example the gateway info in ip configurations was fed with custom gateway address ``` out.writeUTF(GATEWAY_KEY); out.writeInt(0); // Default route. out.writeInt(1); // Have a gateway. out.writeUTF(staticIpConfiguration.getGateway().getHostAddress()); ``` A NPE occurred. When there is no destination, assume it is default route and use the gateway address in all cases. Test: manual Change-Id: I5904efad5d277de6724f81d99e62c21ff8347caa Signed-off-by: gary-wzl77 --- .../core/java/com/android/server/net/IpConfigStore.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java index df1eb6d9fe..d17dbde496 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/services/core/java/com/android/server/net/IpConfigStore.java @@ -322,8 +322,11 @@ public class IpConfigStore { gateway = InetAddresses.parseNumericAddress(in.readUTF()); } // If the destination is a default IPv4 route, use the gateway - // address unless already set. - if (dest.getAddress() instanceof Inet4Address + // address unless already set. If there is no destination, assume + // it is default route and use the gateway address in all cases. + if (dest == null) { + gatewayAddress = gateway; + } else if (dest.getAddress() instanceof Inet4Address && dest.getPrefixLength() == 0 && gatewayAddress == null) { gatewayAddress = gateway; } else { From d622cde7ee31d5d8f0f3ab4607160932a487f807 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 15 Nov 2021 09:20:37 +0000 Subject: [PATCH 0975/1150] [MS06] Add carrier template fields into cloud backup/restore NetworkTemplate with MATCH_CARRIER can be created in NPMS, and can be backup by SettingsBackupAgent. However, since the meteredness is not stored in the backup. After incorrectly deducing from match rule, meteredness always becomes METERED_ALL after restoring from backup. This change also adds debug log if any non-persistable template is being backed up. Test: TH, dedicated test is included in the follow-up CL. Bug: 204830222 Change-Id: I865b1d6e571ed998a75b776f01afc7c2534af2dc --- core/java/android/net/NetworkTemplate.java | 48 ++++++++++++++++++---- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java index ee24084e63..c906a13bf4 100644 --- a/core/java/android/net/NetworkTemplate.java +++ b/core/java/android/net/NetworkTemplate.java @@ -69,10 +69,18 @@ import java.util.Objects; public class NetworkTemplate implements Parcelable { private static final String TAG = "NetworkTemplate"; + /** + * Initial Version of the backup serializer. + */ + public static final int BACKUP_VERSION_1_INIT = 1; + /** + * Version of the backup serializer that added carrier template support. + */ + public static final int BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2; /** * Current Version of the Backup Serializer. */ - private static final int BACKUP_VERSION = 1; + private static final int BACKUP_VERSION = BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE; public static final int MATCH_MOBILE = 1; public static final int MATCH_WIFI = 4; @@ -285,6 +293,10 @@ public class NetworkTemplate implements Parcelable { private final int mRoaming; private final int mDefaultNetwork; private final int mSubType; + /** + * The subscriber Id match rule defines how the template should match networks with + * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail. + */ private final int mSubscriberIdMatchRule; // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. @@ -348,7 +360,7 @@ public class NetworkTemplate implements Parcelable { mSubscriberIdMatchRule = subscriberIdMatchRule; checkValidSubscriberIdMatchRule(); if (!isKnownMatchRule(matchRule)) { - Log.e(TAG, "Unknown network template rule " + matchRule + throw new IllegalArgumentException("Unknown network template rule " + matchRule + " will not match any identity."); } } @@ -842,11 +854,17 @@ public class NetworkTemplate implements Parcelable { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(baos); + if (!isPersistable()) { + Log.wtf(TAG, "Trying to backup non-persistable template: " + this); + } + out.writeInt(BACKUP_VERSION); out.writeInt(mMatchRule); BackupUtils.writeString(out, mSubscriberId); BackupUtils.writeString(out, mNetworkId); + out.writeInt(mMetered); + out.writeInt(mSubscriberIdMatchRule); return baos.toByteArray(); } @@ -854,7 +872,7 @@ public class NetworkTemplate implements Parcelable { public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in) throws IOException, BackupUtils.BadVersionException { int version = in.readInt(); - if (version < 1 || version > BACKUP_VERSION) { + if (version < BACKUP_VERSION_1_INIT || version > BACKUP_VERSION) { throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); } @@ -862,11 +880,27 @@ public class NetworkTemplate implements Parcelable { String subscriberId = BackupUtils.readString(in); String networkId = BackupUtils.readString(in); - if (!isKnownMatchRule(matchRule)) { - throw new BackupUtils.BadVersionException( - "Restored network template contains unknown match rule " + matchRule); + final int metered; + final int subscriberIdMatchRule; + if (version >= BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) { + metered = in.readInt(); + subscriberIdMatchRule = in.readInt(); + } else { + // For backward compatibility, fill the missing filters from match rules. + metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD + || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL; + subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT; } - return new NetworkTemplate(matchRule, subscriberId, networkId); + try { + return new NetworkTemplate(matchRule, + subscriberId, new String[] { subscriberId }, + networkId, metered, NetworkStats.ROAMING_ALL, + NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL, + NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule); + } catch (IllegalArgumentException e) { + throw new BackupUtils.BadVersionException( + "Restored network template contains unknown match rule " + matchRule, e); + } } } From 9dbe49f9545f7df550d53dc9b5cb8ad2f0ffb44f Mon Sep 17 00:00:00 2001 From: paulhu Date: Thu, 18 Nov 2021 15:29:03 +0800 Subject: [PATCH 0976/1150] Centralize nsd associated files Move all nsd associated files include framework, service and test to package/Nsd first. After clear all hidden API dependencies, we can easily migrate these files into connectivity mainline module. Bug: 206893064 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Id26f471a10fe7882e31ccc2dbb73219461f00dbd --- packages/Nsd/OWNERS | 1 + packages/Nsd/framework/Android.bp | 54 +++++++++++++++++++ .../android/net/nsd/NsdServiceInfo.aidl | 0 .../src}/android/net/nsd/INsdManager.aidl | 0 .../android/net/nsd/INsdManagerCallback.aidl | 0 .../android/net/nsd/INsdServiceConnector.aidl | 0 .../src}/android/net/nsd/NsdManager.java | 0 .../src}/android/net/nsd/NsdServiceInfo.java | 0 packages/Nsd/service/Android.bp | 31 +++++++++++ .../INativeDaemonConnectorCallbacks.java | 0 .../android/server/NativeDaemonConnector.java | 0 .../NativeDaemonConnectorException.java | 0 .../com/android/server/NativeDaemonEvent.java | 0 .../server/NativeDaemonTimeoutException.java | 0 .../src}/com/android/server/NsdService.java | 0 .../server/NativeDaemonConnectorTest.java | 0 16 files changed, 86 insertions(+) create mode 100644 packages/Nsd/OWNERS create mode 100644 packages/Nsd/framework/Android.bp rename {core/java => packages/Nsd/framework/aidl-export}/android/net/nsd/NsdServiceInfo.aidl (100%) rename {core/java => packages/Nsd/framework/src}/android/net/nsd/INsdManager.aidl (100%) rename {core/java => packages/Nsd/framework/src}/android/net/nsd/INsdManagerCallback.aidl (100%) rename {core/java => packages/Nsd/framework/src}/android/net/nsd/INsdServiceConnector.aidl (100%) rename {core/java => packages/Nsd/framework/src}/android/net/nsd/NsdManager.java (100%) rename {core/java => packages/Nsd/framework/src}/android/net/nsd/NsdServiceInfo.java (100%) create mode 100644 packages/Nsd/service/Android.bp rename {services/core/java => packages/Nsd/service/src}/com/android/server/INativeDaemonConnectorCallbacks.java (100%) rename {services/core/java => packages/Nsd/service/src}/com/android/server/NativeDaemonConnector.java (100%) rename {services/core/java => packages/Nsd/service/src}/com/android/server/NativeDaemonConnectorException.java (100%) rename {services/core/java => packages/Nsd/service/src}/com/android/server/NativeDaemonEvent.java (100%) rename {services/core/java => packages/Nsd/service/src}/com/android/server/NativeDaemonTimeoutException.java (100%) rename {services/core/java => packages/Nsd/service/src}/com/android/server/NsdService.java (100%) rename {services/tests/servicestests/src => packages/Nsd/tests/unit/java}/com/android/server/NativeDaemonConnectorTest.java (100%) diff --git a/packages/Nsd/OWNERS b/packages/Nsd/OWNERS new file mode 100644 index 0000000000..4862377852 --- /dev/null +++ b/packages/Nsd/OWNERS @@ -0,0 +1 @@ +file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking \ No newline at end of file diff --git a/packages/Nsd/framework/Android.bp b/packages/Nsd/framework/Android.bp new file mode 100644 index 0000000000..2363a9f8d4 --- /dev/null +++ b/packages/Nsd/framework/Android.bp @@ -0,0 +1,54 @@ +// +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["Android-Apache-2.0"], +} + +filegroup { + name: "framework-connectivity-nsd-internal-sources", + srcs: [ + "src/**/*.java", + "src/**/*.aidl", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + +filegroup { + name: "framework-connectivity-nsd-aidl-export-sources", + srcs: [ + "aidl-export/**/*.aidl", + ], + path: "aidl-export", + visibility: [ + "//visibility:private", + ], +} + +filegroup { + name: "framework-connectivity-nsd-sources", + srcs: [ + ":framework-connectivity-nsd-internal-sources", + ":framework-connectivity-nsd-aidl-export-sources", + ], + visibility: [ + "//frameworks/base", + ], +} diff --git a/core/java/android/net/nsd/NsdServiceInfo.aidl b/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl similarity index 100% rename from core/java/android/net/nsd/NsdServiceInfo.aidl rename to packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl diff --git a/core/java/android/net/nsd/INsdManager.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl similarity index 100% rename from core/java/android/net/nsd/INsdManager.aidl rename to packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl diff --git a/core/java/android/net/nsd/INsdManagerCallback.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl similarity index 100% rename from core/java/android/net/nsd/INsdManagerCallback.aidl rename to packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl diff --git a/core/java/android/net/nsd/INsdServiceConnector.aidl b/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl similarity index 100% rename from core/java/android/net/nsd/INsdServiceConnector.aidl rename to packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl diff --git a/core/java/android/net/nsd/NsdManager.java b/packages/Nsd/framework/src/android/net/nsd/NsdManager.java similarity index 100% rename from core/java/android/net/nsd/NsdManager.java rename to packages/Nsd/framework/src/android/net/nsd/NsdManager.java diff --git a/core/java/android/net/nsd/NsdServiceInfo.java b/packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java similarity index 100% rename from core/java/android/net/nsd/NsdServiceInfo.java rename to packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java diff --git a/packages/Nsd/service/Android.bp b/packages/Nsd/service/Android.bp new file mode 100644 index 0000000000..529f58d130 --- /dev/null +++ b/packages/Nsd/service/Android.bp @@ -0,0 +1,31 @@ +// +// Copyright (C) 2021 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + // See: http://go/android-license-faq + default_applicable_licenses: ["Android-Apache-2.0"], +} + +filegroup { + name: "services.connectivity-nsd-sources", + srcs: [ + "src/**/*.java", + ], + path: "src", + visibility: [ + "//frameworks/base/services/core", + ], +} diff --git a/services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java b/packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java similarity index 100% rename from services/core/java/com/android/server/INativeDaemonConnectorCallbacks.java rename to packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java similarity index 100% rename from services/core/java/com/android/server/NativeDaemonConnector.java rename to packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java diff --git a/services/core/java/com/android/server/NativeDaemonConnectorException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java similarity index 100% rename from services/core/java/com/android/server/NativeDaemonConnectorException.java rename to packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java diff --git a/services/core/java/com/android/server/NativeDaemonEvent.java b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java similarity index 100% rename from services/core/java/com/android/server/NativeDaemonEvent.java rename to packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java diff --git a/services/core/java/com/android/server/NativeDaemonTimeoutException.java b/packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java similarity index 100% rename from services/core/java/com/android/server/NativeDaemonTimeoutException.java rename to packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java diff --git a/services/core/java/com/android/server/NsdService.java b/packages/Nsd/service/src/com/android/server/NsdService.java similarity index 100% rename from services/core/java/com/android/server/NsdService.java rename to packages/Nsd/service/src/com/android/server/NsdService.java diff --git a/services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java b/packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java similarity index 100% rename from services/tests/servicestests/src/com/android/server/NativeDaemonConnectorTest.java rename to packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java From c047d9a273fdcc75a16d2f9ba1332d5fe3b26711 Mon Sep 17 00:00:00 2001 From: paulhu Date: Wed, 17 Nov 2021 09:35:33 +0800 Subject: [PATCH 0977/1150] Replace @hide APIs NSD associated files are going to move into connectivity mainline module in T, so need convert all hidden APIs to formal API surfaces. - Replace Slog with Log - Remove useless implements Watchdog.Monitor - Replace Build.IS_DEBUGGABLE with Build.isDebuggable() - Replace Preconditions.checkState90 by checking null directly. - Replace Lists.newArrayList() by new ArrayList<>() - Replace DumpUtils.checkDumpPermission() by checking DUMP permission directly. Bug: 206702844 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: I6bc478b852c10591959d9e0615af63e675532abe --- .../android/server/NativeDaemonConnector.java | 43 ++++++------- .../com/android/server/NativeDaemonEvent.java | 15 +++-- .../src/com/android/server/NsdService.java | 60 ++++++++++--------- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java index eac767f735..02475dd1ea 100644 --- a/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java +++ b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java @@ -26,12 +26,10 @@ import android.os.PowerManager; import android.os.SystemClock; import android.os.SystemProperties; import android.util.LocalLog; -import android.util.Slog; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import com.android.server.power.ShutdownThread; -import com.google.android.collect.Lists; import java.io.FileDescriptor; import java.io.IOException; @@ -40,19 +38,19 @@ import java.io.OutputStream; import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.LinkedList; +import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; -import java.util.LinkedList; -import java.util.Objects; +import java.util.concurrent.atomic.AtomicInteger; /** * Generic connector class for interfacing with a native daemon which uses the * {@code libsysutils} FrameworkListener protocol. */ -final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdog.Monitor { +final class NativeDaemonConnector implements Runnable, Handler.Callback { private final static boolean VDBG = false; private final String TAG; @@ -107,7 +105,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo /** * Enable Set debugging mode, which causes messages to also be written to both - * {@link Slog} in addition to internal log. + * {@link Log} in addition to internal log. */ public void setDebug(boolean debug) { mDebug = debug; @@ -126,7 +124,9 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo * calls while holding a lock on the given object. */ public void setWarnIfHeld(Object warnIfHeld) { - Preconditions.checkState(mWarnIfHeld == null); + if (mWarnIfHeld != null) { + throw new IllegalStateException("warnIfHeld is already set."); + } mWarnIfHeld = Objects.requireNonNull(warnIfHeld); } @@ -183,7 +183,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo // In order to ensure that unprivileged apps aren't able to impersonate native daemons on // production devices, even if said native daemons ill-advisedly pick a socket name that // starts with __test__, only allow this on debug builds. - if (mSocket.startsWith("__test__") && Build.IS_DEBUGGABLE) { + if (mSocket.startsWith("__test__") && Build.isDebuggable()) { return new LocalSocketAddress(mSocket); } else { return new LocalSocketAddress(mSocket, LocalSocketAddress.Namespace.RESERVED); @@ -375,7 +375,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo try { latch.await(); } catch (InterruptedException e) { - Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); + Log.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e); } } @@ -462,13 +462,13 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo public NativeDaemonEvent[] executeForList(long timeoutMs, String cmd, Object... args) throws NativeDaemonConnectorException { if (mWarnIfHeld != null && Thread.holdsLock(mWarnIfHeld)) { - Slog.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" + Log.wtf(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding 0x" + Integer.toHexString(System.identityHashCode(mWarnIfHeld)), new Throwable()); } final long startTime = SystemClock.elapsedRealtime(); - final ArrayList events = Lists.newArrayList(); + final ArrayList events = new ArrayList<>(); final StringBuilder rawBuilder = new StringBuilder(); final StringBuilder logBuilder = new StringBuilder(); @@ -571,7 +571,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo */ public static class Command { private String mCmd; - private ArrayList mArguments = Lists.newArrayList(); + private ArrayList mArguments = new ArrayList<>(); public Command(String cmd, Object... args) { mCmd = cmd; @@ -586,11 +586,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } } - /** {@inheritDoc} */ - public void monitor() { - synchronized (mDaemonLock) { } - } - public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { mLocalLog.dump(fd, pw, args); pw.println(); @@ -598,12 +593,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo } private void log(String logstring) { - if (mDebug) Slog.d(TAG, logstring); + if (mDebug) Log.d(TAG, logstring); mLocalLog.log(logstring); } private void loge(String logstring) { - Slog.e(TAG, logstring); + Log.e(TAG, logstring); mLocalLog.log(logstring); } @@ -659,12 +654,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo if (found == null) { // didn't find it - make sure our queue isn't too big before adding while (mPendingCmds.size() >= mMaxCount) { - Slog.e("NativeDaemonConnector.ResponseQueue", + Log.e("NativeDaemonConnector.ResponseQueue", "more buffered than allowed: " + mPendingCmds.size() + " >= " + mMaxCount); // let any waiter timeout waiting for this PendingCmd pendingCmd = mPendingCmds.remove(); - Slog.e("NativeDaemonConnector.ResponseQueue", + Log.e("NativeDaemonConnector.ResponseQueue", "Removing request: " + pendingCmd.logCmd + " (" + pendingCmd.cmdNum + ")"); } @@ -706,7 +701,7 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback, Watchdo result = found.responses.poll(timeoutMs, TimeUnit.MILLISECONDS); } catch (InterruptedException e) {} if (result == null) { - Slog.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); + Log.e("NativeDaemonConnector.ResponseQueue", "Timeout waiting for response"); } return result; } diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java index e6feda3dad..5683694346 100644 --- a/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java +++ b/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java @@ -16,8 +16,7 @@ package com.android.server; -import android.util.Slog; -import com.google.android.collect.Lists; +import android.util.Log; import java.io.FileDescriptor; import java.util.ArrayList; @@ -179,7 +178,7 @@ public class NativeDaemonEvent { * {@link #getMessage()} for any events matching the requested code. */ public static String[] filterMessageList(NativeDaemonEvent[] events, int matchCode) { - final ArrayList result = Lists.newArrayList(); + final ArrayList result = new ArrayList<>(); for (NativeDaemonEvent event : events) { if (event.getCode() == matchCode) { result.add(event.getMessage()); @@ -212,7 +211,7 @@ public class NativeDaemonEvent { int wordEnd = -1; boolean quoted = false; - if (DEBUG_ROUTINE) Slog.e(LOGTAG, "parsing '" + rawEvent + "'"); + if (DEBUG_ROUTINE) Log.e(LOGTAG, "parsing '" + rawEvent + "'"); if (rawEvent.charAt(current) == '\"') { quoted = true; current++; @@ -240,14 +239,14 @@ public class NativeDaemonEvent { word = word.replace("\\\\", "\\"); word = word.replace("\\\"", "\""); - if (DEBUG_ROUTINE) Slog.e(LOGTAG, "found '" + word + "'"); + if (DEBUG_ROUTINE) Log.e(LOGTAG, "found '" + word + "'"); parsed.add(word); // find the beginning of the next word - either of these options int nextSpace = rawEvent.indexOf(' ', current); int nextQuote = rawEvent.indexOf(" \"", current); if (DEBUG_ROUTINE) { - Slog.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote); + Log.e(LOGTAG, "nextSpace=" + nextSpace + ", nextQuote=" + nextQuote); } if (nextQuote > -1 && nextQuote <= nextSpace) { quoted = true; @@ -259,8 +258,8 @@ public class NativeDaemonEvent { } } // else we just start the next word after the current and read til the end if (DEBUG_ROUTINE) { - Slog.e(LOGTAG, "next loop - current=" + current + - ", length=" + length + ", quoted=" + quoted); + Log.e(LOGTAG, "next loop - current=" + current + + ", length=" + length + ", quoted=" + quoted); } } return parsed.toArray(new String[parsed.size()]); diff --git a/packages/Nsd/service/src/com/android/server/NsdService.java b/packages/Nsd/service/src/com/android/server/NsdService.java index 3e0208411c..76ecea726b 100644 --- a/packages/Nsd/service/src/com/android/server/NsdService.java +++ b/packages/Nsd/service/src/com/android/server/NsdService.java @@ -19,6 +19,7 @@ package com.android.server; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.Uri; import android.net.nsd.INsdManager; @@ -36,12 +37,10 @@ import android.provider.Settings; import android.util.Base64; import android.util.Log; import android.util.Pair; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.DumpUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; import com.android.net.module.util.DnsSdTxtRecord; @@ -228,7 +227,7 @@ public class NsdService extends INsdManager.Stub { break; case NsdManager.NATIVE_DAEMON_EVENT: default: - Slog.e(TAG, "Unhandled " + msg); + Log.e(TAG, "Unhandled " + msg); return NOT_HANDLED; } return HANDLED; @@ -274,7 +273,7 @@ public class NsdService extends INsdManager.Stub { private boolean requestLimitReached(ClientInfo clientInfo) { if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) { - if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo); + if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo); return true; } return false; @@ -307,7 +306,7 @@ public class NsdService extends INsdManager.Stub { transitionTo(mDisabledState); break; case NsdManager.DISCOVER_SERVICES: - if (DBG) Slog.d(TAG, "Discover services"); + if (DBG) Log.d(TAG, "Discover services"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -321,8 +320,8 @@ public class NsdService extends INsdManager.Stub { id = getUniqueId(); if (discoverServices(id, args.serviceInfo.getServiceType())) { if (DBG) { - Slog.d(TAG, "Discover " + msg.arg2 + " " + id + - args.serviceInfo.getServiceType()); + Log.d(TAG, "Discover " + msg.arg2 + " " + id + + args.serviceInfo.getServiceType()); } storeRequestMap(clientId, id, clientInfo, msg.what); clientInfo.onDiscoverServicesStarted(clientId, args.serviceInfo); @@ -333,7 +332,7 @@ public class NsdService extends INsdManager.Stub { } break; case NsdManager.STOP_DISCOVERY: - if (DBG) Slog.d(TAG, "Stop service discovery"); + if (DBG) Log.d(TAG, "Stop service discovery"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -353,7 +352,7 @@ public class NsdService extends INsdManager.Stub { } break; case NsdManager.REGISTER_SERVICE: - if (DBG) Slog.d(TAG, "Register service"); + if (DBG) Log.d(TAG, "Register service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); if (requestLimitReached(clientInfo)) { @@ -365,7 +364,7 @@ public class NsdService extends INsdManager.Stub { maybeStartDaemon(); id = getUniqueId(); if (registerService(id, args.serviceInfo)) { - if (DBG) Slog.d(TAG, "Register " + clientId + " " + id); + if (DBG) Log.d(TAG, "Register " + clientId + " " + id); storeRequestMap(clientId, id, clientInfo, msg.what); // Return success after mDns reports success } else { @@ -375,11 +374,11 @@ public class NsdService extends INsdManager.Stub { } break; case NsdManager.UNREGISTER_SERVICE: - if (DBG) Slog.d(TAG, "unregister service"); + if (DBG) Log.d(TAG, "unregister service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); if (clientInfo == null) { - Slog.e(TAG, "Unknown connector in unregistration"); + Log.e(TAG, "Unknown connector in unregistration"); break; } id = clientInfo.mClientIds.get(clientId); @@ -392,7 +391,7 @@ public class NsdService extends INsdManager.Stub { } break; case NsdManager.RESOLVE_SERVICE: - if (DBG) Slog.d(TAG, "Resolve service"); + if (DBG) Log.d(TAG, "Resolve service"); args = (ListenerArgs) msg.obj; clientInfo = mClients.get(args.connector); @@ -430,7 +429,7 @@ public class NsdService extends INsdManager.Stub { ClientInfo clientInfo = mIdToClientInfoMap.get(id); if (clientInfo == null) { String name = NativeResponseCode.nameOf(code); - Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name)); + Log.e(TAG, String.format("id %d for %s has no client mapping", id, name)); return false; } @@ -441,14 +440,14 @@ public class NsdService extends INsdManager.Stub { // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY, // and we may get in this situation. String name = NativeResponseCode.nameOf(code); - Slog.d(TAG, String.format( + Log.d(TAG, String.format( "Notification %s for listener id %d that is no longer active", name, id)); return false; } if (DBG) { String name = NativeResponseCode.nameOf(code); - Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw)); + Log.d(TAG, String.format("Native daemon message %s: %s", name, raw)); } switch (code) { case NativeResponseCode.SERVICE_FOUND: @@ -492,7 +491,7 @@ public class NsdService extends INsdManager.Stub { ++index; } if (index >= cooked[2].length()) { - Slog.e(TAG, "Invalid service found " + raw); + Log.e(TAG, "Invalid service found " + raw); break; } String name = cooked[2].substring(0, index); @@ -562,13 +561,13 @@ public class NsdService extends INsdManager.Stub { char c = s.charAt(i); if (c == '\\') { if (++i >= s.length()) { - Slog.e(TAG, "Unexpected end of escape sequence in: " + s); + Log.e(TAG, "Unexpected end of escape sequence in: " + s); break; } c = s.charAt(i); if (c != '.' && c != '\\') { if (i + 2 >= s.length()) { - Slog.e(TAG, "Unexpected end of escape sequence in: " + s); + Log.e(TAG, "Unexpected end of escape sequence in: " + s); break; } c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0')); @@ -685,7 +684,7 @@ public class NsdService extends INsdManager.Stub { private boolean isNsdEnabled() { boolean ret = mNsdSettings.isEnabled(); if (DBG) { - Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled")); + Log.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled")); } return ret; } @@ -795,12 +794,12 @@ public class NsdService extends INsdManager.Stub { */ public boolean execute(Object... args) { if (DBG) { - Slog.d(TAG, "mdnssd " + Arrays.toString(args)); + Log.d(TAG, "mdnssd " + Arrays.toString(args)); } try { mNativeConnector.execute("mdnssd", args); } catch (NativeDaemonConnectorException e) { - Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e); + Log.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e); return false; } return true; @@ -831,7 +830,7 @@ public class NsdService extends INsdManager.Stub { private boolean registerService(int regId, NsdServiceInfo service) { if (DBG) { - Slog.d(TAG, "registerService: " + regId + " " + service); + Log.d(TAG, "registerService: " + regId + " " + service); } String name = service.getServiceName(); String type = service.getServiceType(); @@ -880,7 +879,12 @@ public class NsdService extends INsdManager.Stub { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; + if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) + != PackageManager.PERMISSION_GRANTED) { + pw.println("Permission Denial: can't dump " + TAG + + " due to missing android.permission.DUMP permission"); + return; + } for (ClientInfo client : mClients.values()) { pw.println("Client Info"); @@ -909,7 +913,7 @@ public class NsdService extends INsdManager.Stub { private ClientInfo(INsdManagerCallback cb) { mCb = cb; - if (DBG) Slog.d(TAG, "New client"); + if (DBG) Log.d(TAG, "New client"); } @Override @@ -943,8 +947,10 @@ public class NsdService extends INsdManager.Stub { clientId = mClientIds.keyAt(i); globalId = mClientIds.valueAt(i); mIdToClientInfoMap.remove(globalId); - if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId + - " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + if (DBG) { + Log.d(TAG, "Terminating client-ID " + clientId + + " global-ID " + globalId + " type " + mClientRequests.get(clientId)); + } switch (mClientRequests.get(clientId)) { case NsdManager.DISCOVER_SERVICES: stopServiceDiscovery(globalId); From 3279219a5a0e46462b8b5dcfdee269586b2a0ca3 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 30 Nov 2021 13:31:29 +0800 Subject: [PATCH 0978/1150] Stop using NSD_ON setting NSD_ON setting has never been set since it created. Besides, CTS tests assume that nsd service is always enabled otherwise the tests will fail. Thus, remove the setting from NsdService which is no need to read/write it and it's also a hidden symbols. Bug: 206702844 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Id3cef7def96925cec5095e12910e9b97ba7efb11 --- .../src/com/android/server/NsdService.java | 75 +------------------ 1 file changed, 4 insertions(+), 71 deletions(-) diff --git a/packages/Nsd/service/src/com/android/server/NsdService.java b/packages/Nsd/service/src/com/android/server/NsdService.java index 76ecea726b..497107dbf9 100644 --- a/packages/Nsd/service/src/com/android/server/NsdService.java +++ b/packages/Nsd/service/src/com/android/server/NsdService.java @@ -16,12 +16,9 @@ package com.android.server; -import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; -import android.database.ContentObserver; -import android.net.Uri; import android.net.nsd.INsdManager; import android.net.nsd.INsdManagerCallback; import android.net.nsd.INsdServiceConnector; @@ -33,7 +30,6 @@ import android.os.IBinder; import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; -import android.provider.Settings; import android.util.Base64; import android.util.Log; import android.util.Pair; @@ -66,7 +62,6 @@ public class NsdService extends INsdManager.Stub { private static final long CLEANUP_DELAY_MS = 10000; private final Context mContext; - private final NsdSettings mNsdSettings; private final NsdStateMachine mNsdStateMachine; private final DaemonConnection mDaemon; private final NativeCallbackReceiver mDaemonCallback; @@ -121,30 +116,14 @@ public class NsdService extends INsdManager.Stub { this.removeMessages(NsdManager.DAEMON_CLEANUP); } - /** - * Observes the NSD on/off setting, and takes action when changed. - */ - private void registerForNsdSetting() { - final ContentObserver contentObserver = new ContentObserver(this.getHandler()) { - @Override - public void onChange(boolean selfChange) { - notifyEnabled(isNsdEnabled()); - } - }; - - final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON); - mNsdSettings.registerContentObserver(uri, contentObserver); - } - NsdStateMachine(String name, Handler handler) { super(name, handler); addState(mDefaultState); addState(mDisabledState, mDefaultState); addState(mEnabledState, mDefaultState); - State initialState = isNsdEnabled() ? mEnabledState : mDisabledState; + State initialState = mEnabledState; setInitialState(initialState); setLogRecSize(25); - registerForNsdSetting(); } class DefaultState extends State { @@ -580,11 +559,9 @@ public class NsdService extends INsdManager.Stub { } @VisibleForTesting - NsdService(Context ctx, NsdSettings settings, Handler handler, - DaemonConnectionSupplier fn, long cleanupDelayMs) { + NsdService(Context ctx, Handler handler, DaemonConnectionSupplier fn, long cleanupDelayMs) { mCleanupDelayMs = cleanupDelayMs; mContext = ctx; - mNsdSettings = settings; mNsdStateMachine = new NsdStateMachine(TAG, handler); mNsdStateMachine.start(); mDaemonCallback = new NativeCallbackReceiver(); @@ -592,12 +569,11 @@ public class NsdService extends INsdManager.Stub { } public static NsdService create(Context context) throws InterruptedException { - NsdSettings settings = NsdSettings.makeDefault(context); HandlerThread thread = new HandlerThread(TAG); thread.start(); Handler handler = new Handler(thread.getLooper()); - NsdService service = new NsdService(context, settings, handler, - DaemonConnection::new, CLEANUP_DELAY_MS); + NsdService service = + new NsdService(context, handler, DaemonConnection::new, CLEANUP_DELAY_MS); service.mDaemonCallback.awaitConnection(); return service; } @@ -669,10 +645,6 @@ public class NsdService extends INsdManager.Stub { } } - private void notifyEnabled(boolean isEnabled) { - mNsdStateMachine.sendMessage(isEnabled ? NsdManager.ENABLE : NsdManager.DISABLE); - } - private void sendNsdStateChangeBroadcast(boolean isEnabled) { final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); @@ -681,14 +653,6 @@ public class NsdService extends INsdManager.Stub { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private boolean isNsdEnabled() { - boolean ret = mNsdSettings.isEnabled(); - if (DBG) { - Log.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled")); - } - return ret; - } - private int getUniqueId() { if (++mUniqueId == INVALID_ID) return ++mUniqueId; return mUniqueId; @@ -1075,35 +1039,4 @@ public class NsdService extends INsdManager.Stub { } } } - - /** - * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to - * override, or have side effects on global state in unit tests. - */ - @VisibleForTesting - public interface NsdSettings { - boolean isEnabled(); - void putEnabledStatus(boolean isEnabled); - void registerContentObserver(Uri uri, ContentObserver observer); - - static NsdSettings makeDefault(Context context) { - final ContentResolver resolver = context.getContentResolver(); - return new NsdSettings() { - @Override - public boolean isEnabled() { - return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1; - } - - @Override - public void putEnabledStatus(boolean isEnabled) { - Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0); - } - - @Override - public void registerContentObserver(Uri uri, ContentObserver observer) { - resolver.registerContentObserver(uri, false, observer); - } - }; - } - } } From db0b20b2edf21047dab89927e3e7b21ef9b79be2 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 23 Nov 2021 09:49:22 +0800 Subject: [PATCH 0979/1150] Remove @hide symbols from NativeDaemonConnector - FgThread is an service internal class that NativeDaemonConnector can not use it after moving into mainline module. Thus, replace it by creating a new thread. - Remove shutting down check because the original problem owner netd isn't used NativeDaemonConnector now. Bug: 206702844 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Ib2e227ef1e361f96b397abd7c2a88420ad5a2f22 --- .../android/server/NativeDaemonConnector.java | 22 ++++--------------- 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java index 02475dd1ea..ec8d7798e1 100644 --- a/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java +++ b/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java @@ -20,16 +20,15 @@ import android.net.LocalSocket; import android.net.LocalSocketAddress; import android.os.Build; import android.os.Handler; +import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.PowerManager; import android.os.SystemClock; -import android.os.SystemProperties; import android.util.LocalLog; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.server.power.ShutdownThread; import java.io.FileDescriptor; import java.io.IOException; @@ -83,13 +82,6 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl) { - this(callbacks, socket, responseQueueSize, logTag, maxLogSize, wl, - FgThread.get().getLooper()); - } - - NativeDaemonConnector(INativeDaemonConnectorCallbacks callbacks, String socket, - int responseQueueSize, String logTag, int maxLogSize, PowerManager.WakeLock wl, - Looper looper) { mCallbacks = callbacks; mSocket = socket; mResponseQueue = new ResponseQueue(responseQueueSize); @@ -97,10 +89,12 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { if (mWakeLock != null) { mWakeLock.setReferenceCounted(true); } - mLooper = looper; mSequenceNumber = new AtomicInteger(0); TAG = logTag != null ? logTag : "NativeDaemonConnector"; mLocalLog = new LocalLog(maxLogSize); + final HandlerThread thread = new HandlerThread(TAG); + thread.start(); + mLooper = thread.getLooper(); } /** @@ -135,23 +129,15 @@ final class NativeDaemonConnector implements Runnable, Handler.Callback { mCallbackHandler = new Handler(mLooper, this); while (true) { - if (isShuttingDown()) break; try { listenToSocket(); } catch (Exception e) { loge("Error in NativeDaemonConnector: " + e); - if (isShuttingDown()) break; SystemClock.sleep(5000); } } } - private static boolean isShuttingDown() { - String shutdownAct = SystemProperties.get( - ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); - return shutdownAct != null && shutdownAct.length() > 0; - } - @Override public boolean handleMessage(Message msg) { final String event = (String) msg.obj; From 874001496b9375b255f4ddca309439cee54da849 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 8 Dec 2021 15:24:57 +0800 Subject: [PATCH 0980/1150] Move f/b/packages/Nsd files to f/b/packages/ConnectivityT Move Nsd files to ConnectivityT so that nsd, ipsec, ethernet and netstats files can live in the same directory and it will be easier to move everything in frameworks/base/packages/ConnectivityT to packages/modules/Connectivity after fixing all of the hidden API usages. Bug: 204153604 Test: FrameworksNetTests CtsNetTestCases Change-Id: I411e242e8739d15920cfc2fe274115f7f39bd89f --- packages/Nsd/framework/Android.bp => framework-t/Sources.bp | 0 .../src/android/net/nsd/INsdManager.aidl | 0 .../src/android/net/nsd/INsdManagerCallback.aidl | 0 .../src/android/net/nsd/INsdServiceConnector.aidl | 0 .../src/android/net/nsd/NsdManager.java | 0 .../src/android/net/nsd/NsdServiceInfo.java | 0 .../aidl-export/android/net/nsd/NsdServiceInfo.aidl | 0 packages/Nsd/OWNERS | 1 - packages/Nsd/service/Android.bp => service-t/Sources.bp | 0 .../src/com/android/server/INativeDaemonConnectorCallbacks.java | 0 .../src/com/android/server/NativeDaemonConnector.java | 0 .../src/com/android/server/NativeDaemonConnectorException.java | 0 .../src/com/android/server/NativeDaemonEvent.java | 0 .../src/com/android/server/NativeDaemonTimeoutException.java | 0 .../service => service-t}/src/com/android/server/NsdService.java | 0 .../unit/java/com/android/server/NativeDaemonConnectorTest.java | 0 16 files changed, 1 deletion(-) rename packages/Nsd/framework/Android.bp => framework-t/Sources.bp (100%) rename {packages/Nsd/framework => framework-t}/src/android/net/nsd/INsdManager.aidl (100%) rename {packages/Nsd/framework => framework-t}/src/android/net/nsd/INsdManagerCallback.aidl (100%) rename {packages/Nsd/framework => framework-t}/src/android/net/nsd/INsdServiceConnector.aidl (100%) rename {packages/Nsd/framework => framework-t}/src/android/net/nsd/NsdManager.java (100%) rename {packages/Nsd/framework => framework-t}/src/android/net/nsd/NsdServiceInfo.java (100%) rename {packages/Nsd/framework => framework}/aidl-export/android/net/nsd/NsdServiceInfo.aidl (100%) delete mode 100644 packages/Nsd/OWNERS rename packages/Nsd/service/Android.bp => service-t/Sources.bp (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/INativeDaemonConnectorCallbacks.java (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/NativeDaemonConnector.java (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/NativeDaemonConnectorException.java (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/NativeDaemonEvent.java (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/NativeDaemonTimeoutException.java (100%) rename {packages/Nsd/service => service-t}/src/com/android/server/NsdService.java (100%) rename {packages/Nsd/tests => tests}/unit/java/com/android/server/NativeDaemonConnectorTest.java (100%) diff --git a/packages/Nsd/framework/Android.bp b/framework-t/Sources.bp similarity index 100% rename from packages/Nsd/framework/Android.bp rename to framework-t/Sources.bp diff --git a/packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl b/framework-t/src/android/net/nsd/INsdManager.aidl similarity index 100% rename from packages/Nsd/framework/src/android/net/nsd/INsdManager.aidl rename to framework-t/src/android/net/nsd/INsdManager.aidl diff --git a/packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl b/framework-t/src/android/net/nsd/INsdManagerCallback.aidl similarity index 100% rename from packages/Nsd/framework/src/android/net/nsd/INsdManagerCallback.aidl rename to framework-t/src/android/net/nsd/INsdManagerCallback.aidl diff --git a/packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl b/framework-t/src/android/net/nsd/INsdServiceConnector.aidl similarity index 100% rename from packages/Nsd/framework/src/android/net/nsd/INsdServiceConnector.aidl rename to framework-t/src/android/net/nsd/INsdServiceConnector.aidl diff --git a/packages/Nsd/framework/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java similarity index 100% rename from packages/Nsd/framework/src/android/net/nsd/NsdManager.java rename to framework-t/src/android/net/nsd/NsdManager.java diff --git a/packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java b/framework-t/src/android/net/nsd/NsdServiceInfo.java similarity index 100% rename from packages/Nsd/framework/src/android/net/nsd/NsdServiceInfo.java rename to framework-t/src/android/net/nsd/NsdServiceInfo.java diff --git a/packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl b/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl similarity index 100% rename from packages/Nsd/framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl rename to framework/aidl-export/android/net/nsd/NsdServiceInfo.aidl diff --git a/packages/Nsd/OWNERS b/packages/Nsd/OWNERS deleted file mode 100644 index 4862377852..0000000000 --- a/packages/Nsd/OWNERS +++ /dev/null @@ -1 +0,0 @@ -file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking \ No newline at end of file diff --git a/packages/Nsd/service/Android.bp b/service-t/Sources.bp similarity index 100% rename from packages/Nsd/service/Android.bp rename to service-t/Sources.bp diff --git a/packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java b/service-t/src/com/android/server/INativeDaemonConnectorCallbacks.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/INativeDaemonConnectorCallbacks.java rename to service-t/src/com/android/server/INativeDaemonConnectorCallbacks.java diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java b/service-t/src/com/android/server/NativeDaemonConnector.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/NativeDaemonConnector.java rename to service-t/src/com/android/server/NativeDaemonConnector.java diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java b/service-t/src/com/android/server/NativeDaemonConnectorException.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/NativeDaemonConnectorException.java rename to service-t/src/com/android/server/NativeDaemonConnectorException.java diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java b/service-t/src/com/android/server/NativeDaemonEvent.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/NativeDaemonEvent.java rename to service-t/src/com/android/server/NativeDaemonEvent.java diff --git a/packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java b/service-t/src/com/android/server/NativeDaemonTimeoutException.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/NativeDaemonTimeoutException.java rename to service-t/src/com/android/server/NativeDaemonTimeoutException.java diff --git a/packages/Nsd/service/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java similarity index 100% rename from packages/Nsd/service/src/com/android/server/NsdService.java rename to service-t/src/com/android/server/NsdService.java diff --git a/packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java b/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java similarity index 100% rename from packages/Nsd/tests/unit/java/com/android/server/NativeDaemonConnectorTest.java rename to tests/unit/java/com/android/server/NativeDaemonConnectorTest.java From 635e46a2a06416e813d3f81fb913ab3fbfb0d428 Mon Sep 17 00:00:00 2001 From: Zhomart Mukhamejanov Date: Thu, 9 Dec 2021 21:25:48 -0800 Subject: [PATCH 0981/1150] Add javadoc to NetworkStats related classes. Bug: n/a Test: n/a Change-Id: If7f4d68ea89adbcbc02c1e0a06a11f6330f5d8f3 --- core/java/android/net/INetworkStatsSession.aidl | 12 +++++++++++- core/java/android/net/NetworkStats.java | 4 +++- core/java/android/net/NetworkStatsHistory.java | 12 ++++++++++++ .../android/server/net/NetworkStatsCollection.java | 13 +++++++++---- 4 files changed, 35 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/INetworkStatsSession.aidl b/core/java/android/net/INetworkStatsSession.aidl index f13f2cb664..dfedf6633d 100644 --- a/core/java/android/net/INetworkStatsSession.aidl +++ b/core/java/android/net/INetworkStatsSession.aidl @@ -33,7 +33,17 @@ interface INetworkStatsSession { @UnsupportedAppUsage NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); - /** Return network layer usage summary per UID for traffic that matches template. */ + /** + * Return network layer usage summary per UID for traffic that matches template. + * + *

            The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between + * {@code start} and {@code end}. + * + * @param template - a predicate to filter netstats. + * @param start - start of the range, timestamp in milliseconds since the epoch. + * @param end - end of the range, timestamp in milliseconds since the epoch. + * @param includeTags - includes data usage tags if true. + */ @UnsupportedAppUsage NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); /** Return historical network layer stats for specific UID traffic that matches template. */ diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index 46c83df96b..c7ffc19338 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -220,8 +220,10 @@ public final class NetworkStats implements Parcelable { // TODO: move fields to "mVariable" notation /** - * {@link SystemClock#elapsedRealtime()} timestamp when this data was + * {@link SystemClock#elapsedRealtime()} timestamp in milliseconds when this data was * generated. + * It's a timestamps delta when {@link #subtract()}, + * {@code INetworkStatsSession#getSummaryForAllUid()} methods are used. */ private long elapsedRealtime; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java index f41306301d..a875e1ad45 100644 --- a/core/java/android/net/NetworkStatsHistory.java +++ b/core/java/android/net/NetworkStatsHistory.java @@ -526,6 +526,13 @@ public class NetworkStatsHistory implements Parcelable { /** * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. + * + *

            If the active bucket is not completed yet, it returns the proportional value of it + * based on its duration and the {@code end} param. + * + * @param start - start of the range, timestamp in milliseconds since the epoch. + * @param end - end of the range, timestamp in milliseconds since the epoch. + * @param recycle - entry instance for performance, could be null. */ @UnsupportedAppUsage public Entry getValues(long start, long end, Entry recycle) { @@ -535,6 +542,11 @@ public class NetworkStatsHistory implements Parcelable { /** * Return interpolated data usage across the requested range. Interpolates * across buckets, so values may be rounded slightly. + * + * @param start - start of the range, timestamp in milliseconds since the epoch. + * @param end - end of the range, timestamp in milliseconds since the epoch. + * @param now - current timestamp in milliseconds since the epoch (wall clock). + * @param recycle - entry instance for performance, could be null. */ @UnsupportedAppUsage public Entry getValues(long start, long end, long now, Entry recycle) { diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java index df372b1459..213ea402f5 100644 --- a/services/core/java/com/android/server/net/NetworkStatsCollection.java +++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java @@ -59,16 +59,15 @@ import com.android.internal.util.FastDataOutput; import com.android.internal.util.FileRotator; import com.android.internal.util.IndentingPrintWriter; -import libcore.io.IoUtils; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; +import libcore.io.IoUtils; + import java.io.BufferedInputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.DataOutput; -import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -335,7 +334,13 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Summarize all {@link NetworkStatsHistory} in this collection which match - * the requested parameters. + * the requested parameters across the requested range. + * + * @param template - a predicate for filtering netstats. + * @param start - start of the range, timestamp in milliseconds since the epoch. + * @param end - end of the range, timestamp in milliseconds since the epoch. + * @param accessLevel - caller access level. + * @param callerUid - caller UID. */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { From 8074ed308bafdbc868406aa9aae3ec466685a755 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 7 Dec 2021 08:25:31 +0000 Subject: [PATCH 0982/1150] [MS08] Move NetworkStats files to f/b/package/ConnectivityT NetworkStatsService is going to be moved into ConnectivityService module. Move all related files to packages/ConnectivityT so that it can be easily migrate these files to connectivity module after clearing the hidden API usages. Bug: 197717846 Test: TH Change-Id: Iead00832b5eb7b1dc40a92027c5a14ae8316b16c --- framework-t/Sources.bp | 68 +++++++++++++++++-- .../src}/android/app/usage/NetworkStats.java | 0 .../app/usage/NetworkStatsManager.java | 0 .../src}/android/net/DataUsageRequest.aidl | 0 .../src}/android/net/DataUsageRequest.java | 0 .../android/net/INetworkStatsService.aidl | 0 .../android/net/INetworkStatsSession.aidl | 0 .../src}/android/net/NetworkIdentity.java | 0 .../android/net/NetworkStateSnapshot.java | 0 .../src}/android/net/NetworkStats.java | 0 .../src}/android/net/NetworkStatsHistory.aidl | 0 .../src}/android/net/NetworkStatsHistory.java | 0 .../src}/android/net/NetworkTemplate.java | 0 .../src}/android/net/TrafficStats.java | 0 .../android/net/UnderlyingNetworkInfo.aidl | 0 .../android/net/UnderlyingNetworkInfo.java | 0 .../provider/INetworkStatsProvider.aidl | 0 .../INetworkStatsProviderCallback.aidl | 0 .../provider/NetworkStatsProvider.java | 0 .../android/net/NetworkStats.aidl | 0 .../android/net/NetworkTemplate.aidl | 0 service-t/Sources.bp | 36 +++++++++- .../server/net/NetworkIdentitySet.java | 0 .../server/net/NetworkStatsAccess.java | 0 .../server/net/NetworkStatsCollection.java | 0 .../server/net/NetworkStatsFactory.java | 0 .../server/net/NetworkStatsObservers.java | 0 .../server/net/NetworkStatsRecorder.java | 0 .../server/net/NetworkStatsService.java | 0 .../net/NetworkStatsSubscriptionsMonitor.java | 0 30 files changed, 98 insertions(+), 6 deletions(-) rename {core/java => framework-t/src}/android/app/usage/NetworkStats.java (100%) rename {core/java => framework-t/src}/android/app/usage/NetworkStatsManager.java (100%) rename {core/java => framework-t/src}/android/net/DataUsageRequest.aidl (100%) rename {core/java => framework-t/src}/android/net/DataUsageRequest.java (100%) rename {core/java => framework-t/src}/android/net/INetworkStatsService.aidl (100%) rename {core/java => framework-t/src}/android/net/INetworkStatsSession.aidl (100%) rename {core/java => framework-t/src}/android/net/NetworkIdentity.java (100%) rename {core/java => framework-t/src}/android/net/NetworkStateSnapshot.java (100%) rename {core/java => framework-t/src}/android/net/NetworkStats.java (100%) rename {core/java => framework-t/src}/android/net/NetworkStatsHistory.aidl (100%) rename {core/java => framework-t/src}/android/net/NetworkStatsHistory.java (100%) rename {core/java => framework-t/src}/android/net/NetworkTemplate.java (100%) rename {core/java => framework-t/src}/android/net/TrafficStats.java (100%) rename {core/java => framework-t/src}/android/net/UnderlyingNetworkInfo.aidl (100%) rename {core/java => framework-t/src}/android/net/UnderlyingNetworkInfo.java (100%) rename {core/java => framework-t/src}/android/net/netstats/provider/INetworkStatsProvider.aidl (100%) rename {core/java => framework-t/src}/android/net/netstats/provider/INetworkStatsProviderCallback.aidl (100%) rename {core/java => framework-t/src}/android/net/netstats/provider/NetworkStatsProvider.java (100%) rename {core/java => framework/aidl-export}/android/net/NetworkStats.aidl (100%) rename {core/java => framework/aidl-export}/android/net/NetworkTemplate.aidl (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkIdentitySet.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsAccess.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsCollection.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsFactory.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsObservers.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsRecorder.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsService.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/NetworkStatsSubscriptionsMonitor.java (100%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 2363a9f8d4..9c07f399f9 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -19,11 +19,58 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// NetworkStats related libraries. + +filegroup { + name: "framework-connectivity-netstats-internal-sources", + srcs: [ + "src/android/app/usage/*.java", + "src/android/net/DataUsage*.*", + "src/android/net/INetworkStats*.*", + "src/android/net/NetworkIdentity*.java", + "src/android/net/NetworkStateSnapshot.*", + "src/android/net/NetworkStats*.*", + "src/android/net/NetworkTemplate.*", + "src/android/net/TrafficStats.java", + "src/android/net/UnderlyingNetworkInfo.*", + "src/android/net/netstats/**/*.*", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + +filegroup { + name: "framework-connectivity-netstats-aidl-export-sources", + srcs: [ + "aidl-export/android/net/NetworkStats.aidl", + "aidl-export/android/net/NetworkTemplate.aidl", + ], + path: "aidl-export", + visibility: [ + "//visibility:private", + ], +} + +filegroup { + name: "framework-connectivity-netstats-sources", + srcs: [ + ":framework-connectivity-netstats-internal-sources", + ":framework-connectivity-netstats-aidl-export-sources", + ], + visibility: [ + "//visibility:private", + ], +} + +// Nsd related libraries. + filegroup { name: "framework-connectivity-nsd-internal-sources", srcs: [ - "src/**/*.java", - "src/**/*.aidl", + "src/android/net/nsd/*.aidl", + "src/android/net/nsd/*.java", ], path: "src", visibility: [ @@ -34,7 +81,7 @@ filegroup { filegroup { name: "framework-connectivity-nsd-aidl-export-sources", srcs: [ - "aidl-export/**/*.aidl", + "aidl-export/android/net/nsd/*.aidl", ], path: "aidl-export", visibility: [ @@ -49,6 +96,19 @@ filegroup { ":framework-connectivity-nsd-aidl-export-sources", ], visibility: [ - "//frameworks/base", + "//visibility:private", ], } + +// Connectivity-T common libraries. + +filegroup { + name: "framework-connectivity-tiramisu-sources", + srcs: [ + ":framework-connectivity-netstats-sources", + ":framework-connectivity-nsd-sources", + ], + visibility: [ + "//frameworks/base", + ], +} \ No newline at end of file diff --git a/core/java/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java similarity index 100% rename from core/java/android/app/usage/NetworkStats.java rename to framework-t/src/android/app/usage/NetworkStats.java diff --git a/core/java/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java similarity index 100% rename from core/java/android/app/usage/NetworkStatsManager.java rename to framework-t/src/android/app/usage/NetworkStatsManager.java diff --git a/core/java/android/net/DataUsageRequest.aidl b/framework-t/src/android/net/DataUsageRequest.aidl similarity index 100% rename from core/java/android/net/DataUsageRequest.aidl rename to framework-t/src/android/net/DataUsageRequest.aidl diff --git a/core/java/android/net/DataUsageRequest.java b/framework-t/src/android/net/DataUsageRequest.java similarity index 100% rename from core/java/android/net/DataUsageRequest.java rename to framework-t/src/android/net/DataUsageRequest.java diff --git a/core/java/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl similarity index 100% rename from core/java/android/net/INetworkStatsService.aidl rename to framework-t/src/android/net/INetworkStatsService.aidl diff --git a/core/java/android/net/INetworkStatsSession.aidl b/framework-t/src/android/net/INetworkStatsSession.aidl similarity index 100% rename from core/java/android/net/INetworkStatsSession.aidl rename to framework-t/src/android/net/INetworkStatsSession.aidl diff --git a/core/java/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java similarity index 100% rename from core/java/android/net/NetworkIdentity.java rename to framework-t/src/android/net/NetworkIdentity.java diff --git a/core/java/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java similarity index 100% rename from core/java/android/net/NetworkStateSnapshot.java rename to framework-t/src/android/net/NetworkStateSnapshot.java diff --git a/core/java/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java similarity index 100% rename from core/java/android/net/NetworkStats.java rename to framework-t/src/android/net/NetworkStats.java diff --git a/core/java/android/net/NetworkStatsHistory.aidl b/framework-t/src/android/net/NetworkStatsHistory.aidl similarity index 100% rename from core/java/android/net/NetworkStatsHistory.aidl rename to framework-t/src/android/net/NetworkStatsHistory.aidl diff --git a/core/java/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java similarity index 100% rename from core/java/android/net/NetworkStatsHistory.java rename to framework-t/src/android/net/NetworkStatsHistory.java diff --git a/core/java/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java similarity index 100% rename from core/java/android/net/NetworkTemplate.java rename to framework-t/src/android/net/NetworkTemplate.java diff --git a/core/java/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java similarity index 100% rename from core/java/android/net/TrafficStats.java rename to framework-t/src/android/net/TrafficStats.java diff --git a/core/java/android/net/UnderlyingNetworkInfo.aidl b/framework-t/src/android/net/UnderlyingNetworkInfo.aidl similarity index 100% rename from core/java/android/net/UnderlyingNetworkInfo.aidl rename to framework-t/src/android/net/UnderlyingNetworkInfo.aidl diff --git a/core/java/android/net/UnderlyingNetworkInfo.java b/framework-t/src/android/net/UnderlyingNetworkInfo.java similarity index 100% rename from core/java/android/net/UnderlyingNetworkInfo.java rename to framework-t/src/android/net/UnderlyingNetworkInfo.java diff --git a/core/java/android/net/netstats/provider/INetworkStatsProvider.aidl b/framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl similarity index 100% rename from core/java/android/net/netstats/provider/INetworkStatsProvider.aidl rename to framework-t/src/android/net/netstats/provider/INetworkStatsProvider.aidl diff --git a/core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl similarity index 100% rename from core/java/android/net/netstats/provider/INetworkStatsProviderCallback.aidl rename to framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl diff --git a/core/java/android/net/netstats/provider/NetworkStatsProvider.java b/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java similarity index 100% rename from core/java/android/net/netstats/provider/NetworkStatsProvider.java rename to framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java diff --git a/core/java/android/net/NetworkStats.aidl b/framework/aidl-export/android/net/NetworkStats.aidl similarity index 100% rename from core/java/android/net/NetworkStats.aidl rename to framework/aidl-export/android/net/NetworkStats.aidl diff --git a/core/java/android/net/NetworkTemplate.aidl b/framework/aidl-export/android/net/NetworkTemplate.aidl similarity index 100% rename from core/java/android/net/NetworkTemplate.aidl rename to framework/aidl-export/android/net/NetworkTemplate.aidl diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 529f58d130..6a64910609 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -19,13 +19,45 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } +// NetworkStats related libraries. + +filegroup { + name: "services.connectivity-netstats-sources", + srcs: [ + "src/com/android/server/net/NetworkIdentity*.java", + "src/com/android/server/net/NetworkStats*.java", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + +// Nsd related libraries. + filegroup { name: "services.connectivity-nsd-sources", srcs: [ - "src/**/*.java", + "src/com/android/server/INativeDaemon*.java", + "src/com/android/server/NativeDaemon*.java", + "src/com/android/server/Nsd*.java", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + +// Connectivity-T common libraries. + +filegroup { + name: "services.connectivity-tiramisu-sources", + srcs: [ + ":services.connectivity-netstats-sources", + ":services.connectivity-nsd-sources", ], path: "src", visibility: [ "//frameworks/base/services/core", ], -} +} \ No newline at end of file diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/service-t/src/com/android/server/net/NetworkIdentitySet.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkIdentitySet.java rename to service-t/src/com/android/server/net/NetworkIdentitySet.java diff --git a/services/core/java/com/android/server/net/NetworkStatsAccess.java b/service-t/src/com/android/server/net/NetworkStatsAccess.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsAccess.java rename to service-t/src/com/android/server/net/NetworkStatsAccess.java diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/service-t/src/com/android/server/net/NetworkStatsCollection.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsCollection.java rename to service-t/src/com/android/server/net/NetworkStatsCollection.java diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsFactory.java rename to service-t/src/com/android/server/net/NetworkStatsFactory.java diff --git a/services/core/java/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsObservers.java rename to service-t/src/com/android/server/net/NetworkStatsObservers.java diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsRecorder.java rename to service-t/src/com/android/server/net/NetworkStatsRecorder.java diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsService.java rename to service-t/src/com/android/server/net/NetworkStatsService.java diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java similarity index 100% rename from services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java rename to service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java From 4b2fa5914a68612ee93a586e320cdcbecdc55e6e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 10 Dec 2021 07:46:43 +0000 Subject: [PATCH 0983/1150] [MS07.1] Move NetworkStatsCollection/IdentitySet into frameworks These files are needed for the data migration util system Api interfaces to allow OEMs to construct NetworkStats* objects. Thus, they need to be moved into android.net package, and some of them will be exposed as @SystemApi in T. Eventually these classes will be moved into the Connectivity module, but in the mean time they will be temporarily moved to f/b/package/ConnectivityT for the preparation stage. However, the tests are already in the module. Therefore for the S-derived branch, the test cannot see the renamed classes since any framework CLs will not be auto-merged into this branch. Thus, the tests need to stay disabled on the S-derived branch, and will be re-enabled after all files are moved into the module. Test: TH Bug: 197717846 Change-Id: I95278a99cf2437ada28001161ceea17a1d32f2a4 --- .../src/android}/net/NetworkIdentitySet.java | 13 ++++--- .../src/android}/net/NetworkStatsAccess.java | 10 ++++-- .../android}/net/NetworkStatsCollection.java | 35 ++++++++++++------- .../server/net/NetworkStatsObservers.java | 3 ++ .../server/net/NetworkStatsRecorder.java | 3 ++ .../server/net/NetworkStatsService.java | 3 ++ 6 files changed, 47 insertions(+), 20 deletions(-) rename {service-t/src/com/android/server => framework-t/src/android}/net/NetworkIdentitySet.java (97%) rename {service-t/src/com/android/server => framework-t/src/android}/net/NetworkStatsAccess.java (98%) rename {service-t/src/com/android/server => framework-t/src/android}/net/NetworkStatsCollection.java (97%) diff --git a/service-t/src/com/android/server/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java similarity index 97% rename from service-t/src/com/android/server/net/NetworkIdentitySet.java rename to framework-t/src/android/net/NetworkIdentitySet.java index 22ed781da9..abbebef85c 100644 --- a/service-t/src/com/android/server/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package com.android.server.net; +package android.net; + +import static android.net.ConnectivityManager.TYPE_MOBILE; -import android.net.NetworkIdentity; import android.service.NetworkIdentitySetProto; import android.util.proto.ProtoOutputStream; @@ -25,8 +26,6 @@ import java.io.DataOutput; import java.io.IOException; import java.util.HashSet; -import static android.net.ConnectivityManager.TYPE_MOBILE; - /** * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} * active on that interface. @@ -97,6 +96,9 @@ public class NetworkIdentitySet extends HashSet implements } } + /** + * Method to serialize this object into a {@code DataOutput}. + */ public void writeToStream(DataOutput out) throws IOException { out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); out.writeInt(size()); @@ -179,6 +181,9 @@ public class NetworkIdentitySet extends HashSet implements return ident.compareTo(anotherIdent); } + /** + * Method to dump this object into proto debug file. + */ public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); diff --git a/service-t/src/com/android/server/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java similarity index 98% rename from service-t/src/com/android/server/net/NetworkStatsAccess.java rename to framework-t/src/android/net/NetworkStatsAccess.java index d25eae409d..3885a9e6d5 100644 --- a/service-t/src/com/android/server/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java @@ -11,10 +11,10 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License + * limitations under the License. */ -package com.android.server.net; +package android.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.net.NetworkStats.UID_ALL; @@ -37,7 +37,11 @@ import com.android.server.LocalServices; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -/** Utility methods for controlling access to network stats APIs. */ +/** + * Utility methods for controlling access to network stats APIs. + * + * @hide + */ public final class NetworkStatsAccess { private NetworkStatsAccess() {} diff --git a/service-t/src/com/android/server/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java similarity index 97% rename from service-t/src/com/android/server/net/NetworkStatsCollection.java rename to framework-t/src/android/net/NetworkStatsCollection.java index 213ea402f5..0d3b9ed4e3 100644 --- a/service-t/src/com/android/server/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.server.net; +package android.net; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -31,13 +31,7 @@ import static android.net.TrafficStats.UID_REMOVED; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; -import static com.android.server.net.NetworkStatsService.TAG; -import android.net.NetworkIdentity; -import android.net.NetworkStats; -import android.net.NetworkStatsHistory; -import android.net.NetworkTemplate; -import android.net.TrafficStats; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; import android.service.NetworkStatsCollectionProto; @@ -85,8 +79,11 @@ import java.util.Objects; /** * Collection of {@link NetworkStatsHistory}, stored based on combined key of * {@link NetworkIdentitySet}, UID, set, and tag. Knows how to persist itself. + * + * @hide */ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { + private static final String TAG = NetworkStatsCollection.class.getSimpleName(); /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; @@ -366,8 +363,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W entry.uid = key.uid; entry.set = key.set; entry.tag = key.tag; - entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() ? - DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; + entry.defaultNetwork = key.ident.areAllMembersOnDefaultNetwork() + ? DEFAULT_NETWORK_YES : DEFAULT_NETWORK_NO; entry.metered = key.ident.isAnyMemberMetered() ? METERED_YES : METERED_NO; entry.roaming = key.ident.isAnyMemberRoaming() ? ROAMING_YES : ROAMING_NO; entry.rxBytes = historyEntry.rxBytes; @@ -521,6 +518,12 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** + * Read legacy network summary statistics file format into the collection, + * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. + * + * @deprecated + */ @Deprecated public void readLegacyNetwork(File file) throws IOException { final AtomicFile inputFile = new AtomicFile(file); @@ -560,6 +563,12 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** + * Read legacy Uid statistics file format into the collection, + * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. + * + * @deprecated + */ @Deprecated public void readLegacyUid(File file, boolean onlyTags) throws IOException { final AtomicFile inputFile = new AtomicFile(file); @@ -774,19 +783,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W public final int set; public final int tag; - private final int hashCode; + private final int mHashCode; - public Key(NetworkIdentitySet ident, int uid, int set, int tag) { + Key(NetworkIdentitySet ident, int uid, int set, int tag) { this.ident = ident; this.uid = uid; this.set = set; this.tag = tag; - hashCode = Objects.hash(ident, uid, set, tag); + mHashCode = Objects.hash(ident, uid, set, tag); } @Override public int hashCode() { - return hashCode; + return mHashCode; } @Override diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index 2564daeaa1..1a0866d2f9 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -22,7 +22,10 @@ import static com.android.internal.util.Preconditions.checkArgument; import android.app.usage.NetworkStatsManager; import android.net.DataUsageRequest; +import android.net.NetworkIdentitySet; import android.net.NetworkStats; +import android.net.NetworkStatsAccess; +import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.Bundle; diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index 978ae87d39..5e27c776cc 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -21,8 +21,11 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.text.format.DateUtils.YEAR_IN_MILLIS; +import android.net.NetworkIdentitySet; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; +import android.net.NetworkStatsAccess; +import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index c876d411fa..2beca73ecd 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -96,11 +96,14 @@ import android.net.INetworkStatsSession; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; +import android.net.NetworkIdentitySet; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkStats; import android.net.NetworkStats.NonMonotonicObserver; +import android.net.NetworkStatsAccess; +import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; From 24138d07edb6dceff7bd147e29e46a55376089db Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 2 Nov 2021 02:39:49 +0000 Subject: [PATCH 0984/1150] [MS01] Move NetworkTemplate cloud backup functions to NetworkPolicy Since NetworkTemplate will be moved into the mainline module. It is necessary to remove hidden BackupUtil usage from NetworkTemplate. Also, it is also a hazard to maintain compatibility for byte buffer interfaces. Thus, move out these cloud backup functions to NetworkPolicy to address these concerns. Test: atest NetworkPolicyTest NetworkPolicyManagerServiceTest Bug: 204830222 Change-Id: I3ec55f7e419ea13db535acff2457d8e7aaebdce8 --- .../src/android/net/NetworkTemplate.java | 73 ------------------- 1 file changed, 73 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index c906a13bf4..8b9c14df7d 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -44,16 +44,10 @@ import android.os.Parcelable; import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.BackupUtils; -import android.util.Log; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -69,19 +63,6 @@ import java.util.Objects; public class NetworkTemplate implements Parcelable { private static final String TAG = "NetworkTemplate"; - /** - * Initial Version of the backup serializer. - */ - public static final int BACKUP_VERSION_1_INIT = 1; - /** - * Version of the backup serializer that added carrier template support. - */ - public static final int BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE = 2; - /** - * Current Version of the Backup Serializer. - */ - private static final int BACKUP_VERSION = BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE; - public static final int MATCH_MOBILE = 1; public static final int MATCH_WIFI = 4; public static final int MATCH_ETHERNET = 5; @@ -849,58 +830,4 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate[size]; } }; - - public byte[] getBytesForBackup() throws IOException { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream(baos); - - if (!isPersistable()) { - Log.wtf(TAG, "Trying to backup non-persistable template: " + this); - } - - out.writeInt(BACKUP_VERSION); - - out.writeInt(mMatchRule); - BackupUtils.writeString(out, mSubscriberId); - BackupUtils.writeString(out, mNetworkId); - out.writeInt(mMetered); - out.writeInt(mSubscriberIdMatchRule); - - return baos.toByteArray(); - } - - public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in) - throws IOException, BackupUtils.BadVersionException { - int version = in.readInt(); - if (version < BACKUP_VERSION_1_INIT || version > BACKUP_VERSION) { - throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version"); - } - - int matchRule = in.readInt(); - String subscriberId = BackupUtils.readString(in); - String networkId = BackupUtils.readString(in); - - final int metered; - final int subscriberIdMatchRule; - if (version >= BACKUP_VERSION_2_SUPPORT_CARRIER_TEMPLATE) { - metered = in.readInt(); - subscriberIdMatchRule = in.readInt(); - } else { - // For backward compatibility, fill the missing filters from match rules. - metered = (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD - || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL; - subscriberIdMatchRule = SUBSCRIBER_ID_MATCH_RULE_EXACT; - } - - try { - return new NetworkTemplate(matchRule, - subscriberId, new String[] { subscriberId }, - networkId, metered, NetworkStats.ROAMING_ALL, - NetworkStats.DEFAULT_NETWORK_ALL, NetworkTemplate.NETWORK_TYPE_ALL, - NetworkTemplate.OEM_MANAGED_ALL, subscriberIdMatchRule); - } catch (IllegalArgumentException e) { - throw new BackupUtils.BadVersionException( - "Restored network template contains unknown match rule " + matchRule, e); - } - } } From 38413790baaa82f2a1ab6e37660800228add629d Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 23 Nov 2021 16:16:13 +0800 Subject: [PATCH 0985/1150] Register NSD service from ConnectivityFrameworkInitializerTiramisu INsdManager is going to move into connectivity mainline module and it will be not visible to SystemServiceRegistry after migration done. Thus, use ConnectivityFrameworkInitializerTiramisu to register NSD service instead. ConnectivityFrameworkInitializerTiramisu will be implemented in the framework-connectivity-tiramisu bootclasspath JAR, which need to be separated from the S+ framework-connectivity bootclasspath JAR to be only loaded by the module on T+. So its methods cannot be in the same class as ConnectivityFrameworkInitializer. Bug: 206702844 Test: atest FrameworksNetTests CtsNetTestCases Change-Id: Ibf89ab9a35e35dac4978ba70c7ab306b6155a4a3 --- framework-t/Sources.bp | 14 ++++- ...nectivityFrameworkInitializerTiramisu.java | 52 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 9c07f399f9..3e82b28ce6 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -102,13 +102,25 @@ filegroup { // Connectivity-T common libraries. +filegroup { + name: "framework-connectivity-tiramisu-internal-sources", + srcs: [ + "src/android/net/ConnectivityFrameworkInitializerTiramisu.java", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", + ":framework-connectivity-tiramisu-internal-sources", ], visibility: [ "//frameworks/base", ], -} \ No newline at end of file +} diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java new file mode 100644 index 0000000000..630f902ecf --- /dev/null +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.content.Context; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; + +/** + * Class for performing registration for Connectivity services which are exposed via updatable APIs + * since Android T. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerTiramisu { + private ConnectivityFrameworkInitializerTiramisu() {} + + /** + * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to + * {@link Context}, so that {@link Context#getSystemService} can return them. + * + * @throws IllegalStateException if this is called anywhere besides + * {@link SystemServiceRegistry}. + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + Context.NSD_SERVICE, + NsdManager.class, + (context, serviceBinder) -> { + INsdManager service = INsdManager.Stub.asInterface(serviceBinder); + return new NsdManager(context, service); + } + ); + } +} From 2c62aabec6ede2b0263cd81c027cf72ef3988235 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 2 Nov 2021 06:52:46 +0000 Subject: [PATCH 0986/1150] [MS03] Remove ServiceNotFoundException hidden API usage Since ServiceNotFoundException is not a system API. Remove the unsupported interface which uses this exception. This is safe since the method annotated with maxTargetSdk = R and from dashboard it is not using by anybody. Test: TH Bug: 204830222 Change-Id: Ib8c0ce7b165732d24929851792d35371b90a5dfc --- .../src/android/app/usage/NetworkStatsManager.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 8a6c85d548..ca83309216 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -45,8 +45,6 @@ import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.ServiceManager.ServiceNotFoundException; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.DataUnit; @@ -135,15 +133,6 @@ public class NetworkStatsManager { private int mFlags; - /** - * {@hide} - */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public NetworkStatsManager(Context context) throws ServiceNotFoundException { - this(context, INetworkStatsService.Stub.asInterface( - ServiceManager.getServiceOrThrow(Context.NETWORK_STATS_SERVICE))); - } - /** @hide */ @VisibleForTesting public NetworkStatsManager(Context context, INetworkStatsService service) { From 51ce7c1fa0dbf8fd5ab587252f17a98617a2d054 Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 23 Nov 2021 16:16:13 +0800 Subject: [PATCH 0987/1150] Register NSD service from ConnectivityFrameworkInitializerTiramisu INsdManager is going to move into connectivity mainline module and it will be not visible to SystemServiceRegistry after migration done. Thus, use ConnectivityFrameworkInitializerTiramisu to register NSD service instead. ConnectivityFrameworkInitializerTiramisu will be implemented in the framework-connectivity-tiramisu bootclasspath JAR, which need to be separated from the S+ framework-connectivity bootclasspath JAR to be only loaded by the module on T+. So its methods cannot be in the same class as ConnectivityFrameworkInitializer. Bug: 206702844 Test: atest FrameworksNetTests CtsNetTestCases Merged-In: Ibf89ab9a35e35dac4978ba70c7ab306b6155a4a3 Change-Id: Ibf89ab9a35e35dac4978ba70c7ab306b6155a4a3 --- framework-t/Sources.bp | 14 ++++- ...nectivityFrameworkInitializerTiramisu.java | 52 +++++++++++++++++++ 2 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 9c07f399f9..3e82b28ce6 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -102,13 +102,25 @@ filegroup { // Connectivity-T common libraries. +filegroup { + name: "framework-connectivity-tiramisu-internal-sources", + srcs: [ + "src/android/net/ConnectivityFrameworkInitializerTiramisu.java", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", + ":framework-connectivity-tiramisu-internal-sources", ], visibility: [ "//frameworks/base", ], -} \ No newline at end of file +} diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java new file mode 100644 index 0000000000..630f902ecf --- /dev/null +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.SystemApi; +import android.app.SystemServiceRegistry; +import android.content.Context; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; + +/** + * Class for performing registration for Connectivity services which are exposed via updatable APIs + * since Android T. + * + * @hide + */ +@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) +public final class ConnectivityFrameworkInitializerTiramisu { + private ConnectivityFrameworkInitializerTiramisu() {} + + /** + * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to + * {@link Context}, so that {@link Context#getSystemService} can return them. + * + * @throws IllegalStateException if this is called anywhere besides + * {@link SystemServiceRegistry}. + */ + public static void registerServiceWrappers() { + SystemServiceRegistry.registerContextAwareService( + Context.NSD_SERVICE, + NsdManager.class, + (context, serviceBinder) -> { + INsdManager service = INsdManager.Stub.asInterface(serviceBinder); + return new NsdManager(context, service); + } + ); + } +} From 5393e070ed9afdbf4540e2ddfb297224f6869f29 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 9 Sep 2021 17:59:37 +0900 Subject: [PATCH 0988/1150] Remove Preconditions, Protocol @hide usage Remove hidden API usage of the Preconditions and Protocol classes in NsdManager. NsdManager does not share its handler with other components, so it does not need to use specific message IDs from Protocol. Preconditions can also be easily replaced with stable API alternatives. Bug: 190249673 Test: atest FrameworksNetTests CtsNetTestCases:NsdManagerTest Change-Id: Ia173f99b82c90df702291c3690f4a7b047e90daa --- .../src/android/net/nsd/NsdManager.java | 102 ++++++++++-------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index 6c597e26e0..0f21e55b9f 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java @@ -16,10 +16,6 @@ package android.net.nsd; -import static com.android.internal.util.Preconditions.checkArgument; -import static com.android.internal.util.Preconditions.checkNotNull; -import static com.android.internal.util.Preconditions.checkStringNotEmpty; - import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -32,11 +28,13 @@ import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; +import android.text.TextUtils; import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Protocol; + +import java.util.Objects; /** * The Network Service Discovery Manager class provides the API to discover services @@ -175,65 +173,63 @@ public final class NsdManager { */ public static final int NSD_STATE_ENABLED = 2; - private static final int BASE = Protocol.BASE_NSD_MANAGER; + /** @hide */ + public static final int DISCOVER_SERVICES = 1; + /** @hide */ + public static final int DISCOVER_SERVICES_STARTED = 2; + /** @hide */ + public static final int DISCOVER_SERVICES_FAILED = 3; + /** @hide */ + public static final int SERVICE_FOUND = 4; + /** @hide */ + public static final int SERVICE_LOST = 5; /** @hide */ - public static final int DISCOVER_SERVICES = BASE + 1; + public static final int STOP_DISCOVERY = 6; /** @hide */ - public static final int DISCOVER_SERVICES_STARTED = BASE + 2; + public static final int STOP_DISCOVERY_FAILED = 7; /** @hide */ - public static final int DISCOVER_SERVICES_FAILED = BASE + 3; - /** @hide */ - public static final int SERVICE_FOUND = BASE + 4; - /** @hide */ - public static final int SERVICE_LOST = BASE + 5; + public static final int STOP_DISCOVERY_SUCCEEDED = 8; /** @hide */ - public static final int STOP_DISCOVERY = BASE + 6; + public static final int REGISTER_SERVICE = 9; /** @hide */ - public static final int STOP_DISCOVERY_FAILED = BASE + 7; + public static final int REGISTER_SERVICE_FAILED = 10; /** @hide */ - public static final int STOP_DISCOVERY_SUCCEEDED = BASE + 8; + public static final int REGISTER_SERVICE_SUCCEEDED = 11; /** @hide */ - public static final int REGISTER_SERVICE = BASE + 9; + public static final int UNREGISTER_SERVICE = 12; /** @hide */ - public static final int REGISTER_SERVICE_FAILED = BASE + 10; + public static final int UNREGISTER_SERVICE_FAILED = 13; /** @hide */ - public static final int REGISTER_SERVICE_SUCCEEDED = BASE + 11; + public static final int UNREGISTER_SERVICE_SUCCEEDED = 14; /** @hide */ - public static final int UNREGISTER_SERVICE = BASE + 12; + public static final int RESOLVE_SERVICE = 15; /** @hide */ - public static final int UNREGISTER_SERVICE_FAILED = BASE + 13; + public static final int RESOLVE_SERVICE_FAILED = 16; /** @hide */ - public static final int UNREGISTER_SERVICE_SUCCEEDED = BASE + 14; + public static final int RESOLVE_SERVICE_SUCCEEDED = 17; /** @hide */ - public static final int RESOLVE_SERVICE = BASE + 18; - /** @hide */ - public static final int RESOLVE_SERVICE_FAILED = BASE + 19; - /** @hide */ - public static final int RESOLVE_SERVICE_SUCCEEDED = BASE + 20; + public static final int DAEMON_CLEANUP = 18; /** @hide */ - public static final int DAEMON_CLEANUP = BASE + 21; + public static final int DAEMON_STARTUP = 19; /** @hide */ - public static final int DAEMON_STARTUP = BASE + 22; + public static final int ENABLE = 20; + /** @hide */ + public static final int DISABLE = 21; /** @hide */ - public static final int ENABLE = BASE + 24; - /** @hide */ - public static final int DISABLE = BASE + 25; + public static final int NATIVE_DAEMON_EVENT = 22; /** @hide */ - public static final int NATIVE_DAEMON_EVENT = BASE + 26; - + public static final int REGISTER_CLIENT = 23; /** @hide */ - public static final int REGISTER_CLIENT = BASE + 27; - /** @hide */ - public static final int UNREGISTER_CLIENT = BASE + 28; + public static final int UNREGISTER_CLIENT = 24; /** Dns based service discovery protocol */ public static final int PROTOCOL_DNS_SD = 0x0001; @@ -550,7 +546,9 @@ public final class NsdManager { final int key; synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - checkArgument(valueIndex == -1, "listener already in use"); + if (valueIndex != -1) { + throw new IllegalArgumentException("listener already in use"); + } key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); @@ -569,7 +567,9 @@ public final class NsdManager { checkListener(listener); synchronized (mMapLock) { int valueIndex = mListenerMap.indexOfValue(listener); - checkArgument(valueIndex != -1, "listener not registered"); + if (valueIndex == -1) { + throw new IllegalArgumentException("listener not registered"); + } return mListenerMap.keyAt(valueIndex); } } @@ -598,7 +598,9 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { - checkArgument(serviceInfo.getPort() > 0, "Invalid port number"); + if (serviceInfo.getPort() <= 0) { + throw new IllegalArgumentException("Invalid port number"); + } checkServiceInfo(serviceInfo); checkProtocol(protocolType); int key = putListener(listener, serviceInfo); @@ -660,7 +662,9 @@ public final class NsdManager { * Cannot be null. Cannot be in use for an active service discovery. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - checkStringNotEmpty(serviceType, "Service type cannot be empty"); + if (TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException("Service type cannot be empty"); + } checkProtocol(protocolType); NsdServiceInfo s = new NsdServiceInfo(); @@ -719,16 +723,22 @@ public final class NsdManager { } private static void checkListener(Object listener) { - checkNotNull(listener, "listener cannot be null"); + Objects.requireNonNull(listener, "listener cannot be null"); } private static void checkProtocol(int protocolType) { - checkArgument(protocolType == PROTOCOL_DNS_SD, "Unsupported protocol"); + if (protocolType != PROTOCOL_DNS_SD) { + throw new IllegalArgumentException("Unsupported protocol"); + } } private static void checkServiceInfo(NsdServiceInfo serviceInfo) { - checkNotNull(serviceInfo, "NsdServiceInfo cannot be null"); - checkStringNotEmpty(serviceInfo.getServiceName(), "Service name cannot be empty"); - checkStringNotEmpty(serviceInfo.getServiceType(), "Service type cannot be empty"); + Objects.requireNonNull(serviceInfo, "NsdServiceInfo cannot be null"); + if (TextUtils.isEmpty(serviceInfo.getServiceName())) { + throw new IllegalArgumentException("Service name cannot be empty"); + } + if (TextUtils.isEmpty(serviceInfo.getServiceType())) { + throw new IllegalArgumentException("Service type cannot be empty"); + } } } From 8f4e23616c25f06a266196f919dea0e8712da359 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 10 Dec 2021 17:36:49 +0800 Subject: [PATCH 0989/1150] Move IpSec associated files to f/b/packages/ConnectivityT IpSecService is going to be moved into Connectivity mainline module. Move all ipsec associated files to packages/ConnectivityT so that it can be easily migrate these files to connectivity module after clearing the hidden API usages. Bug: 204153604 Test: build pass FrameworksNetTests CtsNetTestCases Change-Id: I562b47f18e345988a2638cf886f86818f9144b91 --- framework-t/Sources.bp | 19 +++++++++++++++--- .../src}/android/net/IIpSecService.aidl | 0 .../src}/android/net/IpSecAlgorithm.java | 0 .../src}/android/net/IpSecConfig.aidl | 0 .../src}/android/net/IpSecConfig.java | 0 .../src}/android/net/IpSecManager.java | 0 .../src}/android/net/IpSecSpiResponse.aidl | 0 .../src}/android/net/IpSecSpiResponse.java | 0 .../src}/android/net/IpSecTransform.java | 0 .../android/net/IpSecTransformResponse.aidl | 0 .../android/net/IpSecTransformResponse.java | 0 .../net/IpSecTunnelInterfaceResponse.aidl | 0 .../net/IpSecTunnelInterfaceResponse.java | 0 .../android/net/IpSecUdpEncapResponse.aidl | 0 .../android/net/IpSecUdpEncapResponse.java | 0 service-t/Sources.bp | 20 +++++++++++++++---- .../src}/com/android/server/IpSecService.java | 0 17 files changed, 32 insertions(+), 7 deletions(-) rename {core/java => framework-t/src}/android/net/IIpSecService.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecAlgorithm.java (100%) rename {core/java => framework-t/src}/android/net/IpSecConfig.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecConfig.java (100%) rename {core/java => framework-t/src}/android/net/IpSecManager.java (100%) rename {core/java => framework-t/src}/android/net/IpSecSpiResponse.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecSpiResponse.java (100%) rename {core/java => framework-t/src}/android/net/IpSecTransform.java (100%) rename {core/java => framework-t/src}/android/net/IpSecTransformResponse.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecTransformResponse.java (100%) rename {core/java => framework-t/src}/android/net/IpSecTunnelInterfaceResponse.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecTunnelInterfaceResponse.java (100%) rename {core/java => framework-t/src}/android/net/IpSecUdpEncapResponse.aidl (100%) rename {core/java => framework-t/src}/android/net/IpSecUdpEncapResponse.java (100%) rename {services/core/java => service-t/src}/com/android/server/IpSecService.java (100%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 3e82b28ce6..931a55b27d 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -100,6 +100,20 @@ filegroup { ], } +// IpSec related libraries. + +filegroup { + name: "framework-connectivity-ipsec-sources", + srcs: [ + "src/android/net/IIpSecService.aidl", + "src/android/net/IpSec*.*", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + // Connectivity-T common libraries. filegroup { @@ -116,11 +130,10 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ + ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], - visibility: [ - "//frameworks/base", - ], + visibility: ["//frameworks/base"], } diff --git a/core/java/android/net/IIpSecService.aidl b/framework-t/src/android/net/IIpSecService.aidl similarity index 100% rename from core/java/android/net/IIpSecService.aidl rename to framework-t/src/android/net/IIpSecService.aidl diff --git a/core/java/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java similarity index 100% rename from core/java/android/net/IpSecAlgorithm.java rename to framework-t/src/android/net/IpSecAlgorithm.java diff --git a/core/java/android/net/IpSecConfig.aidl b/framework-t/src/android/net/IpSecConfig.aidl similarity index 100% rename from core/java/android/net/IpSecConfig.aidl rename to framework-t/src/android/net/IpSecConfig.aidl diff --git a/core/java/android/net/IpSecConfig.java b/framework-t/src/android/net/IpSecConfig.java similarity index 100% rename from core/java/android/net/IpSecConfig.java rename to framework-t/src/android/net/IpSecConfig.java diff --git a/core/java/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java similarity index 100% rename from core/java/android/net/IpSecManager.java rename to framework-t/src/android/net/IpSecManager.java diff --git a/core/java/android/net/IpSecSpiResponse.aidl b/framework-t/src/android/net/IpSecSpiResponse.aidl similarity index 100% rename from core/java/android/net/IpSecSpiResponse.aidl rename to framework-t/src/android/net/IpSecSpiResponse.aidl diff --git a/core/java/android/net/IpSecSpiResponse.java b/framework-t/src/android/net/IpSecSpiResponse.java similarity index 100% rename from core/java/android/net/IpSecSpiResponse.java rename to framework-t/src/android/net/IpSecSpiResponse.java diff --git a/core/java/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java similarity index 100% rename from core/java/android/net/IpSecTransform.java rename to framework-t/src/android/net/IpSecTransform.java diff --git a/core/java/android/net/IpSecTransformResponse.aidl b/framework-t/src/android/net/IpSecTransformResponse.aidl similarity index 100% rename from core/java/android/net/IpSecTransformResponse.aidl rename to framework-t/src/android/net/IpSecTransformResponse.aidl diff --git a/core/java/android/net/IpSecTransformResponse.java b/framework-t/src/android/net/IpSecTransformResponse.java similarity index 100% rename from core/java/android/net/IpSecTransformResponse.java rename to framework-t/src/android/net/IpSecTransformResponse.java diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.aidl b/framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl similarity index 100% rename from core/java/android/net/IpSecTunnelInterfaceResponse.aidl rename to framework-t/src/android/net/IpSecTunnelInterfaceResponse.aidl diff --git a/core/java/android/net/IpSecTunnelInterfaceResponse.java b/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java similarity index 100% rename from core/java/android/net/IpSecTunnelInterfaceResponse.java rename to framework-t/src/android/net/IpSecTunnelInterfaceResponse.java diff --git a/core/java/android/net/IpSecUdpEncapResponse.aidl b/framework-t/src/android/net/IpSecUdpEncapResponse.aidl similarity index 100% rename from core/java/android/net/IpSecUdpEncapResponse.aidl rename to framework-t/src/android/net/IpSecUdpEncapResponse.aidl diff --git a/core/java/android/net/IpSecUdpEncapResponse.java b/framework-t/src/android/net/IpSecUdpEncapResponse.java similarity index 100% rename from core/java/android/net/IpSecUdpEncapResponse.java rename to framework-t/src/android/net/IpSecUdpEncapResponse.java diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 6a64910609..7b8817692b 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -48,16 +48,28 @@ filegroup { ], } +// IpSec related libraries. + +filegroup { + name: "services.connectivity-ipsec-sources", + srcs: [ + "src/com/android/server/IpSecService.java", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + // Connectivity-T common libraries. filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ + ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", ], path: "src", - visibility: [ - "//frameworks/base/services/core", - ], -} \ No newline at end of file + visibility: ["//frameworks/base/services/core"], +} diff --git a/services/core/java/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java similarity index 100% rename from services/core/java/com/android/server/IpSecService.java rename to service-t/src/com/android/server/IpSecService.java From b24f3da2b95d9543bc268e266fde714134f67f97 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 6 Dec 2021 15:18:42 +0800 Subject: [PATCH 0990/1150] Fix style errors for IpSec associated files Bug: 204153604 Test: build pass. Change-Id: I940de8bef7f693dcce8808148a975bea1f36712c --- .../src/android/net/IpSecAlgorithm.java | 2 +- framework-t/src/android/net/IpSecManager.java | 12 +++---- .../android/net/IpSecTransformResponse.java | 3 +- .../net/IpSecTunnelInterfaceResponse.java | 3 +- .../android/net/IpSecUdpEncapResponse.java | 4 ++- .../src/com/android/server/IpSecService.java | 33 ++++++++++--------- 6 files changed, 31 insertions(+), 26 deletions(-) diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java index 86052484ea..840af28b77 100644 --- a/framework-t/src/android/net/IpSecAlgorithm.java +++ b/framework-t/src/android/net/IpSecAlgorithm.java @@ -297,7 +297,7 @@ public final class IpSecAlgorithm implements Parcelable { return mTruncLenBits; } - /* Parcelable Implementation */ + /** Parcelable Implementation */ public int describeContents() { return 0; } diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index c10680761f..837629911c 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -99,9 +99,9 @@ public final class IpSecManager { /** @hide */ public interface Status { - public static final int OK = 0; - public static final int RESOURCE_UNAVAILABLE = 1; - public static final int SPI_UNAVAILABLE = 2; + int OK = 0; + int RESOURCE_UNAVAILABLE = 1; + int SPI_UNAVAILABLE = 2; } /** @hide */ @@ -276,7 +276,7 @@ public final class IpSecManager { * @param destinationAddress the destination address for traffic bearing the requested SPI. * For inbound traffic, the destination should be an address currently assigned on-device. * @return the reserved SecurityParameterIndex - * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * @throws ResourceUnavailableException indicating that too many SPIs are * currently allocated for this user */ @NonNull @@ -307,9 +307,9 @@ public final class IpSecManager { * @param requestedSpi the requested SPI. The range 1-255 is reserved and may not be used. See * RFC 4303 Section 2.1. * @return the reserved SecurityParameterIndex - * @throws {@link #ResourceUnavailableException} indicating that too many SPIs are + * @throws ResourceUnavailableException indicating that too many SPIs are * currently allocated for this user - * @throws {@link #SpiUnavailableException} indicating that the requested SPI could not be + * @throws SpiUnavailableException indicating that the requested SPI could not be * reserved */ @NonNull diff --git a/framework-t/src/android/net/IpSecTransformResponse.java b/framework-t/src/android/net/IpSecTransformResponse.java index a38488954f..363f3165ee 100644 --- a/framework-t/src/android/net/IpSecTransformResponse.java +++ b/framework-t/src/android/net/IpSecTransformResponse.java @@ -60,7 +60,8 @@ public final class IpSecTransformResponse implements Parcelable { resourceId = in.readInt(); } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + @android.annotation.NonNull + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecTransformResponse createFromParcel(Parcel in) { return new IpSecTransformResponse(in); diff --git a/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java b/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java index e3411e003d..127e30a693 100644 --- a/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java +++ b/framework-t/src/android/net/IpSecTunnelInterfaceResponse.java @@ -65,7 +65,8 @@ public final class IpSecTunnelInterfaceResponse implements Parcelable { interfaceName = in.readString(); } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + @android.annotation.NonNull + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecTunnelInterfaceResponse createFromParcel(Parcel in) { return new IpSecTunnelInterfaceResponse(in); diff --git a/framework-t/src/android/net/IpSecUdpEncapResponse.java b/framework-t/src/android/net/IpSecUdpEncapResponse.java index 4e7ba9b515..732cf198a9 100644 --- a/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ b/framework-t/src/android/net/IpSecUdpEncapResponse.java @@ -18,6 +18,7 @@ package android.net; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Parcelable; + import java.io.FileDescriptor; import java.io.IOException; @@ -83,7 +84,8 @@ public final class IpSecUdpEncapResponse implements Parcelable { fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); } - public static final @android.annotation.NonNull Parcelable.Creator CREATOR = + @android.annotation.NonNull + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public IpSecUdpEncapResponse createFromParcel(Parcel in) { return new IpSecUdpEncapResponse(in); diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index aeb814327e..dfc57c136f 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -132,7 +132,7 @@ public class IpSecService extends IIpSecService.Stub { interface IpSecServiceConfiguration { INetd getNetdInstance() throws RemoteException; - static IpSecServiceConfiguration GETSRVINSTANCE = + IpSecServiceConfiguration GETSRVINSTANCE = new IpSecServiceConfiguration() { @Override public INetd getNetdInstance() throws RemoteException { @@ -491,8 +491,8 @@ public class IpSecService extends IIpSecService.Stub { *

            This class associates kernel resources with the UID that owns and controls them. */ private abstract class OwnedResourceRecord implements IResource { - final int pid; - final int uid; + final int mPid; + final int mUid; protected final int mResourceId; OwnedResourceRecord(int resourceId) { @@ -501,8 +501,8 @@ public class IpSecService extends IIpSecService.Stub { throw new IllegalArgumentException("Resource ID must not be INVALID_RESOURCE_ID"); } mResourceId = resourceId; - pid = Binder.getCallingPid(); - uid = Binder.getCallingUid(); + mPid = Binder.getCallingPid(); + mUid = Binder.getCallingUid(); getResourceTracker().take(); } @@ -512,7 +512,7 @@ public class IpSecService extends IIpSecService.Stub { /** Convenience method; retrieves the user resource record for the stored UID. */ protected UserRecord getUserRecord() { - return mUserResourceTracker.getUserRecord(uid); + return mUserResourceTracker.getUserRecord(mUid); } @Override @@ -527,9 +527,9 @@ public class IpSecService extends IIpSecService.Stub { .append("{mResourceId=") .append(mResourceId) .append(", pid=") - .append(pid) + .append(mPid) .append(", uid=") - .append(uid) + .append(mUid) .append("}") .toString(); } @@ -545,7 +545,7 @@ public class IpSecService extends IIpSecService.Stub { SparseArray> mArray = new SparseArray<>(); private final String mTypeName; - public RefcountedResourceArray(String typeName) { + RefcountedResourceArray(String typeName) { this.mTypeName = typeName; } @@ -628,7 +628,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - uid, + mUid, mConfig.getSourceAddress(), mConfig.getDestinationAddress(), spi, @@ -696,7 +696,7 @@ public class IpSecService extends IIpSecService.Stub { mSrvConfig .getNetdInstance() .ipSecDeleteSecurityAssociation( - uid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, + mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, 0 /* mask */, 0 /* if_id */); } } catch (ServiceSpecificException | RemoteException e) { @@ -849,14 +849,14 @@ public class IpSecService extends IIpSecService.Stub { for (int selAddrFamily : ADDRESS_FAMILIES) { netd.ipSecDeleteSecurityPolicy( - uid, + mUid, selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, 0xffffffff, mIfId); netd.ipSecDeleteSecurityPolicy( - uid, + mUid, selAddrFamily, IpSecManager.DIRECTION_IN, mIkey, @@ -1025,7 +1025,7 @@ public class IpSecService extends IIpSecService.Stub { @NonNull private AppOpsManager getAppOpsManager() { AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); - if(appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); + if (appOps == null) throw new RuntimeException("System Server couldn't get AppOps"); return appOps; } @@ -1054,6 +1054,7 @@ public class IpSecService extends IIpSecService.Stub { mUidFdTagger = uidFdTagger; } + /** Called by system server when system is ready. */ public void systemReady() { if (isNetdAlive()) { Log.d(TAG, "IpSecService is ready"); @@ -1229,7 +1230,7 @@ public class IpSecService extends IIpSecService.Stub { *

            Since the socket is created on behalf of an unprivileged application, all traffic * should be accounted to the UID of the unprivileged application. */ - public void tag(FileDescriptor fd, int uid) throws IOException; + void tag(FileDescriptor fd, int uid) throws IOException; } /** @@ -1771,7 +1772,7 @@ public class IpSecService extends IIpSecService.Stub { TransformRecord info = userRecord.mTransformRecords.getResourceOrThrow(resourceId); // TODO: make this a function. - if (info.pid != getCallingPid() || info.uid != callingUid) { + if (info.mPid != getCallingPid() || info.mUid != callingUid) { throw new SecurityException("Only the owner of an IpSec Transform may apply it!"); } From 92b7afc77705719bb45960c91da6bd119f6c5018 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Sat, 27 Nov 2021 00:30:35 +0800 Subject: [PATCH 0991/1150] Refactor IpSecServiceConfiguration to Dependencies IpSecService is going to be moved into ConnectivityService module, so the hidden API usage should be removed. NetdService.getNetdInstance is a hidden API, therefore the alternative is to get the instance by Context.getSystemService. Bug: 204153604 Test: FrameworksNetTests Change-Id: I1bd8efc03c37654d12a8eadd3e78ed45e10b5691 --- .../src/com/android/server/IpSecService.java | 99 ++++++++++--------- 1 file changed, 54 insertions(+), 45 deletions(-) diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index dfc57c136f..f251b86b7a 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -119,6 +119,7 @@ public class IpSecService extends IIpSecService.Stub { /* Binder context for this service */ private final Context mContext; + private final Dependencies mDeps; /** * The next non-repeating global ID for tracking resources between users, this service, and @@ -129,23 +130,24 @@ public class IpSecService extends IIpSecService.Stub { @GuardedBy("IpSecService.this") private int mNextResourceId = 1; - interface IpSecServiceConfiguration { - INetd getNetdInstance() throws RemoteException; - - IpSecServiceConfiguration GETSRVINSTANCE = - new IpSecServiceConfiguration() { - @Override - public INetd getNetdInstance() throws RemoteException { - final INetd netd = NetdService.getInstance(); - if (netd == null) { - throw new RemoteException("Failed to Get Netd Instance"); - } - return netd; - } - }; + /** + * Dependencies of IpSecService, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /** + * Get a reference to INetd. + */ + public INetd getNetdInstance(Context context) throws RemoteException { + final INetd netd = INetd.Stub.asInterface((IBinder) + context.getSystemService(Context.NETD_SERVICE)); + if (netd == null) { + throw new RemoteException("Failed to Get Netd Instance"); + } + return netd; + } } - private final IpSecServiceConfiguration mSrvConfig; final UidFdTagger mUidFdTagger; /** @@ -625,8 +627,8 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { int spi = mSpi.getSpi(); try { - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecDeleteSecurityAssociation( mUid, mConfig.getSourceAddress(), @@ -678,11 +680,14 @@ public class IpSecService extends IIpSecService.Stub { private final String mSourceAddress; private final String mDestinationAddress; private int mSpi; + private final Context mContext; private boolean mOwnedByTransform = false; - SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) { + SpiRecord(Context context, int resourceId, String sourceAddress, + String destinationAddress, int spi) { super(resourceId); + mContext = context; mSourceAddress = sourceAddress; mDestinationAddress = destinationAddress; mSpi = spi; @@ -693,8 +698,8 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { try { if (!mOwnedByTransform) { - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecDeleteSecurityAssociation( mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, 0 /* mask */, 0 /* if_id */); @@ -816,8 +821,10 @@ public class IpSecService extends IIpSecService.Stub { private final int mIfId; private Network mUnderlyingNetwork; + private final Context mContext; TunnelInterfaceRecord( + Context context, int resourceId, String interfaceName, Network underlyingNetwork, @@ -828,6 +835,7 @@ public class IpSecService extends IIpSecService.Stub { int intfId) { super(resourceId); + mContext = context; mInterfaceName = interfaceName; mUnderlyingNetwork = underlyingNetwork; mLocalAddress = localAddr; @@ -844,7 +852,7 @@ public class IpSecService extends IIpSecService.Stub { // Teardown VTI // Delete global policies try { - final INetd netd = mSrvConfig.getNetdInstance(); + final INetd netd = mDeps.getNetdInstance(mContext); netd.ipSecRemoveTunnelInterface(mInterfaceName); for (int selAddrFamily : ADDRESS_FAMILIES) { @@ -1012,7 +1020,7 @@ public class IpSecService extends IIpSecService.Stub { * @param context Binder context for this service */ private IpSecService(Context context) { - this(context, IpSecServiceConfiguration.GETSRVINSTANCE); + this(context, new Dependencies()); } static IpSecService create(Context context) @@ -1031,10 +1039,10 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, IpSecServiceConfiguration config) { + public IpSecService(Context context, Dependencies deps) { this( context, - config, + deps, (fd, uid) -> { try { TrafficStats.setThreadStatsUid(uid); @@ -1047,10 +1055,9 @@ public class IpSecService extends IIpSecService.Stub { /** @hide */ @VisibleForTesting - public IpSecService(Context context, IpSecServiceConfiguration config, - UidFdTagger uidFdTagger) { + public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) { mContext = context; - mSrvConfig = config; + mDeps = deps; mUidFdTagger = uidFdTagger; } @@ -1077,7 +1084,7 @@ public class IpSecService extends IIpSecService.Stub { synchronized boolean isNetdAlive() { try { - final INetd netd = mSrvConfig.getNetdInstance(); + final INetd netd = mDeps.getNetdInstance(mContext); if (netd == null) { return false; } @@ -1143,14 +1150,15 @@ public class IpSecService extends IIpSecService.Stub { } spi = - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, new RefcountedResource( - new SpiRecord(resourceId, "", destinationAddress, spi), binder)); + new SpiRecord(mContext, resourceId, "", + destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { if (e.errorCode == OsConstants.ENOENT) { return new IpSecSpiResponse( @@ -1267,7 +1275,7 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mSrvConfig.getNetdInstance().ipSecSetEncapSocketOwner( + mDeps.getNetdInstance(mContext).ipSecSetEncapSocketOwner( new ParcelFileDescriptor(sockFd), callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); @@ -1330,7 +1338,7 @@ public class IpSecService extends IIpSecService.Stub { // Create VTI // Add inbound/outbound global policies // (use reqid = 0) - final INetd netd = mSrvConfig.getNetdInstance(); + final INetd netd = mDeps.getNetdInstance(mContext); netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); BinderUtils.withCleanCallingIdentity(() -> { @@ -1385,6 +1393,7 @@ public class IpSecService extends IIpSecService.Stub { resourceId, new RefcountedResource( new TunnelInterfaceRecord( + mContext, resourceId, intfName, underlyingNetwork, @@ -1426,8 +1435,8 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .interfaceAddAddress( tunnelInterfaceInfo.mInterfaceName, localAddr.getAddress().getHostAddress(), @@ -1455,8 +1464,8 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .interfaceDelAddress( tunnelInterfaceInfo.mInterfaceName, localAddr.getAddress().getHostAddress(), @@ -1670,8 +1679,8 @@ public class IpSecService extends IIpSecService.Stub { cryptName = crypt.getName(); } - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecAddSecurityAssociation( Binder.getCallingUid(), c.getMode(), @@ -1782,8 +1791,8 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecApplyTransportModeTransform( socket, callingUid, @@ -1802,8 +1811,8 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecRemoveTransportModeTransform(socket); } @@ -1879,8 +1888,8 @@ public class IpSecService extends IIpSecService.Stub { // Always update the policy with the relevant XFRM_IF_ID for (int selAddrFamily : ADDRESS_FAMILIES) { - mSrvConfig - .getNetdInstance() + mDeps + .getNetdInstance(mContext) .ipSecUpdateSecurityPolicy( callingUid, selAddrFamily, From 0aab7c039dcf6582ae52c445cd755cd270a8a65b Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 14 Dec 2021 23:09:55 +0800 Subject: [PATCH 0992/1150] Split out the nsd API surface and use framework-connectivity-tiramisu - Split out nsd APIs and hidden APIs to Connectivity module. - Keep the all files in f/b/packages/Connectivity-T and add framework-connectivity-tiramisu library on p/m/Connectivity. Then make framework to use this module library. - Remove NsdService from SystemServer which will register from ConnectivityServiceInitializer Bug: 206893064 Test: m online-sdk-dev-docs Test: atest FrameworksNetTests CtsNetTestCases CTS-Coverage-Bug: 207804007 Change-Id: I72c7de124b9cc53f2263bd452ecd5f39e88e485b --- framework-t/Sources.bp | 14 ++++++++++++-- service-t/Sources.bp | 12 +++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 931a55b27d..9319e8af95 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -132,8 +132,18 @@ filegroup { srcs: [ ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", - ":framework-connectivity-nsd-sources", - ":framework-connectivity-tiramisu-internal-sources", ], visibility: ["//frameworks/base"], } + +filegroup { + name: "framework-connectivity-tiramisu-updatable-sources", + srcs: [ + ":framework-connectivity-nsd-sources", + ":framework-connectivity-tiramisu-internal-sources", + ], + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +} diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 7b8817692b..422fc43ee4 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -68,8 +68,18 @@ filegroup { srcs: [ ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", - ":services.connectivity-nsd-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], } + +filegroup { + name: "services.connectivity-tiramisu-updatable-sources", + srcs: [ + ":services.connectivity-nsd-sources", + ], + path: "src", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} From f318d55576d449a811e82bffa80cdc836127ec9f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 29 Nov 2021 16:31:32 +0800 Subject: [PATCH 0993/1150] Remove NetdService usage from IpSecService IpSecService is going to be moved into ConnectivityService module. So, NetdService won't be visible to IpSecService since it is a hidden class. NetdService.get(timeout) is a method that blocks for specified time until INetd instance is available. In SystemServer IpSecService is created after NetworkManagementService and NMS uses NetdService.get() to get INetd instance which is a method that blocks until an INetd instance is available. Thus, connectNativeNetdService can be removed because NMS already waits for INetd instance is available so IpSecService should be able to get INetd instance immediately. Bug: 204153604 Test: FrameworksNetTest Change-Id: I007cb28de63783d60084f93dddb4de78faa0e868 --- .../src/com/android/server/IpSecService.java | 194 +++++++----------- 1 file changed, 78 insertions(+), 116 deletions(-) diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index f251b86b7a..d1e432e80f 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -45,7 +45,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; import android.net.TrafficStats; -import android.net.util.NetdService; import android.os.Binder; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -96,8 +95,6 @@ import java.util.Objects; public class IpSecService extends IIpSecService.Stub { private static final String TAG = "IpSecService"; private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG); - - private static final String NETD_SERVICE_NAME = "netd"; private static final int[] ADDRESS_FAMILIES = new int[] {OsConstants.AF_INET, OsConstants.AF_INET6}; @@ -106,6 +103,8 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10; + private final INetd mNetd; + static { try { INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0}); @@ -627,16 +626,14 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { int spi = mSpi.getSpi(); try { - mDeps - .getNetdInstance(mContext) - .ipSecDeleteSecurityAssociation( - mUid, - mConfig.getSourceAddress(), - mConfig.getDestinationAddress(), - spi, - mConfig.getMarkValue(), - mConfig.getMarkMask(), - mConfig.getXfrmInterfaceId()); + mNetd.ipSecDeleteSecurityAssociation( + mUid, + mConfig.getSourceAddress(), + mConfig.getDestinationAddress(), + spi, + mConfig.getMarkValue(), + mConfig.getMarkMask(), + mConfig.getXfrmInterfaceId()); } catch (RemoteException | ServiceSpecificException e) { Log.e(TAG, "Failed to delete SA with ID: " + mResourceId, e); } @@ -680,14 +677,12 @@ public class IpSecService extends IIpSecService.Stub { private final String mSourceAddress; private final String mDestinationAddress; private int mSpi; - private final Context mContext; private boolean mOwnedByTransform = false; - SpiRecord(Context context, int resourceId, String sourceAddress, + SpiRecord(int resourceId, String sourceAddress, String destinationAddress, int spi) { super(resourceId); - mContext = context; mSourceAddress = sourceAddress; mDestinationAddress = destinationAddress; mSpi = spi; @@ -698,11 +693,9 @@ public class IpSecService extends IIpSecService.Stub { public void freeUnderlyingResources() { try { if (!mOwnedByTransform) { - mDeps - .getNetdInstance(mContext) - .ipSecDeleteSecurityAssociation( - mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, - 0 /* mask */, 0 /* if_id */); + mNetd.ipSecDeleteSecurityAssociation( + mUid, mSourceAddress, mDestinationAddress, mSpi, 0 /* mark */, + 0 /* mask */, 0 /* if_id */); } } catch (ServiceSpecificException | RemoteException e) { Log.e(TAG, "Failed to delete SPI reservation with ID: " + mResourceId, e); @@ -821,10 +814,8 @@ public class IpSecService extends IIpSecService.Stub { private final int mIfId; private Network mUnderlyingNetwork; - private final Context mContext; TunnelInterfaceRecord( - Context context, int resourceId, String interfaceName, Network underlyingNetwork, @@ -835,7 +826,6 @@ public class IpSecService extends IIpSecService.Stub { int intfId) { super(resourceId); - mContext = context; mInterfaceName = interfaceName; mUnderlyingNetwork = underlyingNetwork; mLocalAddress = localAddr; @@ -852,18 +842,17 @@ public class IpSecService extends IIpSecService.Stub { // Teardown VTI // Delete global policies try { - final INetd netd = mDeps.getNetdInstance(mContext); - netd.ipSecRemoveTunnelInterface(mInterfaceName); + mNetd.ipSecRemoveTunnelInterface(mInterfaceName); for (int selAddrFamily : ADDRESS_FAMILIES) { - netd.ipSecDeleteSecurityPolicy( + mNetd.ipSecDeleteSecurityPolicy( mUid, selAddrFamily, IpSecManager.DIRECTION_OUT, mOkey, 0xffffffff, mIfId); - netd.ipSecDeleteSecurityPolicy( + mNetd.ipSecDeleteSecurityPolicy( mUid, selAddrFamily, IpSecManager.DIRECTION_IN, @@ -1026,7 +1015,6 @@ public class IpSecService extends IIpSecService.Stub { static IpSecService create(Context context) throws InterruptedException { final IpSecService service = new IpSecService(context); - service.connectNativeNetdService(); return service; } @@ -1057,8 +1045,13 @@ public class IpSecService extends IIpSecService.Stub { @VisibleForTesting public IpSecService(Context context, Dependencies deps, UidFdTagger uidFdTagger) { mContext = context; - mDeps = deps; + mDeps = Objects.requireNonNull(deps, "Missing dependencies."); mUidFdTagger = uidFdTagger; + try { + mNetd = mDeps.getNetdInstance(mContext); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } } /** Called by system server when system is ready. */ @@ -1070,25 +1063,12 @@ public class IpSecService extends IIpSecService.Stub { } } - private void connectNativeNetdService() { - // Avoid blocking the system server to do this - new Thread() { - @Override - public void run() { - synchronized (IpSecService.this) { - NetdService.get(NETD_FETCH_TIMEOUT_MS); - } - } - }.start(); - } - synchronized boolean isNetdAlive() { try { - final INetd netd = mDeps.getNetdInstance(mContext); - if (netd == null) { + if (mNetd == null) { return false; } - return netd.isAlive(); + return mNetd.isAlive(); } catch (RemoteException re) { return false; } @@ -1149,15 +1129,12 @@ public class IpSecService extends IIpSecService.Stub { IpSecManager.Status.RESOURCE_UNAVAILABLE, INVALID_RESOURCE_ID, spi); } - spi = - mDeps - .getNetdInstance(mContext) - .ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); + spi = mNetd.ipSecAllocateSpi(callingUid, "", destinationAddress, requestedSpi); Log.d(TAG, "Allocated SPI " + spi); userRecord.mSpiRecords.put( resourceId, new RefcountedResource( - new SpiRecord(mContext, resourceId, "", + new SpiRecord(resourceId, "", destinationAddress, spi), binder)); } catch (ServiceSpecificException e) { if (e.errorCode == OsConstants.ENOENT) { @@ -1275,8 +1252,7 @@ public class IpSecService extends IIpSecService.Stub { OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mDeps.getNetdInstance(mContext).ipSecSetEncapSocketOwner( - new ParcelFileDescriptor(sockFd), callingUid); + mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); Os.bind(sockFd, INADDR_ANY, port); @@ -1338,16 +1314,15 @@ public class IpSecService extends IIpSecService.Stub { // Create VTI // Add inbound/outbound global policies // (use reqid = 0) - final INetd netd = mDeps.getNetdInstance(mContext); - netd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); + mNetd.ipSecAddTunnelInterface(intfName, localAddr, remoteAddr, ikey, okey, resourceId); BinderUtils.withCleanCallingIdentity(() -> { - NetdUtils.setInterfaceUp(netd, intfName); + NetdUtils.setInterfaceUp(mNetd, intfName); }); for (int selAddrFamily : ADDRESS_FAMILIES) { // Always send down correct local/remote addresses for template. - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_OUT, @@ -1357,7 +1332,7 @@ public class IpSecService extends IIpSecService.Stub { okey, 0xffffffff, resourceId); - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_IN, @@ -1377,7 +1352,7 @@ public class IpSecService extends IIpSecService.Stub { // // This is necessary only on the tunnel interface, and not any the interface to // which traffic will be forwarded to. - netd.ipSecAddSecurityPolicy( + mNetd.ipSecAddSecurityPolicy( callerUid, selAddrFamily, IpSecManager.DIRECTION_FWD, @@ -1393,7 +1368,6 @@ public class IpSecService extends IIpSecService.Stub { resourceId, new RefcountedResource( new TunnelInterfaceRecord( - mContext, resourceId, intfName, underlyingNetwork, @@ -1435,12 +1409,10 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mDeps - .getNetdInstance(mContext) - .interfaceAddAddress( - tunnelInterfaceInfo.mInterfaceName, - localAddr.getAddress().getHostAddress(), - localAddr.getPrefixLength()); + mNetd.interfaceAddAddress( + tunnelInterfaceInfo.mInterfaceName, + localAddr.getAddress().getHostAddress(), + localAddr.getPrefixLength()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1464,9 +1436,7 @@ public class IpSecService extends IIpSecService.Stub { try { // We can assume general validity of the IP address, since we get them as a // LinkAddress, which does some validation. - mDeps - .getNetdInstance(mContext) - .interfaceDelAddress( + mNetd.interfaceDelAddress( tunnelInterfaceInfo.mInterfaceName, localAddr.getAddress().getHostAddress(), localAddr.getPrefixLength()); @@ -1679,30 +1649,28 @@ public class IpSecService extends IIpSecService.Stub { cryptName = crypt.getName(); } - mDeps - .getNetdInstance(mContext) - .ipSecAddSecurityAssociation( - Binder.getCallingUid(), - c.getMode(), - c.getSourceAddress(), - c.getDestinationAddress(), - (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, - spiRecord.getSpi(), - c.getMarkValue(), - c.getMarkMask(), - (auth != null) ? auth.getName() : "", - (auth != null) ? auth.getKey() : new byte[] {}, - (auth != null) ? auth.getTruncationLengthBits() : 0, - cryptName, - (crypt != null) ? crypt.getKey() : new byte[] {}, - (crypt != null) ? crypt.getTruncationLengthBits() : 0, - (authCrypt != null) ? authCrypt.getName() : "", - (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, - (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, - encapType, - encapLocalPort, - encapRemotePort, - c.getXfrmInterfaceId()); + mNetd.ipSecAddSecurityAssociation( + Binder.getCallingUid(), + c.getMode(), + c.getSourceAddress(), + c.getDestinationAddress(), + (c.getNetwork() != null) ? c.getNetwork().getNetId() : 0, + spiRecord.getSpi(), + c.getMarkValue(), + c.getMarkMask(), + (auth != null) ? auth.getName() : "", + (auth != null) ? auth.getKey() : new byte[] {}, + (auth != null) ? auth.getTruncationLengthBits() : 0, + cryptName, + (crypt != null) ? crypt.getKey() : new byte[] {}, + (crypt != null) ? crypt.getTruncationLengthBits() : 0, + (authCrypt != null) ? authCrypt.getName() : "", + (authCrypt != null) ? authCrypt.getKey() : new byte[] {}, + (authCrypt != null) ? authCrypt.getTruncationLengthBits() : 0, + encapType, + encapLocalPort, + encapRemotePort, + c.getXfrmInterfaceId()); } /** @@ -1791,15 +1759,13 @@ public class IpSecService extends IIpSecService.Stub { c.getMode() == IpSecTransform.MODE_TRANSPORT, "Transform mode was not Transport mode; cannot be applied to a socket"); - mDeps - .getNetdInstance(mContext) - .ipSecApplyTransportModeTransform( - socket, - callingUid, - direction, - c.getSourceAddress(), - c.getDestinationAddress(), - info.getSpiRecord().getSpi()); + mNetd.ipSecApplyTransportModeTransform( + socket, + callingUid, + direction, + c.getSourceAddress(), + c.getDestinationAddress(), + info.getSpiRecord().getSpi()); } /** @@ -1811,9 +1777,7 @@ public class IpSecService extends IIpSecService.Stub { @Override public synchronized void removeTransportModeTransforms(ParcelFileDescriptor socket) throws RemoteException { - mDeps - .getNetdInstance(mContext) - .ipSecRemoveTransportModeTransform(socket); + mNetd.ipSecRemoveTransportModeTransform(socket); } /** @@ -1888,18 +1852,16 @@ public class IpSecService extends IIpSecService.Stub { // Always update the policy with the relevant XFRM_IF_ID for (int selAddrFamily : ADDRESS_FAMILIES) { - mDeps - .getNetdInstance(mContext) - .ipSecUpdateSecurityPolicy( - callingUid, - selAddrFamily, - direction, - transformInfo.getConfig().getSourceAddress(), - transformInfo.getConfig().getDestinationAddress(), - spi, // If outbound, also add SPI to the policy. - mark, // Must always set policy mark; ikey/okey for VTIs - 0xffffffff, - c.getXfrmInterfaceId()); + mNetd.ipSecUpdateSecurityPolicy( + callingUid, + selAddrFamily, + direction, + transformInfo.getConfig().getSourceAddress(), + transformInfo.getConfig().getDestinationAddress(), + spi, // If outbound, also add SPI to the policy. + mark, // Must always set policy mark; ikey/okey for VTIs + 0xffffffff, + c.getXfrmInterfaceId()); } // Update SA with tunnel mark (ikey or okey based on direction) From e6ab4493c6fc9e2a5af68b16cdb4b047edf6b048 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 9 Dec 2021 16:18:06 +0800 Subject: [PATCH 0994/1150] Remove isUnsafeBuild() from IpSecAlgorithm IpSec is going to move to Connectivity mainline module so hidden API usage should be removed. There's no formal API could be an alternative for Build.IS_ENG. Considering isUnsafeBuild() is not a really helpful method because it only prints the log in eng build. Therefore, remove it. Bug: 204153604 Test: FrameworksNetTests Change-Id: Ic354e12423629b0d72e8087843893953a0c8c465 --- framework-t/src/android/net/IpSecAlgorithm.java | 8 -------- 1 file changed, 8 deletions(-) diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java index 840af28b77..5e647fe2f9 100644 --- a/framework-t/src/android/net/IpSecAlgorithm.java +++ b/framework-t/src/android/net/IpSecAlgorithm.java @@ -469,20 +469,12 @@ public final class IpSecAlgorithm implements Parcelable { } } - // Because encryption keys are sensitive and userdebug builds are used by large user pools - // such as beta testers, we only allow sensitive info such as keys on eng builds. - private static boolean isUnsafeBuild() { - return Build.IS_DEBUGGABLE && Build.IS_ENG; - } - @Override @NonNull public String toString() { return new StringBuilder() .append("{mName=") .append(mName) - .append(", mKey=") - .append(isUnsafeBuild() ? HexDump.toHexString(mKey) : "") .append(", mTruncLenBits=") .append(mTruncLenBits) .append("}") From e82600c40cbf92c5a61f893ceb6b524628e17b1f Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Tue, 7 Dec 2021 20:01:45 +0000 Subject: [PATCH 0995/1150] Migrate unsafe parcel APIs in framework-minus-apex Migrate the following unsafe parcel APIs in framework-minus-apex: * Parcel.readSerializable() * Parcel.readArrayList() * Parcel.readList() * Parcel.readParcelable() * Parcel.readParcelableList() * Parcel.readSparseArray() This CL was generated by applying lint fixes that infer the expected type from the caller code and provide that as the type parameter (ag/16365240). A few observations: * In some classes we couldn't migrate because the class also belonged to another build module whose min SDK wasn't current (as is the case for framework-minus-apex), hence I suppressed the lint check (since I'll eventually submit the lint check to the tree). * In some cases, I needed to do the cast in https://stackoverflow.com/a/1080525/5765705 to make the compiler happy since there isn't another way of providing a class of type Class>. * In the readSerializable() case, the new API also requires the class loader, that was inferred to by InferredClass.class.getClassLoader(). * Note that automatic formatting and import rely on running hooked up to the IDE, which wasn't the case here. Bug: 195622897 Test: TH passes Change-Id: I11a27b9bdab7959ee86e90aa1e1cbebd7aaf883c --- framework-t/src/android/net/DataUsageRequest.java | 2 +- framework-t/src/android/net/IpSecConfig.java | 8 ++++---- framework-t/src/android/net/IpSecUdpEncapResponse.java | 2 +- framework-t/src/android/net/NetworkStateSnapshot.java | 6 +++--- framework-t/src/android/net/UnderlyingNetworkInfo.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/net/DataUsageRequest.java b/framework-t/src/android/net/DataUsageRequest.java index b06d515b3a..f0ff46522d 100644 --- a/framework-t/src/android/net/DataUsageRequest.java +++ b/framework-t/src/android/net/DataUsageRequest.java @@ -75,7 +75,7 @@ public final class DataUsageRequest implements Parcelable { @Override public DataUsageRequest createFromParcel(Parcel in) { int requestId = in.readInt(); - NetworkTemplate template = in.readParcelable(null); + NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class); long thresholdInBytes = in.readLong(); DataUsageRequest result = new DataUsageRequest(requestId, template, thresholdInBytes); diff --git a/framework-t/src/android/net/IpSecConfig.java b/framework-t/src/android/net/IpSecConfig.java index 575c5ed968..03bb187f11 100644 --- a/framework-t/src/android/net/IpSecConfig.java +++ b/framework-t/src/android/net/IpSecConfig.java @@ -267,14 +267,14 @@ public final class IpSecConfig implements Parcelable { mMode = in.readInt(); mSourceAddress = in.readString(); mDestinationAddress = in.readString(); - mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); + mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class); mSpiResourceId = in.readInt(); mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); diff --git a/framework-t/src/android/net/IpSecUdpEncapResponse.java b/framework-t/src/android/net/IpSecUdpEncapResponse.java index 4e7ba9b515..4910b62646 100644 --- a/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ b/framework-t/src/android/net/IpSecUdpEncapResponse.java @@ -80,7 +80,7 @@ public final class IpSecUdpEncapResponse implements Parcelable { status = in.readInt(); resourceId = in.readInt(); port = in.readInt(); - fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR = diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java index 3915634392..d577aa8fba 100644 --- a/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/framework-t/src/android/net/NetworkStateSnapshot.java @@ -73,9 +73,9 @@ public final class NetworkStateSnapshot implements Parcelable { /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - mNetwork = in.readParcelable(null); - mNetworkCapabilities = in.readParcelable(null); - mLinkProperties = in.readParcelable(null); + mNetwork = in.readParcelable(null, android.net.Network.class); + mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class); + mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class); mSubscriberId = in.readString(); mLegacyType = in.readInt(); } diff --git a/framework-t/src/android/net/UnderlyingNetworkInfo.java b/framework-t/src/android/net/UnderlyingNetworkInfo.java index 33f9375c03..7ab53b1da8 100644 --- a/framework-t/src/android/net/UnderlyingNetworkInfo.java +++ b/framework-t/src/android/net/UnderlyingNetworkInfo.java @@ -60,7 +60,7 @@ public final class UnderlyingNetworkInfo implements Parcelable { mOwnerUid = in.readInt(); mIface = in.readString(); List underlyingIfaces = new ArrayList<>(); - in.readList(underlyingIfaces, null /*classLoader*/); + in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class); mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); } From d3d8f41f2bc0595a634d16177b1ea5819dd55637 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 14 Dec 2021 09:38:32 +0000 Subject: [PATCH 0996/1150] Move Ethernet related files to f/b/packages/ConnectivityT. ethernet-service is going to be moved into Connectivity mainline module. Move all ethernet related files in f/b/ to f/b/packages/ConnectivityT so that it's easier to migrate these files to Connectivity module finally after clearing the hidden API usages. Below files to be moved: Ethernet framework related files: - EthernetManager.java - EthernetNetworkSpecifier.java - IEthernetManager.aidl - IEthernetServiceListener.aidl - ITetheredInterfaceCallback.aidl Ethernet service related files: - IpConfigStore.java(EthernetConfigStore has dependency on the class) For the ethernet-service related files, keep it as-is temproraliy and fix the hiden API dependencies in f/opt/net/ethernet/. After this work is done, then migrating the whole of ethernet folder to Connectivity module completely. This CL also fixes some minor errors of code style format to pass the code style check. Bug: 210586283 Test: build pass atest FrameworksNetTests atest EthernetServiceTests Change-Id: Ib359d29d5221105f648bc4194c6d6dbe4cc6e3e5 --- framework-t/Sources.bp | 18 +++++++++++ .../src}/android/net/EthernetManager.java | 0 .../android/net/EthernetNetworkSpecifier.java | 0 .../src}/android/net/IEthernetManager.aidl | 0 .../android/net/IEthernetServiceListener.aidl | 0 .../net/ITetheredInterfaceCallback.aidl | 0 service-t/Sources.bp | 14 ++++++++ .../com/android/server/net/IpConfigStore.java | 32 +++++++++++++------ 8 files changed, 54 insertions(+), 10 deletions(-) rename {core/java => framework-t/src}/android/net/EthernetManager.java (100%) rename {core/java => framework-t/src}/android/net/EthernetNetworkSpecifier.java (100%) rename {core/java => framework-t/src}/android/net/IEthernetManager.aidl (100%) rename {core/java => framework-t/src}/android/net/IEthernetServiceListener.aidl (100%) rename {core/java => framework-t/src}/android/net/ITetheredInterfaceCallback.aidl (100%) rename {services/core/java => service-t/src}/com/android/server/net/IpConfigStore.java (95%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 931a55b27d..0bda923f23 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -114,6 +114,23 @@ filegroup { ], } +// Ethernet related libraries. + +filegroup { + name: "framework-connectivity-ethernet-sources", + srcs: [ + "src/android/net/EthernetManager.java", + "src/android/net/EthernetNetworkSpecifier.java", + "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/ITetheredInterfaceCallback.aidl", + ], + path: "src", + visibility: [ + "//visibility:private", + ], +} + // Connectivity-T common libraries. filegroup { @@ -130,6 +147,7 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ + ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", diff --git a/core/java/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java similarity index 100% rename from core/java/android/net/EthernetManager.java rename to framework-t/src/android/net/EthernetManager.java diff --git a/core/java/android/net/EthernetNetworkSpecifier.java b/framework-t/src/android/net/EthernetNetworkSpecifier.java similarity index 100% rename from core/java/android/net/EthernetNetworkSpecifier.java rename to framework-t/src/android/net/EthernetNetworkSpecifier.java diff --git a/core/java/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl similarity index 100% rename from core/java/android/net/IEthernetManager.aidl rename to framework-t/src/android/net/IEthernetManager.aidl diff --git a/core/java/android/net/IEthernetServiceListener.aidl b/framework-t/src/android/net/IEthernetServiceListener.aidl similarity index 100% rename from core/java/android/net/IEthernetServiceListener.aidl rename to framework-t/src/android/net/IEthernetServiceListener.aidl diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/framework-t/src/android/net/ITetheredInterfaceCallback.aidl similarity index 100% rename from core/java/android/net/ITetheredInterfaceCallback.aidl rename to framework-t/src/android/net/ITetheredInterfaceCallback.aidl diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 7b8817692b..97dfb64b33 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -61,11 +61,25 @@ filegroup { ], } +// Ethernet related libraries. + +filegroup { + name: "services.connectivity-ethernet-sources", + srcs: [ + "src/com/android/server/net/IpConfigStore.java", + ], + path: "src", + visibility: [ + "//frameworks/opt/net/ethernet", + ], +} + // Connectivity-T common libraries. filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ + ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/service-t/src/com/android/server/net/IpConfigStore.java similarity index 95% rename from services/core/java/com/android/server/net/IpConfigStore.java rename to service-t/src/com/android/server/net/IpConfigStore.java index d17dbde496..3a9a544155 100644 --- a/services/core/java/com/android/server/net/IpConfigStore.java +++ b/service-t/src/com/android/server/net/IpConfigStore.java @@ -44,6 +44,9 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.List; +/** + * This class provides an API to store and manage L3 network IP configuration. + */ public class IpConfigStore { private static final String TAG = "IpConfigStore"; private static final boolean DBG = false; @@ -78,6 +81,9 @@ public class IpConfigStore { return writeConfig(out, configKey, config, IPCONFIG_FILE_VERSION); } + /** + * Write the IP configuration with the given parameters to {@link DataOutputStream}. + */ @VisibleForTesting public static boolean writeConfig(DataOutputStream out, String configKey, IpConfiguration config, int version) throws IOException { @@ -154,10 +160,10 @@ public class IpConfigStore { break; case UNASSIGNED: /* Ignore */ - break; - default: - loge("Ignore invalid proxy settings while writing"); - break; + break; + default: + loge("Ignore invalid proxy settings while writing"); + break; } if (written) { @@ -177,7 +183,7 @@ public class IpConfigStore { } /** - * @Deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. + * @deprecated use {@link #writeIpConfigurations(String, ArrayMap)} instead. * New method uses string as network identifier which could be interface name or MAC address or * other token. */ @@ -186,22 +192,28 @@ public class IpConfigStore { final SparseArray networks) { mWriter.write(filePath, out -> { out.writeInt(IPCONFIG_FILE_VERSION); - for(int i = 0; i < networks.size(); i++) { + for (int i = 0; i < networks.size(); i++) { writeConfig(out, String.valueOf(networks.keyAt(i)), networks.valueAt(i)); } }); } + /** + * Write the IP configuration associated to the target networks to the destination path. + */ public void writeIpConfigurations(String filePath, ArrayMap networks) { mWriter.write(filePath, out -> { out.writeInt(IPCONFIG_FILE_VERSION); - for(int i = 0; i < networks.size(); i++) { + for (int i = 0; i < networks.size(); i++) { writeConfig(out, networks.keyAt(i), networks.valueAt(i)); } }); } + /** + * Read the IP configuration from the destination path to {@link BufferedInputStream}. + */ public static ArrayMap readIpConfigurations(String filePath) { BufferedInputStream bufferedInputStream; try { @@ -215,7 +227,7 @@ public class IpConfigStore { return readIpConfigurations(bufferedInputStream); } - /** @Deprecated use {@link #readIpConfigurations(String)} */ + /** @deprecated use {@link #readIpConfigurations(String)} */ @Deprecated public static SparseArray readIpAndProxyConfigurations(String filePath) { BufferedInputStream bufferedInputStream; @@ -230,7 +242,7 @@ public class IpConfigStore { return readIpAndProxyConfigurations(bufferedInputStream); } - /** @Deprecated use {@link #readIpConfigurations(InputStream)} */ + /** @deprecated use {@link #readIpConfigurations(InputStream)} */ @Deprecated public static SparseArray readIpAndProxyConfigurations( InputStream inputStream) { @@ -420,7 +432,7 @@ public class IpConfigStore { if (in != null) { try { in.close(); - } catch (Exception e) {} + } catch (Exception e) { } } } From a2a6b960a38f06564a78398cb4c4704f4bffd02d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 14 Dec 2021 21:16:09 +0800 Subject: [PATCH 0997/1150] Remove unused import in IpSecAlgorithm HexDump is an internal class which cannot be visible to mainline module. Remove it since this is unused. Bug: 204153604 Test: FrameworksNetTests Change-Id: Ie65e7eff8464487719c3124005a097a500ba21c6 --- framework-t/src/android/net/IpSecAlgorithm.java | 1 - 1 file changed, 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java index 5e647fe2f9..a84e7a9c63 100644 --- a/framework-t/src/android/net/IpSecAlgorithm.java +++ b/framework-t/src/android/net/IpSecAlgorithm.java @@ -23,7 +23,6 @@ import android.os.Parcel; import android.os.Parcelable; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.HexDump; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; From 30a2b03042e26b9d42919e61f005fe3e1be8884f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 15 Dec 2021 23:27:18 +0800 Subject: [PATCH 0998/1150] Make IpSecManager.DIRECTION_FWD @SystemApi IpSecManager.DIRECTION_FWD is used by VcnGatewayConnection and it will be not visible to platform after IpSec was moved into Connectivity mainline module. Therefore, make DIRECTION_FWD @SystemApi so that it can be used by VcnGatewayConnection. Bug: 204153604 Test: FrameworksNetTests Change-Id: I80dc2a5b4940504820cee0d8e2d2e59ef3fcca18 --- framework-t/src/android/net/IpSecManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index 837629911c..0b266b226c 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -86,6 +86,7 @@ public final class IpSecManager { * * @hide */ + @SystemApi(client = MODULE_LIBRARIES) public static final int DIRECTION_FWD = 2; /** From 051de2cd49d1d134c8918d15a2eb87ad21d6ac16 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 17 Dec 2021 08:37:27 +0000 Subject: [PATCH 0999/1150] [MS05] Fix NetworkTemplate lint errors This change also defines some IntDef annotations that will be used in the follow-up CLs. Test: TH Bug: 204830222 Change-Id: Iba5e714a1304fdfd154379415dcc5d0f9b7b1b29 --- .../src/android/net/NetworkTemplate.java | 134 ++++++++++++++++-- 1 file changed, 126 insertions(+), 8 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 8b9c14df7d..cb5a025278 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -24,6 +24,8 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIFI_P2P; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.NetworkIdentity.OEM_NONE; +import static android.net.NetworkIdentity.OEM_PAID; +import static android.net.NetworkIdentity.OEM_PRIVATE; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; @@ -35,6 +37,7 @@ import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; import static android.net.wifi.WifiInfo.sanitizeSsid; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; @@ -48,6 +51,8 @@ import android.text.TextUtils; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; @@ -60,18 +65,58 @@ import java.util.Objects; * * @hide */ -public class NetworkTemplate implements Parcelable { - private static final String TAG = "NetworkTemplate"; +// @SystemApi(client = MODULE_LIBRARIES) +public final class NetworkTemplate implements Parcelable { + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "MATCH_" }, value = { + MATCH_MOBILE, + MATCH_WIFI, + MATCH_ETHERNET, + MATCH_BLUETOOTH, + MATCH_CARRIER + }) + public @interface TemplateMatchRule{} + /** Match rule to match cellular networks with given Subscriber Ids. */ public static final int MATCH_MOBILE = 1; + /** Match rule to match wifi networks. */ public static final int MATCH_WIFI = 4; + /** Match rule to match ethernet networks. */ public static final int MATCH_ETHERNET = 5; + /** + * Match rule to match all cellular networks. + * + * @hide + */ public static final int MATCH_MOBILE_WILDCARD = 6; + /** + * Match rule to match all wifi networks. + * + * @hide + */ public static final int MATCH_WIFI_WILDCARD = 7; + /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; + /** + * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. + * + * @hide + */ public static final int MATCH_PROXY = 9; + /** + * Match rule to match all networks with subscriberId inside the template. Some carriers + * may offer non-cellular networks like WiFi, which will be matched by this rule. + */ public static final int MATCH_CARRIER = 10; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = { + SUBSCRIBER_ID_MATCH_RULE_EXACT, + SUBSCRIBER_ID_MATCH_RULE_ALL + }) + public @interface SubscriberIdMatchRule{} /** * Value of the match rule of the subscriberId to match networks with specific subscriberId. */ @@ -92,8 +137,6 @@ public class NetworkTemplate implements Parcelable { /** * Include all network types when filtering. This is meant to merge in with the * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. - * - * @hide */ public static final int NETWORK_TYPE_ALL = -1; /** @@ -106,21 +149,37 @@ public class NetworkTemplate implements Parcelable { */ public static final int NETWORK_TYPE_5G_NSA = -2; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "OEM_MANAGED_" }, value = { + OEM_MANAGED_ALL, + OEM_MANAGED_NO, + OEM_MANAGED_YES, + OEM_MANAGED_PAID, + OEM_MANAGED_PRIVATE + }) + public @interface OemManaged{} + /** * Value to match both OEM managed and unmanaged networks (all networks). - * @hide */ public static final int OEM_MANAGED_ALL = -1; /** * Value to match networks which are not OEM managed. - * @hide */ public static final int OEM_MANAGED_NO = OEM_NONE; /** * Value to match any OEM managed network. - * @hide */ public static final int OEM_MANAGED_YES = -2; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. + */ + public static final int OEM_MANAGED_PAID = OEM_PAID; + /** + * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. + */ + public static final int OEM_MANAGED_PRIVATE = OEM_PRIVATE; private static boolean isKnownMatchRule(final int rule) { switch (rule) { @@ -142,6 +201,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with * the given IMSI. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateMobileAll(String subscriberId) { @@ -152,6 +213,8 @@ public class NetworkTemplate implements Parcelable { * Template to match cellular networks with the given IMSI, {@code ratType} and * {@code metered}. Use {@link #NETWORK_TYPE_ALL} to include all network types when * filtering. See {@code TelephonyManager.NETWORK_TYPE_*}. + * + * @hide */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, @NetworkType int ratType, int metered) { @@ -168,6 +231,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match metered {@link ConnectivityManager#TYPE_MOBILE} networks, * regardless of IMSI. + * + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public static NetworkTemplate buildTemplateMobileWildcard() { @@ -177,6 +242,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, * regardless of SSID. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifiWildcard() { @@ -185,6 +252,7 @@ public class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_WIFI_WILDCARD, null, null); } + /** @hide */ @Deprecated @UnsupportedAppUsage public static NetworkTemplate buildTemplateWifi() { @@ -194,6 +262,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given SSID. + * + * @hide */ public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { Objects.requireNonNull(networkId); @@ -221,6 +291,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_ETHERNET} style * networks together. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate buildTemplateEthernet() { @@ -230,6 +302,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_BLUETOOTH} style * networks together. + * + * @hide */ public static NetworkTemplate buildTemplateBluetooth() { return new NetworkTemplate(MATCH_BLUETOOTH, null, null); @@ -238,6 +312,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to combine all {@link ConnectivityManager#TYPE_PROXY} style * networks together. + * + * @hide */ public static NetworkTemplate buildTemplateProxy() { return new NetworkTemplate(MATCH_PROXY, null, null); @@ -245,6 +321,8 @@ public class NetworkTemplate implements Parcelable { /** * Template to match all metered carrier networks with the given IMSI. + * + * @hide */ public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { Objects.requireNonNull(subscriberId); @@ -298,12 +376,14 @@ public class NetworkTemplate implements Parcelable { } } + /** @hide */ // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage public NetworkTemplate(int matchRule, String subscriberId, String networkId) { this(matchRule, subscriberId, new String[] { subscriberId }, networkId); } + /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId) { // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates @@ -316,6 +396,7 @@ public class NetworkTemplate implements Parcelable { OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); } + /** @hide */ // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, @@ -324,6 +405,7 @@ public class NetworkTemplate implements Parcelable { defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); } + /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) { @@ -360,7 +442,7 @@ public class NetworkTemplate implements Parcelable { } @Override - public void writeToParcel(Parcel dest, int flags) { + public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); @@ -448,6 +530,7 @@ public class NetworkTemplate implements Parcelable { } } + /** @hide */ public boolean isMatchRuleMobile() { switch (mMatchRule) { case MATCH_MOBILE: @@ -458,6 +541,12 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Check if the template can be persisted into disk. + * + * @hide + */ + // TODO: Move to the NetworkPolicy. public boolean isPersistable() { switch (mMatchRule) { case MATCH_MOBILE_WILDCARD: @@ -476,11 +565,18 @@ public class NetworkTemplate implements Parcelable { } } + /** + * Get match rule of the template. See {@code MATCH_*}. + */ @UnsupportedAppUsage public int getMatchRule() { return mMatchRule; } + /** + * Get subscriber Id of the template. + */ + @Nullable @UnsupportedAppUsage public String getSubscriberId() { return mSubscriberId; @@ -490,16 +586,25 @@ public class NetworkTemplate implements Parcelable { return mNetworkId; } + /** + * Get Subscriber Id Match Rule of the template. + */ public int getSubscriberIdMatchRule() { return mSubscriberIdMatchRule; } + /** + * Get meteredness filter of the template. + */ + @NetworkStats.Meteredness public int getMeteredness() { return mMetered; } /** * Test if given {@link NetworkIdentity} matches this template. + * + * @hide */ public boolean matches(NetworkIdentity ident) { if (!matchesMetered(ident)) return false; @@ -565,6 +670,8 @@ public class NetworkTemplate implements Parcelable { * Check if this template matches {@code subscriberId}. Returns true if this * template was created with {@code SUBSCRIBER_ID_MATCH_RULE_ALL}, or with a * {@code mMatchSubscriberIds} array that contains {@code subscriberId}. + * + * @hide */ public boolean matchesSubscriberId(@Nullable String subscriberId) { return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL @@ -599,10 +706,13 @@ public class NetworkTemplate implements Parcelable { * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. * * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + * + * @hide */ // TODO: 1. Consider move this to TelephonyManager if used by other modules. // 2. Consider make this configurable. // 3. Use TelephonyManager APIs when available. + // TODO: @SystemApi when ready. public static int getCollapsedRatType(int ratType) { switch (ratType) { case TelephonyManager.NETWORK_TYPE_GPRS: @@ -639,7 +749,10 @@ public class NetworkTemplate implements Parcelable { /** * Return all supported collapsed RAT types that could be returned by * {@link #getCollapsedRatType(int)}. + * + * @hide */ + // TODO: @SystemApi when ready. @NonNull public static final int[] getAllCollapsedRatTypes() { final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); @@ -779,6 +892,8 @@ public class NetworkTemplate implements Parcelable { * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. * TODO: remove and use {@link #normalize(NetworkTemplate, List)}. + * + * @hide */ @UnsupportedAppUsage public static NetworkTemplate normalize(NetworkTemplate template, String[] merged) { @@ -797,7 +912,10 @@ public class NetworkTemplate implements Parcelable { * For example, given an incoming template matching B, and the currently * active merge set [A,B], we'd return a new template that primarily matches * A, but also matches B. + * + * @hide */ + // TODO: @SystemApi when ready. public static NetworkTemplate normalize(NetworkTemplate template, List mergedList) { // Now there are several types of network which uses SubscriberId to store network // information. For instances: From 46429b7dedc44b3bcc9053d5016af9e2c78d6b1a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 13 Dec 2021 07:52:45 +0000 Subject: [PATCH 1000/1150] [MS10.1] Move multiplySafeByRational to NetworkStatsUtils Since NetworkStats related code will be moved to the module. multiplySafeByRational in the NetworkUtilsInternal cannot be accessed after that. Thus, create another utils class that will be moved with NetworkStats code and put the function into it. Test: atest NetworkStaticLibTests:com.android.net.moduletests.util.NetworkStatsUtilsTest Bug: 204830222 Change-Id: I96f3ac02e57b7325ed53988285770f478dee529e --- framework-t/src/android/net/NetworkStats.java | 2 +- framework-t/src/android/net/NetworkStatsCollection.java | 2 +- framework-t/src/android/net/NetworkStatsHistory.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index c7ffc19338..1986b83b12 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -16,7 +16,7 @@ package android.net; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.annotation.IntDef; import android.annotation.NonNull; diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 0d3b9ed4e3..8d1347e25b 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -30,7 +30,7 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.text.format.DateUtils.WEEK_IN_MILLIS; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index a875e1ad45..3eef4ee6f8 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -28,8 +28,8 @@ import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.net.NetworkUtilsInternal.multiplySafeByRational; import static com.android.internal.util.ArrayUtils.total; +import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; From 155cb5cced030f245f1b6602b72b49e18cdb91c7 Mon Sep 17 00:00:00 2001 From: lifr Date: Tue, 21 Dec 2021 11:07:02 +0800 Subject: [PATCH 1001/1150] [DU02]Remove DevicePolicyManagerInternal from NetworkStatsAccess NetworkStatsAccess is using DevicePolicyManagerInternal APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 207100745 Test: atest NetworkStatsAccessTest Change-Id: I0802148050869d92e1f09d1d657034380029f236 --- .../src/android/net/NetworkStatsAccess.java | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java index 3885a9e6d5..591605d952 100644 --- a/framework-t/src/android/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java @@ -24,7 +24,7 @@ import static android.net.TrafficStats.UID_TETHERING; import android.Manifest; import android.annotation.IntDef; import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManagerInternal; +import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; @@ -32,8 +32,6 @@ import android.os.Process; import android.os.UserHandle; import android.telephony.TelephonyManager; -import com.android.server.LocalServices; - import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -109,8 +107,7 @@ public final class NetworkStatsAccess { /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ public static @NetworkStatsAccess.Level int checkAccessLevel( Context context, int callingUid, String callingPackage) { - final DevicePolicyManagerInternal dpmi = LocalServices.getService( - DevicePolicyManagerInternal.class); + final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); boolean hasCarrierPrivileges; @@ -123,8 +120,9 @@ public final class NetworkStatsAccess { Binder.restoreCallingIdentity(token); } - final boolean isDeviceOwner = dpmi != null && dpmi.isActiveDeviceOwner(callingUid); + final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); final int appId = UserHandle.getAppId(callingUid); + if (hasCarrierPrivileges || isDeviceOwner || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { // Carrier-privileged apps and device owners, and the system (including the @@ -139,8 +137,8 @@ public final class NetworkStatsAccess { } //TODO(b/169395065) Figure out if this flow makes sense in Device Owner mode. - boolean isProfileOwner = dpmi != null && (dpmi.isActiveProfileOwner(callingUid) - || dpmi.isActiveDeviceOwner(callingUid)); + boolean isProfileOwner = mDpm != null && (mDpm.isProfileOwnerApp(callingPackage) + || mDpm.isDeviceOwnerApp(callingPackage)); if (isProfileOwner) { // Apps with the AppOps permission, profile owners, and apps with the privileged // permission can access data usage for all apps in this user/profile. From 2c9441062097bf3501caabb60e5c876b9b3f7d85 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 16 Dec 2021 02:07:21 +0000 Subject: [PATCH 1002/1150] [MS12.1] Support NetworkTemplate builder In current design, NeworkTemplate has a lot of buildTemplate* functions to create various type of templates. These functions do not have any flexibility to add any dimension. Thus, if there is a need to add a dimension, the typical ways are: 1. Add one parameter to the buildTemplate* function and change all callers. 2. Use the NetworkTemplate constructors directly. And add one more parameter if it doesn't fulfill the needs. These codes are painful to maintain in the future if they are exposed as system api since they are lack of flexibility. Thus, introduce a builder class to NetworkTemplate to address this problem. Test: atest NetworkTemplateTest Bug: 204830222 Change-Id: I49fab236bac392563b1290d69573ad1415fda734 --- .../src/android/net/NetworkTemplate.java | 294 +++++++++++++++++- 1 file changed, 277 insertions(+), 17 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index cb5a025278..7dd04c5d42 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -47,6 +47,7 @@ import android.os.Parcelable; import android.telephony.Annotation.NetworkType; import android.telephony.TelephonyManager; import android.text.TextUtils; +import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -58,6 +59,9 @@ import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Objects; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; /** * Predicate used to match {@link NetworkIdentity}, usually when collecting @@ -119,21 +123,31 @@ public final class NetworkTemplate implements Parcelable { public @interface SubscriberIdMatchRule{} /** * Value of the match rule of the subscriberId to match networks with specific subscriberId. + * + * @hide */ public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; /** * Value of the match rule of the subscriberId to match networks with any subscriberId which * includes null and non-null. + * + * @hide */ public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; - /** - * Wi-Fi Network ID is never supposed to be null (if it is, it is a bug that - * should be fixed), so it's not possible to want to match null vs - * non-null. Therefore it's fine to use null as a sentinel for Network ID. - */ + // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. + /** @hide */ public static final String WIFI_NETWORKID_ALL = null; + /** + * Wi-Fi Network Key is never supposed to be null (if it is, it is a bug that + * should be fixed), so it's not possible to want to match null vs + * non-null. Therefore it's fine to use null as a sentinel for Wifi Network Key. + * + * @hide + */ + public static final String WIFI_NETWORK_KEY_ALL = WIFI_NETWORKID_ALL; + /** * Include all network types when filtering. This is meant to merge in with the * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. @@ -278,7 +292,10 @@ public final class NetworkTemplate implements Parcelable { * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, * and IMSI. * - * Call with {@link #WIFI_NETWORKID_ALL} for {@code networkId} to get result regardless of SSID. + * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless + * of SSID. + * + * @hide */ public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, @Nullable String subscriberId) { @@ -345,6 +362,7 @@ public final class NetworkTemplate implements Parcelable { */ private final String[] mMatchSubscriberIds; + // TODO: Change variable name to match the Api surface. private final String mNetworkId; // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. @@ -361,14 +379,14 @@ public final class NetworkTemplate implements Parcelable { // Bitfield containing OEM network properties{@code NetworkIdentity#OEM_*}. private final int mOemManaged; - private void checkValidSubscriberIdMatchRule() { - switch (mMatchRule) { + private static void checkValidSubscriberIdMatchRule(int matchRule, int subscriberIdMatchRule) { + switch (matchRule) { case MATCH_MOBILE: case MATCH_CARRIER: // MOBILE and CARRIER templates must always specify a subscriber ID. - if (mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { - throw new IllegalArgumentException("Invalid SubscriberIdMatchRule" - + "on match rule: " + getMatchRuleName(mMatchRule)); + if (subscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " + + "on match rule: " + getMatchRuleName(matchRule)); } return; default: @@ -421,7 +439,7 @@ public final class NetworkTemplate implements Parcelable { mSubType = subType; mOemManaged = oemManaged; mSubscriberIdMatchRule = subscriberIdMatchRule; - checkValidSubscriberIdMatchRule(); + checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); if (!isKnownMatchRule(matchRule)) { throw new IllegalArgumentException("Unknown network template rule " + matchRule + " will not match any identity."); @@ -519,7 +537,7 @@ public final class NetworkTemplate implements Parcelable { return false; } - private String subscriberIdMatchRuleToString(int rule) { + private static String subscriberIdMatchRuleToString(int rule) { switch (rule) { case SUBSCRIBER_ID_MATCH_RULE_EXACT: return "EXACT_MATCH"; @@ -555,7 +573,7 @@ public final class NetworkTemplate implements Parcelable { case MATCH_CARRIER: return mSubscriberId != null; case MATCH_WIFI: - if (Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + if (Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL) && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { return false; } @@ -570,7 +588,16 @@ public final class NetworkTemplate implements Parcelable { */ @UnsupportedAppUsage public int getMatchRule() { - return mMatchRule; + // Wildcard rules are not exposed. For external callers, convert wildcard rules to + // exposed rules before returning. + switch (mMatchRule) { + case MATCH_MOBILE_WILDCARD: + return MATCH_MOBILE; + case MATCH_WIFI_WILDCARD: + return MATCH_WIFI; + default: + return mMatchRule; + } } /** @@ -582,12 +609,33 @@ public final class NetworkTemplate implements Parcelable { return mSubscriberId; } + /** + * Get set of subscriber Ids of the template. + */ + @NonNull + public Set getSubscriberIds() { + return new ArraySet<>(Arrays.asList(mMatchSubscriberIds)); + } + + /** + * Get Wifi Network Key of the template. See {@link WifiInfo#getCurrentNetworkKey()}. + */ + @Nullable + public String getWifiNetworkKey() { + return mNetworkId; + } + + /** @hide */ + // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}. + @Nullable public String getNetworkId() { return mNetworkId; } /** * Get Subscriber Id Match Rule of the template. + * + * @hide */ public int getSubscriberIdMatchRule() { return mSubscriberIdMatchRule; @@ -601,6 +649,38 @@ public final class NetworkTemplate implements Parcelable { return mMetered; } + /** + * Get roaming filter of the template. + */ + @NetworkStats.Roaming + public int getRoaming() { + return mRoaming; + } + + /** + * Get the default network status filter of the template. + */ + @NetworkStats.DefaultNetwork + public int getDefaultNetworkStatus() { + return mDefaultNetwork; + } + + /** + * Get the Radio Access Technology(RAT) type filter of the template. + */ + public int getRatType() { + return mSubType; + } + + /** + * Get the OEM managed filter of the template. See {@code OEM_MANAGED_*} or + * {@code android.net.NetworkIdentity#OEM_*}. + */ + @OemManaged + public int getOemManaged() { + return mOemManaged; + } + /** * Test if given {@link NetworkIdentity} matches this template. * @@ -680,10 +760,10 @@ public final class NetworkTemplate implements Parcelable { /** * Check if network with matching SSID. Returns true when the SSID matches, or when - * {@code mNetworkId} is {@code WIFI_NETWORKID_ALL}. + * {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}. */ private boolean matchesWifiNetworkId(@Nullable String networkId) { - return Objects.equals(mNetworkId, WIFI_NETWORKID_ALL) + return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL) || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); } @@ -948,4 +1028,184 @@ public final class NetworkTemplate implements Parcelable { return new NetworkTemplate[size]; } }; + + /** + * Builder class for NetworkTemplate. + */ + public static final class Builder { + private final int mMatchRule; + // Use a SortedSet to provide a deterministic order when fetching the first one. + @NonNull + private final SortedSet mMatchSubscriberIds = new TreeSet<>(); + @Nullable + private String mWifiNetworkKey; + + // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. + private int mMetered; + private int mRoaming; + private int mDefaultNetwork; + private int mRatType; + + // Bitfield containing OEM network properties {@code NetworkIdentity#OEM_*}. + private int mOemManaged; + + /** + * Creates a new Builder with given match rule to construct NetworkTemplate objects. + * + * @param matchRule the match rule of the template, see {@code MATCH_*}. + */ + public Builder(@TemplateMatchRule final int matchRule) { + assertRequestableMatchRule(matchRule); + // Initialize members with default values. + mMatchRule = matchRule; + mWifiNetworkKey = WIFI_NETWORK_KEY_ALL; + mMetered = METERED_ALL; + mRoaming = ROAMING_ALL; + mDefaultNetwork = DEFAULT_NETWORK_ALL; + mRatType = NETWORK_TYPE_ALL; + mOemManaged = OEM_MANAGED_ALL; + } + + /** + * Set the Subscriber Ids. Calling this function with an empty set represents + * the intention of matching any Subscriber Ids. + * + * @param subscriberIds the list of Subscriber Ids. + * @return this builder. + */ + @NonNull + public Builder setSubscriberIds(@NonNull Set subscriberIds) { + Objects.requireNonNull(subscriberIds); + mMatchSubscriberIds.clear(); + mMatchSubscriberIds.addAll(subscriberIds); + return this; + } + + /** + * Set the Wifi Network Key. + * + * @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}. + * Or null to match all networks. + * @return this builder. + */ + @NonNull + public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { + mWifiNetworkKey = wifiNetworkKey; + return this; + } + + /** + * Set the meteredness filter. + * + * @param metered the meteredness filter. + * @return this builder. + */ + @NonNull + public Builder setMeteredness(@NetworkStats.Meteredness int metered) { + mMetered = metered; + return this; + } + + /** + * Set the roaming filter. + * + * @param roaming the roaming filter. + * @return this builder. + */ + @NonNull + public Builder setRoaming(@NetworkStats.Roaming int roaming) { + mRoaming = roaming; + return this; + } + + /** + * Set the default network status filter. + * + * @param defaultNetwork the default network status filter. + * @return this builder. + */ + @NonNull + public Builder setDefaultNetworkStatus(@NetworkStats.DefaultNetwork int defaultNetwork) { + mDefaultNetwork = defaultNetwork; + return this; + } + + /** + * Set the Radio Access Technology(RAT) type filter. + * + * @param ratType the Radio Access Technology(RAT) type filter. Use + * {@link #NETWORK_TYPE_ALL} to include all network types when filtering. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + * @return this builder. + */ + @NonNull + public Builder setRatType(@NetworkType int ratType) { + // Input will be validated with the match rule when building the template. + mRatType = ratType; + return this; + } + + /** + * Set the OEM managed filter. + * + * @param oemManaged the match rule to match different type of OEM managed network or + * unmanaged networks. See {@code OEM_MANAGED_*}. + * @return this builder. + */ + @NonNull + public Builder setOemManaged(@OemManaged int oemManaged) { + mOemManaged = oemManaged; + return this; + } + + /** + * Check whether the match rule is requestable. + * + * @param matchRule the target match rule to be checked. + */ + private static void assertRequestableMatchRule(final int matchRule) { + if (!isKnownMatchRule(matchRule) + || matchRule == MATCH_PROXY + || matchRule == MATCH_MOBILE_WILDCARD + || matchRule == MATCH_WIFI_WILDCARD) { + throw new IllegalArgumentException("Invalid match rule: " + + getMatchRuleName(matchRule)); + } + } + + private void assertRequestableParameters() { + // TODO: Check all the input are legitimate. + } + + /** + * For backward compatibility, deduce match rule to a wildcard match rule + * if the Subscriber Ids are empty. + */ + private int getWildcardDeducedMatchRule() { + if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { + return MATCH_MOBILE_WILDCARD; + } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() + && mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) { + return MATCH_WIFI_WILDCARD; + } + return mMatchRule; + } + + /** + * Builds the instance of the NetworkTemplate. + * + * @return the built instance of NetworkTemplate. + */ + @NonNull + public NetworkTemplate build() { + assertRequestableParameters(); + final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() + ? SUBSCRIBER_ID_MATCH_RULE_ALL : SUBSCRIBER_ID_MATCH_RULE_EXACT; + return new NetworkTemplate(getWildcardDeducedMatchRule(), + mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), + mMatchSubscriberIds.toArray(new String[0]), + mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, + subscriberIdMatchRule); + } + } } From 682bebbf6065a83681782b70e323830829761e68 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 20 Dec 2021 16:54:47 +0000 Subject: [PATCH 1003/1150] [MS14] Move isPersistable to NetworkPolicy Since the NetworkTemplate serialization is done in the platform code. To decide whether the template is persistable should be also inside the platform along with the serialization logic. Test: atest NetworkPolicyTest Bug: 204830222 Change-Id: I15d17dda77e6a3e1ae11275915e3d2f6e2888639 --- .../src/android/net/NetworkTemplate.java | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 7dd04c5d42..d85291318f 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -559,30 +559,6 @@ public final class NetworkTemplate implements Parcelable { } } - /** - * Check if the template can be persisted into disk. - * - * @hide - */ - // TODO: Move to the NetworkPolicy. - public boolean isPersistable() { - switch (mMatchRule) { - case MATCH_MOBILE_WILDCARD: - case MATCH_WIFI_WILDCARD: - return false; - case MATCH_CARRIER: - return mSubscriberId != null; - case MATCH_WIFI: - if (Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL) - && mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { - return false; - } - return true; - default: - return true; - } - } - /** * Get match rule of the template. See {@code MATCH_*}. */ From eb50ef2da7b7f60001266199df5706053faaaf47 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 22 Dec 2021 16:35:13 +0800 Subject: [PATCH 1004/1150] Replace Preconditions.checkNotNull with Objects.requireNonNull IpSec service is going to be moved into Connectivity module. Replace Preconditions.checkNotNull with Objects.requireNonNull to remove hidden API usages. Bug: 204153604 Test: FrameworksNetTests Change-Id: Iff7f76844d4126b0e17b62b4ce821449b5b6ce44 --- framework-t/src/android/net/IpSecManager.java | 5 ++--- .../src/android/net/IpSecTransform.java | 20 +++++++++---------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index 837629911c..ca9be1cc40 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -17,8 +17,6 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; -import static com.android.internal.util.Preconditions.checkNotNull; - import android.annotation.NonNull; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; @@ -46,6 +44,7 @@ import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; +import java.util.Objects; /** * This class contains methods for managing IPsec sessions. Once configured, the kernel will apply @@ -988,7 +987,7 @@ public final class IpSecManager { */ public IpSecManager(Context ctx, IIpSecService service) { mContext = ctx; - mService = checkNotNull(service, "missing service"); + mService = Objects.requireNonNull(service, "missing service"); } private static void maybeHandleServiceSpecificException(ServiceSpecificException sse) { diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java index b48c1fdaf1..36199a046c 100644 --- a/framework-t/src/android/net/IpSecTransform.java +++ b/framework-t/src/android/net/IpSecTransform.java @@ -33,7 +33,6 @@ import android.os.ServiceSpecificException; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; @@ -41,6 +40,7 @@ import java.io.IOException; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.net.InetAddress; +import java.util.Objects; /** * This class represents a transform, which roughly corresponds to an IPsec Security Association. @@ -255,7 +255,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setEncryption(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an encryption algorithm. - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setEncryption(algo); return this; } @@ -270,7 +270,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setAuthentication(@NonNull IpSecAlgorithm algo) { // TODO: throw IllegalArgumentException if algo is not an authentication algorithm. - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setAuthentication(algo); return this; } @@ -290,7 +290,7 @@ public final class IpSecTransform implements AutoCloseable { */ @NonNull public IpSecTransform.Builder setAuthenticatedEncryption(@NonNull IpSecAlgorithm algo) { - Preconditions.checkNotNull(algo); + Objects.requireNonNull(algo); mConfig.setAuthenticatedEncryption(algo); return this; } @@ -311,7 +311,7 @@ public final class IpSecTransform implements AutoCloseable { @NonNull public IpSecTransform.Builder setIpv4Encapsulation( @NonNull IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) { - Preconditions.checkNotNull(localSocket); + Objects.requireNonNull(localSocket); mConfig.setEncapType(ENCAP_ESPINUDP); if (localSocket.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid UdpEncapsulationSocket"); @@ -348,8 +348,8 @@ public final class IpSecTransform implements AutoCloseable { @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - Preconditions.checkNotNull(sourceAddress); - Preconditions.checkNotNull(spi); + Objects.requireNonNull(sourceAddress); + Objects.requireNonNull(spi); if (spi.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } @@ -387,8 +387,8 @@ public final class IpSecTransform implements AutoCloseable { @NonNull IpSecManager.SecurityParameterIndex spi) throws IpSecManager.ResourceUnavailableException, IpSecManager.SpiUnavailableException, IOException { - Preconditions.checkNotNull(sourceAddress); - Preconditions.checkNotNull(spi); + Objects.requireNonNull(sourceAddress); + Objects.requireNonNull(spi); if (spi.getResourceId() == INVALID_RESOURCE_ID) { throw new IllegalArgumentException("Invalid SecurityParameterIndex"); } @@ -404,7 +404,7 @@ public final class IpSecTransform implements AutoCloseable { * @param context current context */ public Builder(@NonNull Context context) { - Preconditions.checkNotNull(context); + Objects.requireNonNull(context); mContext = context; mConfig = new IpSecConfig(); } From 4451b45f702a82301498045b557adc43b77e710c Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 21 Dec 2021 06:57:14 +0000 Subject: [PATCH 1005/1150] [MS15.1] Remove get/setSubscriberIdMatchRule dependencies Subscriber Id Match Rule won't be exposed as system Api. Callers should use Builder#setSubscriberIds or NetworkTemplate#getSubscriberIds to set/get the Subscriber Ids filter. An empty set in the paremter or return value represents the intention of matching any Subscriber Ids. Test: atest NetworkPolicyManagerServiceTest \ FrameworksNetTests Bug: 204830222 Change-Id: I12c54280b44c71e4737e82859dfe869794cc9c29 --- .../src/android/net/NetworkTemplate.java | 57 +++++-------------- 1 file changed, 15 insertions(+), 42 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index d85291318f..5da8e259d0 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -51,6 +51,7 @@ import android.util.ArraySet; import com.android.internal.util.ArrayUtils; import com.android.net.module.util.NetworkIdentityUtils; +import com.android.net.module.util.NetworkStatsUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -114,27 +115,6 @@ public final class NetworkTemplate implements Parcelable { */ public static final int MATCH_CARRIER = 10; - /** @hide */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "SUBSCRIBER_ID_MATCH_RULE_" }, value = { - SUBSCRIBER_ID_MATCH_RULE_EXACT, - SUBSCRIBER_ID_MATCH_RULE_ALL - }) - public @interface SubscriberIdMatchRule{} - /** - * Value of the match rule of the subscriberId to match networks with specific subscriberId. - * - * @hide - */ - public static final int SUBSCRIBER_ID_MATCH_RULE_EXACT = 0; - /** - * Value of the match rule of the subscriberId to match networks with any subscriberId which - * includes null and non-null. - * - * @hide - */ - public static final int SUBSCRIBER_ID_MATCH_RULE_ALL = 1; - // TODO: Remove this and replace all callers with WIFI_NETWORK_KEY_ALL. /** @hide */ public static final String WIFI_NETWORKID_ALL = null; @@ -235,11 +215,11 @@ public final class NetworkTemplate implements Parcelable { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -285,7 +265,7 @@ public final class NetworkTemplate implements Parcelable { new String[] { null } /* matchSubscriberIds */, networkId, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_ALL); + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL); } /** @@ -302,7 +282,7 @@ public final class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, networkId, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @@ -346,7 +326,7 @@ public final class NetworkTemplate implements Parcelable { return new NetworkTemplate(MATCH_CARRIER, subscriberId, new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, - SUBSCRIBER_ID_MATCH_RULE_EXACT); + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } private final int mMatchRule; @@ -384,7 +364,7 @@ public final class NetworkTemplate implements Parcelable { case MATCH_MOBILE: case MATCH_CARRIER: // MOBILE and CARRIER templates must always specify a subscriber ID. - if (subscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL) { + if (subscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL) { throw new IllegalArgumentException("Invalid SubscriberIdMatchRule " + "on match rule: " + getMatchRuleName(matchRule)); } @@ -411,7 +391,7 @@ public final class NetworkTemplate implements Parcelable { this(matchRule, subscriberId, matchSubscriberIds, networkId, (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, - OEM_MANAGED_ALL, SUBSCRIBER_ID_MATCH_RULE_EXACT); + OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @hide */ @@ -420,7 +400,8 @@ public final class NetworkTemplate implements Parcelable { String networkId, int metered, int roaming, int defaultNetwork, int subType, int oemManaged) { this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, - defaultNetwork, subType, oemManaged, SUBSCRIBER_ID_MATCH_RULE_EXACT); + defaultNetwork, subType, oemManaged, + NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @hide */ @@ -539,9 +520,9 @@ public final class NetworkTemplate implements Parcelable { private static String subscriberIdMatchRuleToString(int rule) { switch (rule) { - case SUBSCRIBER_ID_MATCH_RULE_EXACT: + case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT: return "EXACT_MATCH"; - case SUBSCRIBER_ID_MATCH_RULE_ALL: + case NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL: return "ALL"; default: return "Unknown rule " + rule; @@ -608,15 +589,6 @@ public final class NetworkTemplate implements Parcelable { return mNetworkId; } - /** - * Get Subscriber Id Match Rule of the template. - * - * @hide - */ - public int getSubscriberIdMatchRule() { - return mSubscriberIdMatchRule; - } - /** * Get meteredness filter of the template. */ @@ -730,7 +702,7 @@ public final class NetworkTemplate implements Parcelable { * @hide */ public boolean matchesSubscriberId(@Nullable String subscriberId) { - return mSubscriberIdMatchRule == SUBSCRIBER_ID_MATCH_RULE_ALL + return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); } @@ -1176,7 +1148,8 @@ public final class NetworkTemplate implements Parcelable { public NetworkTemplate build() { assertRequestableParameters(); final int subscriberIdMatchRule = mMatchSubscriberIds.isEmpty() - ? SUBSCRIBER_ID_MATCH_RULE_ALL : SUBSCRIBER_ID_MATCH_RULE_EXACT; + ? NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL + : NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT; return new NetworkTemplate(getWildcardDeducedMatchRule(), mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), mMatchSubscriberIds.toArray(new String[0]), From d03aa846f3f159f5d0c47da35171a6c8ac5af946 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 14 Dec 2021 18:12:40 -0800 Subject: [PATCH 1006/1150] aidl and Parcelable defintions for eth management aidl and Parcelable definitions neccessary for internal network management APIs as related to ethernet interfaces. Bug: 210485380 Test: make, flash and boot Change-Id: I5908d21564014c56282dad001da441f5b900b523 --- .../InternalNetworkManagementException.aidl | 19 +++ .../InternalNetworkManagementException.java | 59 ++++++++++ .../net/InternalNetworkUpdateRequest.aidl | 19 +++ .../net/InternalNetworkUpdateRequest.java | 108 ++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 core/java/android/net/InternalNetworkManagementException.aidl create mode 100644 core/java/android/net/InternalNetworkManagementException.java create mode 100644 core/java/android/net/InternalNetworkUpdateRequest.aidl create mode 100644 core/java/android/net/InternalNetworkUpdateRequest.java diff --git a/core/java/android/net/InternalNetworkManagementException.aidl b/core/java/android/net/InternalNetworkManagementException.aidl new file mode 100644 index 0000000000..dcce706989 --- /dev/null +++ b/core/java/android/net/InternalNetworkManagementException.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package android.net; + + parcelable InternalNetworkManagementException; \ No newline at end of file diff --git a/core/java/android/net/InternalNetworkManagementException.java b/core/java/android/net/InternalNetworkManagementException.java new file mode 100644 index 0000000000..7f4e403f22 --- /dev/null +++ b/core/java/android/net/InternalNetworkManagementException.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.os.Parcel; +import android.os.Parcelable; + +/** @hide */ +public final class InternalNetworkManagementException + extends RuntimeException implements Parcelable { + + /* @hide */ + public InternalNetworkManagementException(@NonNull final Throwable t) { + super(t); + } + + private InternalNetworkManagementException(@NonNull final Parcel source) { + super(source.readString()); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeString(getCause().getMessage()); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public InternalNetworkManagementException[] newArray(int size) { + return new InternalNetworkManagementException[size]; + } + + @Override + public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) { + return new InternalNetworkManagementException(source); + } + }; +} diff --git a/core/java/android/net/InternalNetworkUpdateRequest.aidl b/core/java/android/net/InternalNetworkUpdateRequest.aidl new file mode 100644 index 0000000000..da00cb97af --- /dev/null +++ b/core/java/android/net/InternalNetworkUpdateRequest.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package android.net; + + parcelable InternalNetworkUpdateRequest; \ No newline at end of file diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java new file mode 100644 index 0000000000..6f093835fb --- /dev/null +++ b/core/java/android/net/InternalNetworkUpdateRequest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** @hide */ +public final class InternalNetworkUpdateRequest implements Parcelable { + @NonNull + private final StaticIpConfiguration mIpConfig; + @Nullable + private final NetworkCapabilities mNetworkCapabilities; + + @NonNull + public StaticIpConfiguration getIpConfig() { + return new StaticIpConfiguration(mIpConfig); + } + + @NonNull + public NetworkCapabilities getNetworkCapabilities() { + return mNetworkCapabilities == null + ? null : new NetworkCapabilities(mNetworkCapabilities); + } + + /** @hide */ + public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + @Nullable final NetworkCapabilities networkCapabilities) { + Objects.requireNonNull(ipConfig); + mIpConfig = new StaticIpConfiguration(ipConfig); + if (null == networkCapabilities) { + mNetworkCapabilities = null; + } else { + mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); + } + } + + private InternalNetworkUpdateRequest(@NonNull final Parcel source) { + Objects.requireNonNull(source); + mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); + mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); + } + + @Override + public String toString() { + return "InternalNetworkUpdateRequest{" + + "mIpConfig=" + mIpConfig + + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o; + + return Objects.equals(that.getIpConfig(), mIpConfig) + && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); + } + + @Override + public int hashCode() { + return Objects.hash(mIpConfig, mNetworkCapabilities); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + mIpConfig.writeToParcel(dest, flags); + mNetworkCapabilities.writeToParcel(dest, flags); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public InternalNetworkUpdateRequest[] newArray(int size) { + return new InternalNetworkUpdateRequest[size]; + } + + @Override + public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { + return new InternalNetworkUpdateRequest(source); + } + }; +} From be91b5831e3c638021f84119e4308d2a17bbfb8e Mon Sep 17 00:00:00 2001 From: James Mattis Date: Tue, 14 Dec 2021 18:23:30 -0800 Subject: [PATCH 1007/1150] eth manager updates for network management APIs Private methods added to EthernetManager for network management to be made public when ready. Bug: 210485380 Test: make, flash and boot Change-Id: I7f484d373e05225c98bf0e6111afdc12be31764f --- .../src/android/net/EthernetManager.java | 82 +++++++++++++++++++ .../src/android/net/IEthernetManager.aidl | 6 ++ 2 files changed, 88 insertions(+) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 7cd63ef9cc..ece54df966 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -16,7 +16,9 @@ package android.net; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; @@ -32,6 +34,7 @@ import com.android.internal.os.BackgroundThread; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.BiConsumer; /** * A class representing the IP configuration of the Ethernet network. @@ -315,4 +318,83 @@ public class EthernetManager { } return new TetheredInterfaceRequest(mService, cbInternal); } + + private static final class InternalNetworkManagementListener + extends IInternalNetworkManagementListener.Stub { + @NonNull + private final Executor mExecutor; + @NonNull + private final BiConsumer mListener; + + InternalNetworkManagementListener( + @NonNull final Executor executor, + @NonNull final BiConsumer listener) { + Objects.requireNonNull(executor, "Pass a non-null executor"); + Objects.requireNonNull(listener, "Pass a non-null listener"); + mExecutor = executor; + mListener = listener; + } + + @Override + public void onComplete( + @Nullable final Network network, + @Nullable final InternalNetworkManagementException e) { + mExecutor.execute(() -> mListener.accept(network, e)); + } + } + + private InternalNetworkManagementListener getInternalNetworkManagementListener( + @Nullable final Executor executor, + @Nullable final BiConsumer listener) { + if (null != listener) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); + } + final InternalNetworkManagementListener proxy; + if (null == listener) { + proxy = null; + } else { + proxy = new InternalNetworkManagementListener(executor, listener); + } + return proxy; + } + + private void updateConfiguration( + @NonNull String iface, + @NonNull InternalNetworkUpdateRequest request, + @Nullable @CallbackExecutor Executor executor, + @Nullable BiConsumer listener) { + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); + try { + mService.updateConfiguration(iface, request, proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private void connectNetwork( + @NonNull String iface, + @Nullable @CallbackExecutor Executor executor, + @Nullable BiConsumer listener) { + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); + try { + mService.connectNetwork(iface, proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + private void disconnectNetwork( + @NonNull String iface, + @Nullable @CallbackExecutor Executor executor, + @Nullable BiConsumer listener) { + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); + try { + mService.disconnectNetwork(iface, proxy); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index e058e5a70c..e688bea1cf 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,6 +18,8 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; +import android.net.IInternalNetworkManagementListener; +import android.net.InternalNetworkUpdateRequest; import android.net.ITetheredInterfaceCallback; /** @@ -36,4 +38,8 @@ interface IEthernetManager void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); + void updateConfiguration(String iface, in InternalNetworkUpdateRequest request, + in IInternalNetworkManagementListener listener); + void connectNetwork(String iface, in IInternalNetworkManagementListener listener); + void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener); } From 654c1a61d54d533ebbc59e075245cde9a5b0ff0d Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 23 Dec 2021 03:27:59 +0000 Subject: [PATCH 1008/1150] [MS16.1] Prepare APIs for replacing getNetwork[Total|Uid]Bytes These internal methods are used in MultipathPolicyTracker and NetworkPolicyManagementService. getNetworkTotalBytes is used to query total bytes regarding to the specified NetworkPolicy, to see how much data quota is used. getNetworkUidBytes is used to find the app to blame for rapid data usage. These methods needs to be replaced by public APIs in follow-up patches. Test: TH Bug: 204830222 Change-Id: Iec9cc7a07397ec2bbc6c3d2559fc3680b149cb8a --- .../app/usage/NetworkStatsManager.java | 87 +++++++++++++++---- 1 file changed, 69 insertions(+), 18 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index ca83309216..40b6371da7 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -170,16 +170,44 @@ public class NetworkStatsManager { } } - /** @hide */ - public Bucket querySummaryForDevice(NetworkTemplate template, - long startTime, long endTime) throws SecurityException, RemoteException { - Bucket bucket = null; - NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, - mService); - bucket = stats.getDeviceSummaryForNetwork(); - - stats.close(); - return bucket; + /** + * Query network usage statistics summaries. + * + * Result is summarised data usage for the whole + * device. Result is a single Bucket aggregated over time, state, uid, tag, metered, and + * roaming. This means the bucket's start and end timestamp will be the same as the + * 'startTime' and 'endTime' arguments. State is going to be + * {@link NetworkStats.Bucket#STATE_ALL}, uid {@link NetworkStats.Bucket#UID_ALL}, + * tag {@link NetworkStats.Bucket#TAG_NONE}, + * default network {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered {@link NetworkStats.Bucket#METERED_ALL}, + * and roaming {@link NetworkStats.Bucket#ROAMING_ALL}. + * This may take a long time, and apps should avoid calling this on their main thread. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param startTime Start of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @return Bucket Summarised data usage. + * + * @hide + */ + @NonNull + @WorkerThread + // @SystemApi(client = MODULE_LIBRARIES) + public Bucket querySummaryForDevice(@NonNull NetworkTemplate template, + long startTime, long endTime) { + try { + NetworkStats stats = + new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); + Bucket bucket = stats.getDeviceSummaryForNetwork(); + stats.close(); + return bucket; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return null; // To make the compiler happy. } /** @@ -323,14 +351,37 @@ public class NetworkStatsManager { return querySummary(template, startTime, endTime); } - /** @hide */ - public NetworkStats querySummary(NetworkTemplate template, long startTime, - long endTime) throws SecurityException, RemoteException { - NetworkStats result; - result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startSummaryEnumeration(); - - return result; + /** + * Query network usage statistics summaries. + * + * The results will only include traffic made by UIDs belonging to the calling user profile. + * The results are aggregated over time, so that all buckets will have the same start and + * end timestamps as the passed arguments. Not aggregated over state, uid, default network, + * metered, or roaming. + * This may take a long time, and apps should avoid calling this on their main thread. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param startTime Start of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @return Statistics which is described above. + * @hide + */ + @Nullable + // @SystemApi(client = MODULE_LIBRARIES) + @WorkerThread + public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, + long endTime) throws SecurityException { + try { + NetworkStats result = + new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); + result.startSummaryEnumeration(); + return result; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return null; // To make the compiler happy. } /** From 366c1d7c4bd7c2298a181203f4f5a24ee77d39bb Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 24 Dec 2021 08:31:26 +0000 Subject: [PATCH 1009/1150] [MS18] Augment data usage by default Follow-up from ag/2815797, callers who uses the hidden API will have their data augmented by default, and the public API offers a way to opt-into augmentation. However, since the data usage is going to the module. All the hidden API usage must be eliminated. Also, from user perspective, it is better for UI and API to have aligned behavior. Thus, enable augment data usage for public API callers. Test: atest FrameworksNetTests \ android.app.usage.cts.NetworkUsageStatsTest Bug: 204830222 Change-Id: Ida254fac8d44c32d388f1886a866f7324a41ce75 --- framework-t/src/android/app/usage/NetworkStatsManager.java | 1 + service-t/src/com/android/server/net/NetworkStatsService.java | 4 ---- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 40b6371da7..2b9560e7ec 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -139,6 +139,7 @@ public class NetworkStatsManager { mContext = context; mService = service; setPollOnOpen(true); + setAugmentWithSubscriptionPlan(true); } /** @hide */ diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 2beca73ecd..df066c21d7 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -655,8 +655,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public INetworkStatsSession openSession() { - // NOTE: if callers want to get non-augmented data, they should go - // through the public API return openSessionInternal(NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, null); } @@ -876,8 +874,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { assertSystemReady(); - // NOTE: if callers want to get non-augmented data, they should go - // through the public API return internalGetSummaryForNetwork(template, NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN, start, end, NetworkStatsAccess.Level.DEVICE, Binder.getCallingUid()).getTotalBytes(); From fe925d8e2db1ca63f3320b856e6a4fc4896d9c8b Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Dec 2021 02:33:53 +0800 Subject: [PATCH 1010/1150] Remove ServiceManager usage from IpSecTransform Remove ServiceManager hidden API dependency because this class is going to be moved into mainline module. Thus have IpSecTransform calls createTransform and deleteTransform through IpSecManager to remove the ServiceManager usage. Bug: 204153604 Test: FrameworksNetTests Change-Id: Iba48da4aecac1080684d5a7e7e7ca2e31219591a --- framework-t/src/android/net/IpSecManager.java | 24 +++++++++++++++++++ .../src/android/net/IpSecTransform.java | 24 ++++--------------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index 0d15dffae9..819ac6bdec 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.net.annotations.PolicyDirection; import android.os.Binder; +import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -980,6 +981,29 @@ public final class IpSecManager { } } + /** + * @hide + */ + public IpSecTransformResponse createTransform(IpSecConfig config, IBinder binder, + String callingPackage) { + try { + return mService.createTransform(config, binder, callingPackage); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * @hide + */ + public void deleteTransform(int resourceId) { + try { + mService.deleteTransform(resourceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Construct an instance of IpSecManager within an application context. * diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java index 36199a046c..68ae5de4ee 100644 --- a/framework-t/src/android/net/IpSecTransform.java +++ b/framework-t/src/android/net/IpSecTransform.java @@ -26,9 +26,6 @@ import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageManager; import android.os.Binder; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; import android.os.ServiceSpecificException; import android.util.Log; @@ -93,16 +90,9 @@ public final class IpSecTransform implements AutoCloseable { mResourceId = INVALID_RESOURCE_ID; } - private IIpSecService getIpSecService() { - IBinder b = ServiceManager.getService(android.content.Context.IPSEC_SERVICE); - if (b == null) { - throw new RemoteException("Failed to connect to IpSecService") - .rethrowAsRuntimeException(); - } - - return IIpSecService.Stub.asInterface(b); + private IpSecManager getIpSecManager(Context context) { + return context.getSystemService(IpSecManager.class); } - /** * Checks the result status and throws an appropriate exception if the status is not Status.OK. */ @@ -130,8 +120,7 @@ public final class IpSecTransform implements AutoCloseable { IpSecManager.SpiUnavailableException { synchronized (this) { try { - IIpSecService svc = getIpSecService(); - IpSecTransformResponse result = svc.createTransform( + IpSecTransformResponse result = getIpSecManager(mContext).createTransform( mConfig, new Binder(), mContext.getOpPackageName()); int status = result.status; checkResultStatus(status); @@ -140,8 +129,6 @@ public final class IpSecTransform implements AutoCloseable { mCloseGuard.open("build"); } catch (ServiceSpecificException e) { throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); } } @@ -177,10 +164,7 @@ public final class IpSecTransform implements AutoCloseable { return; } try { - IIpSecService svc = getIpSecService(); - svc.deleteTransform(mResourceId); - } catch (RemoteException e) { - throw e.rethrowAsRuntimeException(); + getIpSecManager(mContext).deleteTransform(mResourceId); } catch (Exception e) { // On close we swallow all random exceptions since failure to close is not // actionable by the user. From 6c4fca78b0779a0791df0b71a522962bd27acb3f Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 27 Dec 2021 03:55:06 +0000 Subject: [PATCH 1011/1150] [MS19.1] Fix several hidden API dependencies This includes: 1. Use android.util.IndentingPrintWriter instead of the deprecated internal one. 2. Replace usages of IntArray with CollectionUtils and ArrayList. 3. Replace usages of ArrayUtils with CollectionUtils. 4. Refactor MathUtils.constrain functions into NetworkStatsUtils. 5. Replace Maps.newHashMap and Lists.newArrayList with public class constructors. 6. Replace Slog with Log. Test: FrameworksNetTests NetworkStaticLibTests Bug: 204830222 Change-Id: If009194ad5668a6d48dd341ea6d325028ce56d42 --- .../src/android/app/usage/NetworkStats.java | 8 +++-- framework-t/src/android/net/NetworkStats.java | 6 ++-- .../android/net/NetworkStatsCollection.java | 33 +++++++++---------- .../src/android/net/NetworkStatsHistory.java | 20 +++++++---- .../src/android/net/NetworkTemplate.java | 14 ++++---- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java index 216a4a0987..f684a4d9d8 100644 --- a/framework-t/src/android/app/usage/NetworkStats.java +++ b/framework-t/src/android/app/usage/NetworkStats.java @@ -24,13 +24,15 @@ import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TrafficStats; import android.os.RemoteException; -import android.util.IntArray; import android.util.Log; +import com.android.net.module.util.CollectionUtils; + import dalvik.system.CloseGuard; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; /** * Class providing enumeration over buckets of network usage statistics. {@link NetworkStats} objects @@ -568,7 +570,7 @@ public final class NetworkStats implements AutoCloseable { // the filtering logic below can be removed. int[] uids = mSession.getRelevantUids(); // Filtering of uids with empty history. - IntArray filteredUids = new IntArray(uids.length); + final ArrayList filteredUids = new ArrayList<>(); for (int uid : uids) { try { NetworkStatsHistory history = mSession.getHistoryIntervalForUid(mTemplate, uid, @@ -581,7 +583,7 @@ public final class NetworkStats implements AutoCloseable { Log.w(TAG, "Error while getting history of uid " + uid, e); } } - mUids = filteredUids.toArray(); + mUids = CollectionUtils.toIntArray(filteredUids); mUidOrUidIndex = -1; stepHistory(); } diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index 1986b83b12..181a594cbc 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -31,7 +31,7 @@ import android.os.SystemClock; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; +import com.android.net.module.util.CollectionUtils; import libcore.util.EmptyArray; @@ -1185,7 +1185,7 @@ public final class NetworkStats implements Parcelable { * @hide */ public void removeUids(int[] uids) { - filter(e -> !ArrayUtils.contains(uids, e.uid)); + filter(e -> !CollectionUtils.contains(uids, e.uid)); } /** @@ -1218,7 +1218,7 @@ public final class NetworkStats implements Parcelable { filter(e -> (limitUid == UID_ALL || limitUid == e.uid) && (limitTag == TAG_ALL || limitTag == e.tag) && (limitIfaces == INTERFACES_ALL - || ArrayUtils.contains(limitIfaces, e.iface))); + || CollectionUtils.contains(limitIfaces, e.iface))); } /** diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 8d1347e25b..7935d28f30 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -40,21 +40,17 @@ import android.telephony.SubscriptionPlan; import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.AtomicFile; -import android.util.IntArray; -import android.util.MathUtils; +import android.util.IndentingPrintWriter; +import android.util.Log; import android.util.Range; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastDataInput; import com.android.internal.util.FastDataOutput; import com.android.internal.util.FileRotator; -import com.android.internal.util.IndentingPrintWriter; - -import com.google.android.collect.Lists; -import com.google.android.collect.Maps; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.NetworkStatsUtils; import libcore.io.IoUtils; @@ -196,11 +192,11 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, final int callerUid) { - IntArray uids = new IntArray(); + final ArrayList uids = new ArrayList<>(); for (int i = 0; i < mStats.size(); i++) { final Key key = mStats.keyAt(i); if (NetworkStatsAccess.isAccessibleToUser(key.uid, callerUid, accessLevel)) { - int j = uids.binarySearch(key.uid); + int j = Collections.binarySearch(uids, new Integer(key.uid)); if (j < 0) { j = ~j; @@ -208,7 +204,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } } - return uids.toArray(); + return CollectionUtils.toIntArray(uids); } /** @@ -225,7 +221,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W // 180 days of history should be enough for anyone; if we end up needing // more, we'll dynamically grow the history object. - final int bucketEstimate = (int) MathUtils.constrain(((end - start) / mBucketDuration), 0, + final int bucketEstimate = (int) NetworkStatsUtils.constrain( + ((end - start) / mBucketDuration), 0, (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration); final NetworkStatsHistory combined = new NetworkStatsHistory( mBucketDuration, bucketEstimate, fields); @@ -316,7 +313,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long deltaTotal = combined.getTotalBytes() - beforeTotal; if (deltaTotal != 0) { - Slog.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); + Log.d(TAG, "Augmented network usage by " + deltaTotal + " bytes"); } // Finally we can slice data as originally requested @@ -489,11 +486,11 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private void write(DataOutput out) throws IOException { // cluster key lists grouped by ident - final HashMap> keysByIdent = Maps.newHashMap(); + final HashMap> keysByIdent = new HashMap<>(); for (Key key : mStats.keySet()) { ArrayList keys = keysByIdent.get(key.ident); if (keys == null) { - keys = Lists.newArrayList(); + keys = new ArrayList<>(); keysByIdent.put(key.ident, keys); } keys.add(key); @@ -640,12 +637,12 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * {@link TrafficStats#UID_REMOVED}. */ public void removeUids(int[] uids) { - final ArrayList knownKeys = Lists.newArrayList(); + final ArrayList knownKeys = new ArrayList<>(); knownKeys.addAll(mStats.keySet()); // migrate all UID stats into special "removed" bucket for (Key key : knownKeys) { - if (ArrayUtils.contains(uids, key.uid)) { + if (CollectionUtils.contains(uids, key.uid)) { // only migrate combined TAG_NONE history if (key.tag == TAG_NONE) { final NetworkStatsHistory uidHistory = mStats.get(key); @@ -672,7 +669,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } private ArrayList getSortedKeys() { - final ArrayList keys = Lists.newArrayList(); + final ArrayList keys = new ArrayList<>(); keys.addAll(mStats.keySet()); Collections.sort(keys); return keys; diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 3eef4ee6f8..428bc6df26 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -28,7 +28,6 @@ import static android.net.NetworkStatsHistory.ParcelUtils.readLongArray; import static android.net.NetworkStatsHistory.ParcelUtils.writeLongArray; import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static com.android.internal.util.ArrayUtils.total; import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.compat.annotation.UnsupportedAppUsage; @@ -37,10 +36,11 @@ import android.os.Parcel; import android.os.Parcelable; import android.service.NetworkStatsHistoryBucketProto; import android.service.NetworkStatsHistoryProto; -import android.util.MathUtils; +import android.util.IndentingPrintWriter; import android.util.proto.ProtoOutputStream; -import com.android.internal.util.IndentingPrintWriter; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.NetworkStatsUtils; import libcore.util.EmptyArray; @@ -174,7 +174,7 @@ public class NetworkStatsHistory implements Parcelable { txPackets = new long[bucketStart.length]; operations = new long[bucketStart.length]; bucketCount = bucketStart.length; - totalBytes = total(rxBytes) + total(txBytes); + totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); break; } case VERSION_ADD_PACKETS: @@ -189,7 +189,7 @@ public class NetworkStatsHistory implements Parcelable { txPackets = readVarLongArray(in); operations = readVarLongArray(in); bucketCount = bucketStart.length; - totalBytes = total(rxBytes) + total(txBytes); + totalBytes = CollectionUtils.total(rxBytes) + CollectionUtils.total(txBytes); break; } default: { @@ -267,7 +267,7 @@ public class NetworkStatsHistory implements Parcelable { } else { index -= 1; } - return MathUtils.constrain(index, 0, bucketCount - 1); + return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); } /** @@ -281,7 +281,7 @@ public class NetworkStatsHistory implements Parcelable { } else { index += 1; } - return MathUtils.constrain(index, 0, bucketCount - 1); + return NetworkStatsUtils.constrain(index, 0, bucketCount - 1); } /** @@ -349,6 +349,9 @@ public class NetworkStatsHistory implements Parcelable { // create any buckets needed by this range ensureBuckets(start, end); + // Return fast if there is still no entry. This would typically happen when the start, + // end or duration are not valid values, e.g. start > end, negative duration value, etc. + if (bucketCount == 0) return; // distribute data usage into buckets long duration = end - start; @@ -560,6 +563,9 @@ public class NetworkStatsHistory implements Parcelable { entry.txPackets = txPackets != null ? 0 : UNKNOWN; entry.operations = operations != null ? 0 : UNKNOWN; + // Return fast if there is no entry. + if (bucketCount == 0) return entry; + final int startIndex = getIndexAfter(end); for (int i = startIndex; i >= 0; i--) { final long curStart = bucketStart[i]; diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 5da8e259d0..9fa777d27c 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -49,7 +49,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; -import com.android.internal.util.ArrayUtils; +import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkIdentityUtils; import com.android.net.module.util.NetworkStatsUtils; @@ -703,7 +703,7 @@ public final class NetworkTemplate implements Parcelable { */ public boolean matchesSubscriberId(@Nullable String subscriberId) { return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); } /** @@ -723,8 +723,8 @@ public final class NetworkTemplate implements Parcelable { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds) + && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } } @@ -835,8 +835,8 @@ public final class NetworkTemplate implements Parcelable { */ private boolean matchesCarrier(NetworkIdentity ident) { return ident.mSubscriberId != null - && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && !CollectionUtils.isEmpty(mMatchSubscriberIds) + && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } private boolean matchesMobileWildcard(NetworkIdentity ident) { @@ -953,7 +953,7 @@ public final class NetworkTemplate implements Parcelable { if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { - if (ArrayUtils.contains(merged, template.mSubscriberId)) { + if (CollectionUtils.contains(merged, template.mSubscriberId)) { // Requested template subscriber is part of the merge group; return // a template that matches all merged subscribers. return new NetworkTemplate(template.mMatchRule, merged[0], merged, From 989b2128db294a79986860c91576e4e239985782 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 27 Dec 2021 13:56:59 +0000 Subject: [PATCH 1012/1150] [MS21] Remove DataUnit dependency DataUnit is a hidden class, remove the references to it from files that about to be moved into the module. Test: TH Bug: 204830222 Change-Id: Ibfb82ab74f283686fb2af6c3a550d541440c890d --- .../src/android/app/usage/NetworkStatsManager.java | 3 +-- framework-t/src/android/net/TrafficStats.java | 11 +++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index ca83309216..82c72ab1de 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -47,7 +47,6 @@ import android.os.Messenger; import android.os.RemoteException; import android.telephony.TelephonyManager; import android.text.TextUtils; -import android.util.DataUnit; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; @@ -119,7 +118,7 @@ public class NetworkStatsManager { * is reached. * @hide */ - public static final long MIN_THRESHOLD_BYTES = DataUnit.MEBIBYTES.toBytes(2); + public static final long MIN_THRESHOLD_BYTES = 2 * 1_048_576L; // 2MiB private final Context mContext; private final INetworkStatsService mService; diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index fa650617f3..d8feb88f0f 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -29,7 +29,6 @@ import android.media.MediaPlayer; import android.os.Build; import android.os.RemoteException; import android.os.ServiceManager; -import android.util.DataUnit; import com.android.server.NetworkManagementSocketTagger; @@ -59,19 +58,19 @@ public class TrafficStats { */ public final static int UNSUPPORTED = -1; - /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ @Deprecated public static final long KB_IN_BYTES = 1024; - /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ @Deprecated public static final long MB_IN_BYTES = KB_IN_BYTES * 1024; - /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ @Deprecated public static final long GB_IN_BYTES = MB_IN_BYTES * 1024; - /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ @Deprecated public static final long TB_IN_BYTES = GB_IN_BYTES * 1024; - /** @hide @deprecated use {@link DataUnit} instead to clarify SI-vs-IEC */ + /** @hide @deprecated use {@code DataUnit} instead to clarify SI-vs-IEC */ @Deprecated public static final long PB_IN_BYTES = TB_IN_BYTES * 1024; From 4f84ff37091d05733eceb7867bdfb619aca65052 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 28 Dec 2021 09:03:07 +0000 Subject: [PATCH 1013/1150] [MS26.1] Remove Process.NETWORK_STACK_UID dependency Check NetworkStack permission instead. Test: NetworkStatsAccessTest Bug: 204830222 Change-Id: I052a1422d145af533b036b0f017ace485b67cbfe --- framework-t/src/android/net/NetworkStatsAccess.java | 9 +++++++-- .../src/com/android/server/net/NetworkStatsService.java | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java index 591605d952..779fdf94a0 100644 --- a/framework-t/src/android/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java @@ -17,6 +17,7 @@ package android.net; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkStats.UID_ALL; import static android.net.TrafficStats.UID_REMOVED; import static android.net.TrafficStats.UID_TETHERING; @@ -106,7 +107,7 @@ public final class NetworkStatsAccess { /** Returns the {@link NetworkStatsAccess.Level} for the given caller. */ public static @NetworkStatsAccess.Level int checkAccessLevel( - Context context, int callingUid, String callingPackage) { + Context context, int callingPid, int callingUid, String callingPackage) { final DevicePolicyManager mDpm = context.getSystemService(DevicePolicyManager.class); final TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); @@ -123,8 +124,12 @@ public final class NetworkStatsAccess { final boolean isDeviceOwner = mDpm != null && mDpm.isDeviceOwnerApp(callingPackage); final int appId = UserHandle.getAppId(callingUid); + final boolean isNetworkStack = context.checkPermission( + android.Manifest.permission.NETWORK_STACK, callingPid, callingUid) + == PERMISSION_GRANTED; + if (hasCarrierPrivileges || isDeviceOwner - || appId == Process.SYSTEM_UID || appId == Process.NETWORK_STACK_UID) { + || appId == Process.SYSTEM_UID || isNetworkStack) { // Carrier-privileged apps and device owners, and the system (including the // network stack) can access data usage for all apps on the device. return NetworkStatsAccess.Level.DEVICE; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 2beca73ecd..748cc27d51 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -811,7 +811,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) { return NetworkStatsAccess.checkAccessLevel( - mContext, Binder.getCallingUid(), callingPackage); + mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage); } /** From 978ef03a6c830150e1520a069be55480316754f6 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 27 Dec 2021 15:40:22 +0000 Subject: [PATCH 1014/1150] [MS23] Remove UserHandle.getUserId dependencies Replaced with SystemApi. Test: TH Bug: 204830222 Change-Id: Ibc834489428c2036cd4ccd3284ba06c4c9e792b7 --- framework-t/src/android/net/NetworkStatsAccess.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java index 779fdf94a0..8980bbcbab 100644 --- a/framework-t/src/android/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java @@ -160,6 +160,8 @@ public final class NetworkStatsAccess { */ public static boolean isAccessibleToUser(int uid, int callerUid, @NetworkStatsAccess.Level int accessLevel) { + final int userId = UserHandle.getUserHandleForUid(uid).getIdentifier(); + final int callerUserId = UserHandle.getUserHandleForUid(callerUid).getIdentifier(); switch (accessLevel) { case NetworkStatsAccess.Level.DEVICE: // Device-level access - can access usage for any uid. @@ -170,13 +172,13 @@ public final class NetworkStatsAccess { // anonymized uids return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING || uid == UID_ALL - || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); + || userId == callerUserId; case NetworkStatsAccess.Level.USER: // User-level access - can access usage for any app running in the same user, along // with some special uids (system, removed, or tethering). return uid == android.os.Process.SYSTEM_UID || uid == UID_REMOVED || uid == UID_TETHERING - || UserHandle.getUserId(uid) == UserHandle.getUserId(callerUid); + || userId == callerUserId; case NetworkStatsAccess.Level.DEFAULT: default: // Default access level - can only access one's own usage. From 67b95e049e59d970f5f12d315082a389e0662503 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 28 Dec 2021 02:05:57 +0000 Subject: [PATCH 1015/1150] [MS25.1] Remove AppOpsManager.OP_GET_USAGE_STATS dependency Replaced by public interface. Test: TH Bug: 204830222 Change-Id: If7d17879b0ffdb6300373bc581cb07252fccfc7a --- framework-t/src/android/net/NetworkStatsAccess.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java index 8980bbcbab..b64fbdba9a 100644 --- a/framework-t/src/android/net/NetworkStatsAccess.java +++ b/framework-t/src/android/net/NetworkStatsAccess.java @@ -192,8 +192,8 @@ public final class NetworkStatsAccess { AppOpsManager appOps = (AppOpsManager) context.getSystemService( Context.APP_OPS_SERVICE); - final int mode = appOps.noteOp(AppOpsManager.OP_GET_USAGE_STATS, - callingUid, callingPackage); + final int mode = appOps.noteOp(AppOpsManager.OPSTR_GET_USAGE_STATS, + callingUid, callingPackage, null /* attributionTag */, null /* message */); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app // permission. From 04a367ebc1ce7725a6fddea0b94b863d1af2adad Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 30 Dec 2021 06:23:36 +0000 Subject: [PATCH 1016/1150] [MS28.1] Fix several hidden API dependencies This includes: 1. Replace Slog with Log 2. Use android.util.IndentingPrintWriter instead of the deprecated internal one. 3. Replace usages of ArrayUtils with CollectionUtils. 4. Reimplement DumpUtils#checkDumpPermission in PermissionUtils. 5. Replace MathUtils.constrain with NetworkStatsUtils.constrain Test: FrameworksNetTests Bug: 204830222 Change-Id: I2b064fc25497288d66018584e66da98c79bd208d --- .../server/net/NetworkStatsFactory.java | 4 +- .../server/net/NetworkStatsObservers.java | 27 ++++---- .../server/net/NetworkStatsRecorder.java | 11 ++-- .../server/net/NetworkStatsService.java | 62 ++++++++++--------- 4 files changed, 53 insertions(+), 51 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index e6433db11d..c7c8893ed8 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -35,8 +35,8 @@ import android.os.SystemClock; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; import com.android.internal.util.ProcFileReader; +import com.android.net.module.util.CollectionUtils; import libcore.io.IoUtils; @@ -434,7 +434,7 @@ public class NetworkStatsFactory { entry.txBytes = reader.nextLong(); entry.txPackets = reader.nextLong(); - if ((limitIfaces == null || ArrayUtils.contains(limitIfaces, entry.iface)) + if ((limitIfaces == null || CollectionUtils.contains(limitIfaces, entry.iface)) && (limitUid == UID_ALL || limitUid == entry.uid) && (limitTag == TAG_ALL || limitTag == entry.tag)) { stats.insertEntry(entry); diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index 1a0866d2f9..9aa20a4830 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -38,7 +38,7 @@ import android.os.Messenger; import android.os.Process; import android.os.RemoteException; import android.util.ArrayMap; -import android.util.Slog; +import android.util.Log; import android.util.SparseArray; import com.android.internal.annotations.VisibleForTesting; @@ -83,7 +83,7 @@ class NetworkStatsObservers { RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid, accessLevel); - if (LOGV) Slog.v(TAG, "Registering observer for " + request); + if (LOGV) Log.v(TAG, "Registering observer for " + request); getHandler().sendMessage(mHandler.obtainMessage(MSG_REGISTER, requestInfo)); return request; } @@ -116,7 +116,7 @@ class NetworkStatsObservers { if (mHandler == null) { synchronized (this) { if (mHandler == null) { - if (LOGV) Slog.v(TAG, "Creating handler"); + if (LOGV) Log.v(TAG, "Creating handler"); mHandler = new Handler(getHandlerLooperLocked(), mHandlerCallback); } } @@ -172,15 +172,15 @@ class NetworkStatsObservers { RequestInfo requestInfo; requestInfo = mDataUsageRequests.get(request.requestId); if (requestInfo == null) { - if (LOGV) Slog.v(TAG, "Trying to unregister unknown request " + request); + if (LOGV) Log.v(TAG, "Trying to unregister unknown request " + request); return; } if (Process.SYSTEM_UID != callingUid && requestInfo.mCallingUid != callingUid) { - Slog.w(TAG, "Caller uid " + callingUid + " is not owner of " + request); + Log.w(TAG, "Caller uid " + callingUid + " is not owner of " + request); return; } - if (LOGV) Slog.v(TAG, "Unregistering " + request); + if (LOGV) Log.v(TAG, "Unregistering " + request); mDataUsageRequests.remove(request.requestId); requestInfo.unlinkDeathRecipient(); requestInfo.callCallback(NetworkStatsManager.CALLBACK_RELEASED); @@ -201,7 +201,7 @@ class NetworkStatsObservers { // Cap the minimum threshold to a safe default to avoid too many callbacks long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes); if (thresholdInBytes < request.thresholdInBytes) { - Slog.w(TAG, "Threshold was too low for " + request + Log.w(TAG, "Threshold was too low for " + request + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); } return new DataUsageRequest(mNextDataUsageRequestId.incrementAndGet(), @@ -255,8 +255,9 @@ class NetworkStatsObservers { @Override public void binderDied() { - if (LOGV) Slog.v(TAG, "RequestInfo binderDied(" - + mRequest + ", " + mBinder + ")"); + if (LOGV) { + Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")"); + } mStatsObserver.unregister(mRequest, Process.SYSTEM_UID); callCallback(NetworkStatsManager.CALLBACK_RELEASED); } @@ -299,13 +300,13 @@ class NetworkStatsObservers { msg.setData(bundle); try { if (LOGV) { - Slog.v(TAG, "sending notification " + callbackTypeToName(callbackType) + Log.v(TAG, "sending notification " + callbackTypeToName(callbackType) + " for " + mRequest); } mMessenger.send(msg); } catch (RemoteException e) { // May occur naturally in the race of binder death. - Slog.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); + Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); } } @@ -341,7 +342,7 @@ class NetworkStatsObservers { protected boolean checkStats() { long bytesSoFar = getTotalBytesForNetwork(mRequest.template); if (LOGV) { - Slog.v(TAG, bytesSoFar + " bytes so far since notification for " + Log.v(TAG, bytesSoFar + " bytes so far since notification for " + mRequest.template); } if (bytesSoFar > mRequest.thresholdInBytes) { @@ -416,7 +417,7 @@ class NetworkStatsObservers { return history.getTotalBytes(); } catch (SecurityException e) { if (LOGV) { - Slog.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid " + Log.w(TAG, "CallerUid " + mCallingUid + " may have lost access to uid " + uid); } return 0; diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index 5e27c776cc..cec6609dc4 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -32,13 +32,12 @@ import android.net.TrafficStats; import android.os.Binder; import android.os.DropBoxManager; import android.service.NetworkStatsRecorderProto; +import android.util.IndentingPrintWriter; import android.util.Log; import android.util.MathUtils; -import android.util.Slog; import android.util.proto.ProtoOutputStream; import com.android.internal.util.FileRotator; -import com.android.internal.util.IndentingPrintWriter; import com.google.android.collect.Sets; @@ -132,7 +131,7 @@ public class NetworkStatsRecorder { } public void setPersistThreshold(long thresholdBytes) { - if (LOGV) Slog.v(TAG, "setPersistThreshold() with " + thresholdBytes); + if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes); mPersistThresholdBytes = MathUtils.constrain( thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES); } @@ -185,7 +184,7 @@ public class NetworkStatsRecorder { } private NetworkStatsCollection loadLocked(long start, long end) { - if (LOGD) Slog.d(TAG, "loadLocked() reading from disk for " + mCookie); + if (LOGD) Log.d(TAG, "loadLocked() reading from disk for " + mCookie); final NetworkStatsCollection res = new NetworkStatsCollection(mBucketDuration); try { mRotator.readMatching(res, start, end); @@ -272,7 +271,7 @@ public class NetworkStatsRecorder { mLastSnapshot = snapshot; if (LOGV && unknownIfaces.size() > 0) { - Slog.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); + Log.w(TAG, "unknown interfaces " + unknownIfaces + ", ignoring those stats"); } } @@ -296,7 +295,7 @@ public class NetworkStatsRecorder { public void forcePersistLocked(long currentTimeMillis) { Objects.requireNonNull(mRotator, "missing FileRotator"); if (mPending.isDirty()) { - if (LOGD) Slog.d(TAG, "forcePersistLocked() writing for " + mCookie); + if (LOGD) Log.d(TAG, "forcePersistLocked() writing for " + mCookie); try { mRotator.rewriteActive(mPendingRewriter, currentTimeMillis); mRotator.maybeRotate(currentTimeMillis); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 748cc27d51..44d7d1f668 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -141,19 +141,18 @@ import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; +import android.util.IndentingPrintWriter; import android.util.Log; -import android.util.MathUtils; -import android.util.Slog; import android.util.SparseIntArray; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.ArrayUtils; -import com.android.internal.util.DumpUtils; import com.android.internal.util.FileRotator; -import com.android.internal.util.IndentingPrintWriter; import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.NetworkStatsUtils; +import com.android.net.module.util.PermissionUtils; import com.android.server.EventLogTags; import com.android.server.LocalServices; @@ -163,6 +162,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.time.Clock; import java.time.ZoneOffset; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; @@ -646,7 +646,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { try { mNetworkManager.setGlobalAlert(mGlobalAlertBytes); } catch (IllegalStateException e) { - Slog.w(TAG, "problem registering for global alert: " + e); + Log.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { // ignored; service lives in system_server } @@ -766,7 +766,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return stats; } catch (NullPointerException e) { // TODO: Track down and fix the cause of this crash and remove this catch block. - Slog.wtf(TAG, "NullPointerException in getSummaryForAllUid", e); + Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e); throw e; } } @@ -823,7 +823,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { SubscriptionPlan plan = null; if ((flags & NetworkStatsManager.FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN) != 0 && mSettings.getAugmentEnabled()) { - if (LOGD) Slog.d(TAG, "Resolving plan for " + template); + if (LOGD) Log.d(TAG, "Resolving plan for " + template); final long token = Binder.clearCallingIdentity(); try { plan = LocalServices.getService(NetworkPolicyManagerInternal.class) @@ -831,7 +831,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } finally { Binder.restoreCallingIdentity(token); } - if (LOGD) Slog.d(TAG, "Resolved to plan " + plan); + if (LOGD) Log.d(TAG, "Resolved to plan " + plan); } return plan; } @@ -936,7 +936,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public String[] getMobileIfaces() { // TODO (b/192758557): Remove debug log. - if (ArrayUtils.contains(mMobileIfaces, null)) { + if (CollectionUtils.contains(mMobileIfaces, null)) { throw new NullPointerException( "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); } @@ -1014,9 +1014,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void advisePersistThreshold(long thresholdBytes) { // clamp threshold into safe range - mPersistThreshold = MathUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); + mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes, + 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); if (LOGV) { - Slog.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " + Log.v(TAG, "advisePersistThreshold() given " + thresholdBytes + ", clamped to " + mPersistThreshold); } @@ -1279,7 +1280,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void handleNotifyNetworkStatusLocked(@NonNull Network[] defaultNetworks, @NonNull NetworkStateSnapshot[] snapshots) { if (!mSystemReady) return; - if (LOGV) Slog.v(TAG, "handleNotifyNetworkStatusLocked()"); + if (LOGV) Log.v(TAG, "handleNotifyNetworkStatusLocked()"); // take one last stats snapshot before updating iface mapping. this // isn't perfect, since the kernel may already be counting traffic from @@ -1303,7 +1304,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final int displayTransport = getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); - final boolean isDefault = ArrayUtils.contains(mDefaultNetworks, snapshot.getNetwork()); + final boolean isDefault = CollectionUtils.contains( + mDefaultNetworks, snapshot.getNetwork()); final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED : getSubTypeForStateSnapshot(snapshot); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, @@ -1386,7 +1388,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mMobileIfaces = mobileIfaces.toArray(new String[0]); // TODO (b/192758557): Remove debug log. - if (ArrayUtils.contains(mMobileIfaces, null)) { + if (CollectionUtils.contains(mMobileIfaces, null)) { throw new NullPointerException( "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); } @@ -1401,7 +1403,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (spec instanceof TelephonyNetworkSpecifier) { return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); } else { - Slog.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); + Log.wtf(TAG, "getSubIdForState invalid NetworkSpecifier"); return INVALID_SUBSCRIPTION_ID; } } @@ -1485,7 +1487,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { try { recordSnapshotLocked(currentTime); } catch (IllegalStateException e) { - Slog.w(TAG, "problem reading network stats: " + e); + Log.w(TAG, "problem reading network stats: " + e); } catch (RemoteException e) { // ignored; service lives in system_server } @@ -1510,7 +1512,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private void performPollLocked(int flags) { if (!mSystemReady) return; - if (LOGV) Slog.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); + if (LOGV) Log.v(TAG, "performPollLocked(flags=0x" + Integer.toHexString(flags) + ")"); Trace.traceBegin(TRACE_TAG_NETWORK, "performPollLocked"); final boolean persistNetwork = (flags & FLAG_PERSIST_NETWORK) != 0; @@ -1632,7 +1634,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @GuardedBy("mStatsLock") private void removeUidsLocked(int... uids) { - if (LOGV) Slog.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); + if (LOGV) Log.v(TAG, "removeUidsLocked() for UIDs " + Arrays.toString(uids)); // Perform one last poll before removing performPollLocked(FLAG_PERSIST_ALL); @@ -1651,19 +1653,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @GuardedBy("mStatsLock") private void removeUserLocked(int userId) { - if (LOGV) Slog.v(TAG, "removeUserLocked() for userId=" + userId); + if (LOGV) Log.v(TAG, "removeUserLocked() for userId=" + userId); // Build list of UIDs that we should clean up - int[] uids = new int[0]; + final ArrayList uids = new ArrayList<>(); final List apps = mContext.getPackageManager().getInstalledApplications( PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS); for (ApplicationInfo app : apps) { final int uid = UserHandle.getUid(userId, app.uid); - uids = ArrayUtils.appendInt(uids, uid); + uids.add(uid); } - removeUidsLocked(uids); + removeUidsLocked(CollectionUtils.toIntArray(uids)); } private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal { @@ -1706,7 +1708,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void setStatsProviderWarningAndLimitAsync( @NonNull String iface, long warning, long limit) { if (LOGV) { - Slog.v(TAG, "setStatsProviderWarningAndLimitAsync(" + Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" + iface + "," + warning + "," + limit + ")"); } invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, @@ -1716,7 +1718,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override protected void dump(FileDescriptor fd, PrintWriter rawWriter, String[] args) { - if (!DumpUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; + if (!PermissionUtils.checkDumpPermission(mContext, TAG, rawWriter)) return; long duration = DateUtils.DAY_IN_MILLIS; final HashSet argSet = new HashSet(); @@ -1777,15 +1779,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { pw.println("Configs:"); pw.increaseIndent(); - pw.printPair(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); + pw.print(NETSTATS_COMBINE_SUBTYPE_ENABLED, mSettings.getCombineSubtypeEnabled()); pw.println(); pw.decreaseIndent(); pw.println("Active interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveIfaces.size(); i++) { - pw.printPair("iface", mActiveIfaces.keyAt(i)); - pw.printPair("ident", mActiveIfaces.valueAt(i)); + pw.print("iface", mActiveIfaces.keyAt(i)); + pw.print("ident", mActiveIfaces.valueAt(i)); pw.println(); } pw.decreaseIndent(); @@ -1793,8 +1795,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { pw.println("Active UID interfaces:"); pw.increaseIndent(); for (int i = 0; i < mActiveUidIfaces.size(); i++) { - pw.printPair("iface", mActiveUidIfaces.keyAt(i)); - pw.printPair("ident", mActiveUidIfaces.valueAt(i)); + pw.print("iface", mActiveUidIfaces.keyAt(i)); + pw.print("ident", mActiveUidIfaces.valueAt(i)); pw.println(); } pw.decreaseIndent(); From c70871f60a3635b4ccf83155d970c076ebe533f3 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Thu, 23 Dec 2021 11:45:02 +0800 Subject: [PATCH 1017/1150] wifi data usage: replaced Wi-Fi SSID with a Wi-Fi network key 1. Used SSID to be a wifi network identity can't separate wifi data usage when there are two different network with same SSID. Use a new usage key from WifiInfo to replace wifi SSID to solve this issue. 2. To support to query wifi usage per configured Wifi network. Adding matchWifiNetworkKeys in NetworkTemplate to support querying multi networkKeys wifi data usage since each configured Wifi network configuration might be used to connect different Wifi network. (Replace mNetworkId with mMatchWifiNetworkKeys) 3. Updated callers who were using NetworkTemplate constructor. 4. Fixed SortedSet null order case. The null subscriberId is a valid input for matchSubscriberIds. 5. Replaced ArrayUtils with CollectionUtils. Bug: 197520752 Bug: 126299427 Test: atest -c NetworkTemplateTest Test: atest -c NetworkStatsServiceTest Test: atest -c NetworkPolicyManagerServiceTest Test: atest -c NetworkPolicyTest Change-Id: Ie20e7fb56597817901be4ce1d2a7afcbc9ded0c6 --- .../src/android/net/NetworkIdentity.java | 11 +- .../src/android/net/NetworkTemplate.java | 183 +++++++++++------- 2 files changed, 121 insertions(+), 73 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index eb8f43e3d0..8f1115e065 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -21,7 +21,6 @@ import static android.net.ConnectivityManager.TYPE_WIFI; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; -import android.net.wifi.WifiManager; import android.service.NetworkIdentityProto; import android.telephony.Annotation.NetworkType; import android.util.proto.ProtoOutputStream; @@ -228,11 +227,11 @@ public class NetworkIdentity implements Comparable { final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); if (legacyType == TYPE_WIFI) { - networkId = snapshot.getNetworkCapabilities().getSsid(); - if (networkId == null) { - final WifiManager wifi = context.getSystemService(WifiManager.class); - final WifiInfo info = wifi.getConnectionInfo(); - networkId = info != null ? info.getSSID() : null; + final TransportInfo transportInfo = snapshot.getNetworkCapabilities() + .getTransportInfo(); + if (transportInfo instanceof WifiInfo) { + final WifiInfo info = (WifiInfo) transportInfo; + networkId = info != null ? info.getCurrentNetworkKey() : null; } } diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 5da8e259d0..659ad06039 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -35,7 +35,6 @@ import static android.net.NetworkStats.METERED_YES; import static android.net.NetworkStats.ROAMING_ALL; import static android.net.NetworkStats.ROAMING_NO; import static android.net.NetworkStats.ROAMING_YES; -import static android.net.wifi.WifiInfo.sanitizeSsid; import android.annotation.IntDef; import android.annotation.NonNull; @@ -49,7 +48,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; -import com.android.internal.util.ArrayUtils; +import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkIdentityUtils; import com.android.net.module.util.NetworkStatsUtils; @@ -57,6 +56,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.Collection; +import java.util.Comparator; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -213,11 +213,14 @@ public final class NetworkTemplate implements Parcelable { public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, @NetworkType int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { - return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null, null, null, - metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, + return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */, + null /* matchSubscriberIds */, + new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL, + DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } - return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[]{subscriberId}, null, + return new NetworkTemplate(MATCH_MOBILE, subscriberId, new String[] { subscriberId }, + new String[0] /* matchWifiNetworkKeys */, metered, ROAMING_ALL, DEFAULT_NETWORK_ALL, ratType, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -235,7 +238,7 @@ public final class NetworkTemplate implements Parcelable { /** * Template to match all metered {@link ConnectivityManager#TYPE_WIFI} networks, - * regardless of SSID. + * regardless of key of the wifi network. * * @hide */ @@ -255,33 +258,40 @@ public final class NetworkTemplate implements Parcelable { /** * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the - * given SSID. + * given key of the wifi network. * + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * to know details about the key. * @hide */ - public static NetworkTemplate buildTemplateWifi(@NonNull String networkId) { - Objects.requireNonNull(networkId); + public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) { + Objects.requireNonNull(wifiNetworkKey); return new NetworkTemplate(MATCH_WIFI, null /* subscriberId */, new String[] { null } /* matchSubscriberIds */, - networkId, METERED_ALL, ROAMING_ALL, + new String[] { wifiNetworkKey }, METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL); } /** - * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given SSID, - * and IMSI. + * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks with the given + * key of the wifi network and IMSI. * - * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code networkId} to get result regardless - * of SSID. + * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless + * of key of the wifi network. + * + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * to know details about the key. + * @param subscriberId the IMSI associated to this wifi network. * * @hide */ - public static NetworkTemplate buildTemplateWifi(@Nullable String networkId, + public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey, @Nullable String subscriberId) { return new NetworkTemplate(MATCH_WIFI, subscriberId, new String[] { subscriberId }, - networkId, METERED_ALL, ROAMING_ALL, - DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, + wifiNetworkKey != null + ? new String[] { wifiNetworkKey } : new String[0], + METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -324,7 +334,9 @@ public final class NetworkTemplate implements Parcelable { public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) { Objects.requireNonNull(subscriberId); return new NetworkTemplate(MATCH_CARRIER, subscriberId, - new String[] { subscriberId }, null /* networkId */, METERED_YES, ROAMING_ALL, + new String[] { subscriberId }, + new String[0] /* matchWifiNetworkKeys */, + METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } @@ -342,8 +354,8 @@ public final class NetworkTemplate implements Parcelable { */ private final String[] mMatchSubscriberIds; - // TODO: Change variable name to match the Api surface. - private final String mNetworkId; + @NonNull + private final String[] mMatchWifiNetworkKeys; // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. private final int mMetered; @@ -377,18 +389,19 @@ public final class NetworkTemplate implements Parcelable { /** @hide */ // TODO: Deprecate this constructor, mark it @UnsupportedAppUsage(maxTargetSdk = S) @UnsupportedAppUsage - public NetworkTemplate(int matchRule, String subscriberId, String networkId) { - this(matchRule, subscriberId, new String[] { subscriberId }, networkId); + public NetworkTemplate(int matchRule, String subscriberId, String wifiNetworkKey) { + this(matchRule, subscriberId, new String[] { subscriberId }, wifiNetworkKey); } /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId) { + String wifiNetworkKey) { // Older versions used to only match MATCH_MOBILE and MATCH_MOBILE_WILDCARD templates // to metered networks. It is now possible to match mobile with any meteredness, but // in order to preserve backward compatibility of @UnsupportedAppUsage methods, this //constructor passes METERED_YES for these types. - this(matchRule, subscriberId, matchSubscriberIds, networkId, + this(matchRule, subscriberId, matchSubscriberIds, + wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD) ? METERED_YES : METERED_ALL , ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); @@ -397,23 +410,25 @@ public final class NetworkTemplate implements Parcelable { /** @hide */ // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork, int subType, + String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType, int oemManaged) { - this(matchRule, subscriberId, matchSubscriberIds, networkId, metered, roaming, - defaultNetwork, subType, oemManaged, + this(matchRule, subscriberId, matchSubscriberIds, + wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], + metered, roaming, defaultNetwork, subType, oemManaged, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String networkId, int metered, int roaming, int defaultNetwork, int subType, - int oemManaged, int subscriberIdMatchRule) { + String[] matchWifiNetworkKeys, int metered, int roaming, + int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) { + Objects.requireNonNull(matchWifiNetworkKeys); mMatchRule = matchRule; mSubscriberId = subscriberId; // TODO: Check whether mMatchSubscriberIds = null or mMatchSubscriberIds = {null} when // mSubscriberId is null mMatchSubscriberIds = matchSubscriberIds; - mNetworkId = networkId; + mMatchWifiNetworkKeys = matchWifiNetworkKeys; mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; @@ -431,7 +446,7 @@ public final class NetworkTemplate implements Parcelable { mMatchRule = in.readInt(); mSubscriberId = in.readString(); mMatchSubscriberIds = in.createStringArray(); - mNetworkId = in.readString(); + mMatchWifiNetworkKeys = in.createStringArray(); mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); @@ -445,7 +460,7 @@ public final class NetworkTemplate implements Parcelable { dest.writeInt(mMatchRule); dest.writeString(mSubscriberId); dest.writeStringArray(mMatchSubscriberIds); - dest.writeString(mNetworkId); + dest.writeStringArray(mMatchWifiNetworkKeys); dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); @@ -471,9 +486,7 @@ public final class NetworkTemplate implements Parcelable { builder.append(", matchSubscriberIds=").append( Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds))); } - if (mNetworkId != null) { - builder.append(", networkId=").append(mNetworkId); - } + builder.append(", matchWifiNetworkKeys=").append(Arrays.toString(mMatchWifiNetworkKeys)); if (mMetered != METERED_ALL) { builder.append(", metered=").append(NetworkStats.meteredToString(mMetered)); } @@ -497,8 +510,8 @@ public final class NetworkTemplate implements Parcelable { @Override public int hashCode() { - return Objects.hash(mMatchRule, mSubscriberId, mNetworkId, mMetered, mRoaming, - mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); + return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys), + mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -507,13 +520,13 @@ public final class NetworkTemplate implements Parcelable { final NetworkTemplate other = (NetworkTemplate) obj; return mMatchRule == other.mMatchRule && Objects.equals(mSubscriberId, other.mSubscriberId) - && Objects.equals(mNetworkId, other.mNetworkId) && mMetered == other.mMetered && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork && mSubType == other.mSubType && mOemManaged == other.mOemManaged - && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule; + && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule + && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); } return false; } @@ -579,14 +592,22 @@ public final class NetworkTemplate implements Parcelable { */ @Nullable public String getWifiNetworkKey() { - return mNetworkId; + return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0]; + } + + /** + * Get set of Wifi Network Keys of the template. + */ + @Nullable + public Set getWifiNetworkKeys() { + return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys)); } /** @hide */ // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}. @Nullable public String getNetworkId() { - return mNetworkId; + return getWifiNetworkKey(); } /** @@ -703,28 +724,33 @@ public final class NetworkTemplate implements Parcelable { */ public boolean matchesSubscriberId(@Nullable String subscriberId) { return mSubscriberIdMatchRule == NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_ALL - || ArrayUtils.contains(mMatchSubscriberIds, subscriberId); + || CollectionUtils.contains(mMatchSubscriberIds, subscriberId); } /** - * Check if network with matching SSID. Returns true when the SSID matches, or when - * {@code mNetworkId} is {@code WIFI_NETWORK_KEY_ALL}. + * Check if network matches key of the wifi network. + * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is + * empty. + * + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * to know details about the key. */ - private boolean matchesWifiNetworkId(@Nullable String networkId) { - return Objects.equals(mNetworkId, WIFI_NETWORK_KEY_ALL) - || Objects.equals(sanitizeSsid(mNetworkId), sanitizeSsid(networkId)); + private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { + Objects.requireNonNull(wifiNetworkKey); + return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) + || CollectionUtils.contains(mMatchWifiNetworkKeys, wifiNetworkKey); } /** - * Check if mobile network with matching IMSI. + * Check if mobile network matches IMSI. */ private boolean matchesMobile(NetworkIdentity ident) { if (ident.mType == TYPE_WIMAX) { // TODO: consider matching against WiMAX subscriber identity return true; } else { - return ident.mType == TYPE_MOBILE && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) + return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds) + && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId) && matchesCollapsedRatType(ident); } } @@ -814,7 +840,7 @@ public final class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return matchesSubscriberId(ident.mSubscriberId) - && matchesWifiNetworkId(ident.mNetworkId); + && matchesWifiNetworkKey(ident.mNetworkId); default: return false; } @@ -835,8 +861,8 @@ public final class NetworkTemplate implements Parcelable { */ private boolean matchesCarrier(NetworkIdentity ident) { return ident.mSubscriberId != null - && !ArrayUtils.isEmpty(mMatchSubscriberIds) - && ArrayUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); + && !CollectionUtils.isEmpty(mMatchSubscriberIds) + && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId); } private boolean matchesMobileWildcard(NetworkIdentity ident) { @@ -953,11 +979,13 @@ public final class NetworkTemplate implements Parcelable { if (template.mSubscriberId == null) return template; for (String[] merged : mergedList) { - if (ArrayUtils.contains(merged, template.mSubscriberId)) { + if (CollectionUtils.contains(merged, template.mSubscriberId)) { // Requested template subscriber is part of the merge group; return // a template that matches all merged subscribers. + final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys; return new NetworkTemplate(template.mMatchRule, merged[0], merged, - template.mNetworkId); + CollectionUtils.isEmpty(matchWifiNetworkKeys) + ? null : matchWifiNetworkKeys[0]); } } @@ -984,9 +1012,10 @@ public final class NetworkTemplate implements Parcelable { private final int mMatchRule; // Use a SortedSet to provide a deterministic order when fetching the first one. @NonNull - private final SortedSet mMatchSubscriberIds = new TreeSet<>(); - @Nullable - private String mWifiNetworkKey; + private final SortedSet mMatchSubscriberIds = + new TreeSet<>(Comparator.nullsFirst(Comparator.naturalOrder())); + @NonNull + private final SortedSet mMatchWifiNetworkKeys = new TreeSet<>(); // Matches for the NetworkStats constants METERED_*, ROAMING_* and DEFAULT_NETWORK_*. private int mMetered; @@ -1006,7 +1035,6 @@ public final class NetworkTemplate implements Parcelable { assertRequestableMatchRule(matchRule); // Initialize members with default values. mMatchRule = matchRule; - mWifiNetworkKey = WIFI_NETWORK_KEY_ALL; mMetered = METERED_ALL; mRoaming = ROAMING_ALL; mDefaultNetwork = DEFAULT_NETWORK_ALL; @@ -1030,15 +1058,28 @@ public final class NetworkTemplate implements Parcelable { } /** - * Set the Wifi Network Key. + * Set the Wifi Network Keys. Calling this function with an empty set represents + * the intention of matching any Wifi Network Key. * - * @param wifiNetworkKey the Wifi Network Key, see {@link WifiInfo#getCurrentNetworkKey()}. - * Or null to match all networks. + * @param wifiNetworkKeys the list of Wifi Network Key, + * see {@link WifiInfo#getCurrentNetworkKey()}. + * Or an empty list to match all networks. + * Note that {@code getCurrentNetworkKey()} might get null key + * when wifi disconnects. However, the caller should never invoke + * this function with a null Wifi Network Key since such statistics + * never exists. * @return this builder. */ @NonNull - public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { - mWifiNetworkKey = wifiNetworkKey; + public Builder setWifiNetworkKeys(@NonNull Set wifiNetworkKeys) { + Objects.requireNonNull(wifiNetworkKeys); + for (String key : wifiNetworkKeys) { + if (key == null) { + throw new IllegalArgumentException("Null is not a valid key"); + } + } + mMatchWifiNetworkKeys.clear(); + mMatchWifiNetworkKeys.addAll(wifiNetworkKeys); return this; } @@ -1122,9 +1163,17 @@ public final class NetworkTemplate implements Parcelable { } private void assertRequestableParameters() { + validateWifiNetworkKeys(); // TODO: Check all the input are legitimate. } + private void validateWifiNetworkKeys() { + if (mMatchRule != MATCH_WIFI && !mMatchWifiNetworkKeys.isEmpty()) { + throw new IllegalArgumentException("Trying to build non wifi match rule: " + + mMatchRule + " with wifi network keys"); + } + } + /** * For backward compatibility, deduce match rule to a wildcard match rule * if the Subscriber Ids are empty. @@ -1133,7 +1182,7 @@ public final class NetworkTemplate implements Parcelable { if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) { return MATCH_MOBILE_WILDCARD; } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty() - && mWifiNetworkKey == WIFI_NETWORK_KEY_ALL) { + && mMatchWifiNetworkKeys.isEmpty()) { return MATCH_WIFI_WILDCARD; } return mMatchRule; @@ -1153,8 +1202,8 @@ public final class NetworkTemplate implements Parcelable { return new NetworkTemplate(getWildcardDeducedMatchRule(), mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(), mMatchSubscriberIds.toArray(new String[0]), - mWifiNetworkKey, mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, - subscriberIdMatchRule); + mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming, + mDefaultNetwork, mRatType, mOemManaged, subscriberIdMatchRule); } } } From 6acd545fe15f016db5724e156b0d0e8ac8b751ba Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Dec 2021 03:23:02 +0800 Subject: [PATCH 1018/1150] Use public resouce in android.R package Use public resource since IpSec is planed to be moved into Connectivity mainline module. Bug: 204153604 Test: build Change-Id: I0aafef6b9b08307c3aebce597a2dd24925c6b09a --- framework-t/src/android/net/IpSecAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java index a84e7a9c63..10a22ac360 100644 --- a/framework-t/src/android/net/IpSecAlgorithm.java +++ b/framework-t/src/android/net/IpSecAlgorithm.java @@ -343,7 +343,7 @@ public final class IpSecAlgorithm implements Parcelable { // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in // the resource are not allowed. final String[] resourceAlgos = systemResources.getStringArray( - com.android.internal.R.array.config_optionalIpSecAlgorithms); + android.R.array.config_optionalIpSecAlgorithms); for (String str : resourceAlgos) { if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { // This error should be caught by CTS and never be thrown to API callers From 9426a6f03488c78f1581c13d9a1119bc1baee840 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 30 Dec 2021 10:49:29 +0000 Subject: [PATCH 1019/1150] [MS31] Fix several hidden API usages This includes: 1. Replace UserHandle.getUid(userId, appId) with public API 2. Remove Preconditions.checkArgument 3. Replace MathUtil.constrain with the one in NetworkStatsUtils 4. Remove Sets 5. Replace NetworkStack.checkNetworkStackPermission with the one in the PermissionUtils 6. Replace internal CollectionUtils with the one in the module 7. Inline ProtoOutputStream(fd) 8. Replace Intent.EXTRA_USER_HANDLE with Intent.EXTRA_USER Test: atest NetworkStatsSubscriptionsMonitorTest \ NetworkStatsServiceTest Bug: 204830222 Change-Id: If06a27b04ad15c29052b670eefc2f6dc0d199420 --- .../server/net/NetworkStatsObservers.java | 7 ++--- .../server/net/NetworkStatsRecorder.java | 8 +++--- .../server/net/NetworkStatsService.java | 20 +++++++------- .../net/NetworkStatsSubscriptionsMonitor.java | 26 ++++++++++--------- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index 9aa20a4830..b57a4f920b 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -18,8 +18,6 @@ package com.android.server.net; import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; -import static com.android.internal.util.Preconditions.checkArgument; - import android.app.usage.NetworkStatsManager; import android.net.DataUsageRequest; import android.net.NetworkIdentitySet; @@ -216,7 +214,10 @@ class NetworkStatsObservers { accessLevel); } else { // Safety check in case a new access level is added and we forgot to update this - checkArgument(accessLevel >= NetworkStatsAccess.Level.DEVICESUMMARY); + if (accessLevel < NetworkStatsAccess.Level.DEVICESUMMARY) { + throw new IllegalArgumentException( + "accessLevel " + accessLevel + " is less than DEVICESUMMARY."); + } return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid, accessLevel); } diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index cec6609dc4..c371f0859a 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -34,12 +34,10 @@ import android.os.DropBoxManager; import android.service.NetworkStatsRecorderProto; import android.util.IndentingPrintWriter; import android.util.Log; -import android.util.MathUtils; import android.util.proto.ProtoOutputStream; import com.android.internal.util.FileRotator; - -import com.google.android.collect.Sets; +import com.android.net.module.util.NetworkStatsUtils; import libcore.io.IoUtils; @@ -132,7 +130,7 @@ public class NetworkStatsRecorder { public void setPersistThreshold(long thresholdBytes) { if (LOGV) Log.v(TAG, "setPersistThreshold() with " + thresholdBytes); - mPersistThresholdBytes = MathUtils.constrain( + mPersistThresholdBytes = NetworkStatsUtils.constrain( thresholdBytes, 1 * KB_IN_BYTES, 100 * MB_IN_BYTES); } @@ -206,7 +204,7 @@ public class NetworkStatsRecorder { */ public void recordSnapshotLocked(NetworkStats snapshot, Map ifaceIdent, long currentTimeMillis) { - final HashSet unknownIfaces = Sets.newHashSet(); + final HashSet unknownIfaces = new HashSet<>(); // skip recording when snapshot missing if (snapshot == null) return; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 44d7d1f668..4fd62c1ad5 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -25,7 +25,6 @@ import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.net.NetworkIdentity.SUBTYPE_COMBINED; -import static android.net.NetworkStack.checkNetworkStackPermission; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.IFACE_VT; @@ -158,6 +157,7 @@ import com.android.server.LocalServices; import java.io.File; import java.io.FileDescriptor; +import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; import java.time.Clock; @@ -985,7 +985,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull NetworkStateSnapshot[] networkStates, @Nullable String activeIface, @NonNull UnderlyingNetworkInfo[] underlyingNetworkInfos) { - checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); try { @@ -1201,13 +1201,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // On background handler thread, and USER_REMOVED is protected // broadcast. - final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); - if (userId == -1) return; + final UserHandle userHandle = intent.getParcelableExtra(Intent.EXTRA_USER); + if (userHandle == null) return; synchronized (mStatsLock) { mWakeLock.acquire(); try { - removeUserLocked(userId); + removeUserLocked(userHandle); } finally { mWakeLock.release(); } @@ -1232,7 +1232,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void limitReached(String limitName, String iface) { // only someone like NMS should be calling us - NetworkStack.checkNetworkStackPermission(mContext); + PermissionUtils.enforceNetworkStackPermission(mContext); if (LIMIT_GLOBAL_ALERT.equals(limitName)) { // kick off background poll to collect network stats unless there is already @@ -1652,8 +1652,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * Clean up {@link #mUidRecorder} after user is removed. */ @GuardedBy("mStatsLock") - private void removeUserLocked(int userId) { - if (LOGV) Log.v(TAG, "removeUserLocked() for userId=" + userId); + private void removeUserLocked(@NonNull UserHandle userHandle) { + if (LOGV) Log.v(TAG, "removeUserLocked() for UserHandle=" + userHandle); // Build list of UIDs that we should clean up final ArrayList uids = new ArrayList<>(); @@ -1661,7 +1661,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PackageManager.MATCH_ANY_USER | PackageManager.MATCH_DISABLED_COMPONENTS); for (ApplicationInfo app : apps) { - final int uid = UserHandle.getUid(userId, app.uid); + final int uid = userHandle.getUid(app.uid); uids.add(uid); } @@ -1869,7 +1869,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private void dumpProtoLocked(FileDescriptor fd) { - final ProtoOutputStream proto = new ProtoOutputStream(fd); + final ProtoOutputStream proto = new ProtoOutputStream(new FileOutputStream(fd)); // TODO Right now it writes all history. Should it limit to the "since-boot" log? diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 5646c752fc..93d0ae7da0 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -33,7 +33,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.CollectionUtils; +import com.android.net.module.util.CollectionUtils; import java.util.ArrayList; import java.util.List; @@ -99,18 +99,19 @@ public class NetworkStatsSubscriptionsMonitor extends // prevent binder call to telephony when querying RAT. Keep listener registration with empty // IMSI is meaningless since the RAT type changed is ambiguous for multi-SIM if reported // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. - final List> filteredNewSubs = - CollectionUtils.mapNotNull(newSubs, subId -> { - final String subscriberId = mTeleManager.getSubscriberId(subId); - return TextUtils.isEmpty(subscriberId) ? null : new Pair(subId, subscriberId); - }); + final List> filteredNewSubs = new ArrayList<>(); + for (final int subId : newSubs) { + final String subscriberId = mTeleManager.getSubscriberId(subId); + if (!TextUtils.isEmpty(subscriberId)) { + filteredNewSubs.add(new Pair(subId, subscriberId)); + } + } for (final Pair sub : filteredNewSubs) { // Fully match listener with subId and IMSI, since in some rare cases, IMSI might be // suddenly change regardless of subId, such as switch IMSI feature in modem side. // If that happens, register new listener with new IMSI and remove old one later. - if (CollectionUtils.find(mRatListeners, - it -> it.equalsKey(sub.first, sub.second)) != null) { + if (CollectionUtils.any(mRatListeners, it -> it.equalsKey(sub.first, sub.second))) { continue; } @@ -126,8 +127,8 @@ public class NetworkStatsSubscriptionsMonitor extends for (final RatTypeListener listener : new ArrayList<>(mRatListeners)) { // If there is no subId and IMSI matched the listener, removes it. - if (CollectionUtils.find(filteredNewSubs, - it -> listener.equalsKey(it.first, it.second)) == null) { + if (!CollectionUtils.any(filteredNewSubs, + it -> listener.equalsKey(it.first, it.second))) { handleRemoveRatTypeListener(listener); } } @@ -148,9 +149,10 @@ public class NetworkStatsSubscriptionsMonitor extends * @return collapsed RatType for the given subscriberId */ public int getRatTypeForSubscriberId(@NonNull String subscriberId) { - final RatTypeListener match = CollectionUtils.find(mRatListeners, + final int index = CollectionUtils.indexOf(mRatListeners, it -> TextUtils.equals(subscriberId, it.mSubscriberId)); - return match != null ? match.mLastCollapsedRatType : TelephonyManager.NETWORK_TYPE_UNKNOWN; + return index != -1 ? mRatListeners.get(index).mLastCollapsedRatType + : TelephonyManager.NETWORK_TYPE_UNKNOWN; } /** From 1d1c2d22c78d2d96712460f5d0e916fcedcfd722 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 3 Jan 2022 12:30:03 +0000 Subject: [PATCH 1020/1150] [MS33.1] Remove NetdService dependency This change pass INetd to NetworkStatsFactory to replace NetdService#getNetdInstance. Test: atest FrameworksNetTests Bug: 204830222 Change-Id: I39b278989cea06dd316f21214380b5c4b54d2d50 --- .../android/server/net/NetworkStatsFactory.java | 16 +++++++--------- .../android/server/net/NetworkStatsService.java | 6 ++++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index c7c8893ed8..bb123a38eb 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -24,11 +24,11 @@ import static android.net.NetworkStats.UID_ALL; import static com.android.server.NetworkManagementSocketTagger.kernelToTag; +import android.annotation.NonNull; import android.annotation.Nullable; import android.net.INetd; import android.net.NetworkStats; import android.net.UnderlyingNetworkInfo; -import android.net.util.NetdService; import android.os.RemoteException; import android.os.StrictMode; import android.os.SystemClock; @@ -70,7 +70,7 @@ public class NetworkStatsFactory { private final boolean mUseBpfStats; - private INetd mNetdService; + private final INetd mNetd; /** * Guards persistent data access in this class @@ -158,12 +158,12 @@ public class NetworkStatsFactory { NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } - public NetworkStatsFactory() { - this(new File("/proc/"), true); + public NetworkStatsFactory(@NonNull INetd netd) { + this(new File("/proc/"), true, netd); } @VisibleForTesting - public NetworkStatsFactory(File procRoot, boolean useBpfStats) { + public NetworkStatsFactory(File procRoot, boolean useBpfStats, @NonNull INetd netd) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); @@ -172,6 +172,7 @@ public class NetworkStatsFactory { mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } + mNetd = netd; } public NetworkStats readBpfNetworkStatsDev() throws IOException { @@ -298,10 +299,7 @@ public class NetworkStatsFactory { // Ask netd to do a active map stats swap. When the binder call successfully returns, // the system server should be able to safely read and clean the inactive map // without race problem. - if (mNetdService == null) { - mNetdService = NetdService.getInstance(); - } - mNetdService.trafficSwapActiveStatsMap(); + mNetd.trafficSwapActiveStatsMap(); } /** diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index a3de9e4ba7..ef84ce02e2 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -89,6 +89,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.DataUsageRequest; +import android.net.INetd; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -410,10 +411,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - + final INetd netd = INetd.Stub.asInterface( + (IBinder) context.getSystemService(Context.NETD_SERVICE)); final NetworkStatsService service = new NetworkStatsService(context, networkManager, alarmManager, wakeLock, getDefaultClock(), - new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(), + new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); service.registerLocalService(); From 0dbd0c8d26252c44b5a30c3d8c76620b6326e96e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 5 Jan 2022 08:09:16 +0000 Subject: [PATCH 1021/1150] [MS40.1] Remove Clock dependencies from NetworkStatsService This includes: 1. Re-implement the BestClock in the static library. 2. Expose SystemClock#currentNetworkTimeClock as public Api Test: TH Bug: 204830222 CTS-Coverage-Bug: 213393821 Exempt-From-Owner-Approval: 1. Owner approved the change with explicitly granted submission after adderessing the straight-forward comment. 2. Owner is OOO for 3 months. Change-Id: I08c0162a7101cc6184f3eca3d4a59211183fb843 --- service-t/src/com/android/server/net/NetworkStatsService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ef84ce02e2..5584293b7d 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -113,7 +113,6 @@ import android.net.Uri; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; -import android.os.BestClock; import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; @@ -149,6 +148,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FileRotator; +import com.android.net.module.util.BestClock; import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; From 5bef63756c51e6232ceee81f2b40a200ef16aa69 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 3 Jan 2022 14:05:45 +0000 Subject: [PATCH 1022/1150] [MS34.1] Replace TelephonyManager#getSubscriberId(subId) with public API Test: atest com.android.server.net.NetworkStatsSubscriptionsMonitorTest Bug: 204830222 Change-Id: I57aa4470aea1715217fa7d74f2c9067b096d1bae --- .../android/server/net/NetworkStatsSubscriptionsMonitor.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 93d0ae7da0..9bb7bb8078 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -101,7 +101,8 @@ public class NetworkStatsSubscriptionsMonitor extends // with empty IMSI. So filter the subs w/o a valid IMSI to prevent such registration. final List> filteredNewSubs = new ArrayList<>(); for (final int subId : newSubs) { - final String subscriberId = mTeleManager.getSubscriberId(subId); + final String subscriberId = + mTeleManager.createForSubscriptionId(subId).getSubscriberId(); if (!TextUtils.isEmpty(subscriberId)) { filteredNewSubs.add(new Pair(subId, subscriberId)); } From e7c835b3ad96eab1a03bec2da4a38664fc8e1e61 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 4 Jan 2022 10:23:47 +0000 Subject: [PATCH 1023/1150] [MS09] Expose NetworkTemplate APIs which are needed by NetworkPolicy This change also remove getWifiNetworkKey which should not be exposed as system API. Test: atest NetworkTemplateTest Bug: 204830222 Change-Id: I924f62025a8672167f778ff790cd208c74eed878 --- framework-t/src/android/net/NetworkStats.java | 23 ++++--------------- .../src/android/net/NetworkTemplate.java | 23 ++++++++----------- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index 181a594cbc..b00fea4de2 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -83,10 +83,7 @@ public final class NetworkStats implements Parcelable { */ // TODO: Rename TAG_ALL to TAG_ANY. public static final int TAG_ALL = -1; - /** - * {@link #set} value for all sets combined, not including debug sets. - * @hide - */ + /** {@link #set} value for all sets combined, not including debug sets. */ public static final int SET_ALL = -1; /** {@link #set} value where background data is accounted. */ public static final int SET_DEFAULT = 0; @@ -114,9 +111,6 @@ public final class NetworkStats implements Parcelable { SET_ALL, SET_DEFAULT, SET_FOREGROUND, - SET_DEBUG_START, - SET_DBG_VPN_IN, - SET_DBG_VPN_OUT }) public @interface State { } @@ -131,10 +125,7 @@ public final class NetworkStats implements Parcelable { // TODO: Rename TAG_NONE to TAG_ALL. public static final int TAG_NONE = 0; - /** - * {@link #metered} value to account for all metered states. - * @hide - */ + /** {@link #metered} value to account for all metered states. */ public static final int METERED_ALL = -1; /** {@link #metered} value where native, unmetered data is accounted. */ public static final int METERED_NO = 0; @@ -152,10 +143,7 @@ public final class NetworkStats implements Parcelable { } - /** - * {@link #roaming} value to account for all roaming states. - * @hide - */ + /** {@link #roaming} value to account for all roaming states. */ public static final int ROAMING_ALL = -1; /** {@link #roaming} value where native, non-roaming data is accounted. */ public static final int ROAMING_NO = 0; @@ -172,10 +160,7 @@ public final class NetworkStats implements Parcelable { public @interface Roaming { } - /** - * {@link #onDefaultNetwork} value to account for all default network states. - * @hide - */ + /** {@link #onDefaultNetwork} value to account for all default network states. */ public static final int DEFAULT_NETWORK_ALL = -1; /** {@link #onDefaultNetwork} value to account for usage while not the default network. */ public static final int DEFAULT_NETWORK_NO = 0; diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 659ad06039..e9084b0196 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -16,6 +16,7 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; @@ -39,7 +40,9 @@ import static android.net.NetworkStats.ROAMING_YES; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; +import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; @@ -70,7 +73,7 @@ import java.util.TreeSet; * * @hide */ -// @SystemApi(client = MODULE_LIBRARIES) +@SystemApi(client = MODULE_LIBRARIES) public final class NetworkTemplate implements Parcelable { /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -572,6 +575,7 @@ public final class NetworkTemplate implements Parcelable { /** * Get subscriber Id of the template. + * @hide */ @Nullable @UnsupportedAppUsage @@ -588,26 +592,19 @@ public final class NetworkTemplate implements Parcelable { } /** - * Get Wifi Network Key of the template. See {@link WifiInfo#getCurrentNetworkKey()}. + * Get the set of Wifi Network Keys of the template. + * See {@link WifiInfo#getCurrentNetworkKey()}. */ - @Nullable - public String getWifiNetworkKey() { - return CollectionUtils.isEmpty(mMatchWifiNetworkKeys) ? null : mMatchWifiNetworkKeys[0]; - } - - /** - * Get set of Wifi Network Keys of the template. - */ - @Nullable + @NonNull public Set getWifiNetworkKeys() { return new ArraySet<>(Arrays.asList(mMatchWifiNetworkKeys)); } /** @hide */ - // TODO: Remove this and replace all callers with {@link #getWifiNetworkKey()}. + // TODO: Remove this and replace all callers with {@link #getWifiNetworkKeys()}. @Nullable public String getNetworkId() { - return getWifiNetworkKey(); + return getWifiNetworkKeys().isEmpty() ? null : getWifiNetworkKeys().iterator().next(); } /** From 1ea62cdab4e4c869bac4035640ff23ecf47e496a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 3 Jan 2022 07:39:55 +0000 Subject: [PATCH 1024/1150] [MS32.1] Remove TetheringManager#ACTION_TETHER_STATE_CHANGED usage Replace intent receiver with callback listener. Test: atest com.android.server.net.NetworkStatsServiceTest Bug: 204830222 Change-Id: I585b2bb471b59cbca3cce1c01ce527dff87f42da --- .../server/net/NetworkStatsService.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 5584293b7d..ced2e22f14 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -42,7 +42,6 @@ import static android.net.NetworkStats.UID_ALL; import static android.net.NetworkStatsHistory.FIELD_ALL; import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UNSUPPORTED; @@ -107,6 +106,7 @@ import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; +import android.net.TetheringManager; import android.net.TrafficStats; import android.net.UnderlyingNetworkInfo; import android.net.Uri; @@ -531,8 +531,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // watch for tethering changes - final IntentFilter tetherFilter = new IntentFilter(ACTION_TETHER_STATE_CHANGED); - mContext.registerReceiver(mTetherReceiver, tetherFilter, null, mHandler); + final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); + tetheringManager.registerTetheringEventCallback( + new HandlerExecutor(mHandler), mTetherListener); // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); @@ -588,7 +589,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private void shutdownLocked() { - mContext.unregisterReceiver(mTetherReceiver); + final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); + tetheringManager.unregisterTetheringEventCallback(mTetherListener); mContext.unregisterReceiver(mPollReceiver); mContext.unregisterReceiver(mRemovedReceiver); mContext.unregisterReceiver(mUserReceiver); @@ -1152,14 +1154,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Receiver that watches for {@link Tethering} to claim interface pairs. + * Listener that watches for {@link TetheringManager} to claim interface pairs. */ - private BroadcastReceiver mTetherReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - performPoll(FLAG_PERSIST_NETWORK); - } - }; + private final TetheringManager.TetheringEventCallback mTetherListener = + new TetheringManager.TetheringEventCallback() { + @Override + public void onUpstreamChanged(@Nullable Network network) { + performPoll(FLAG_PERSIST_NETWORK); + } + }; private BroadcastReceiver mPollReceiver = new BroadcastReceiver() { @Override From 76b8f884287231b3a8e6839d19b42f074de9fe78 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 23 Dec 2021 10:47:05 +0800 Subject: [PATCH 1025/1150] Remove ParcelFileDescriptor hidden API usage from IpSecService IpSec service is going to be a part of Connectivity mainline module and ParcelFileDescriptor(FileDescriptor) is a hidden API that cannot be used by mainline module. Therefore, use ParcelFileDescriptor.dup(FileDescriptor) to get a ParcelFileDescriptor instead. Bug: 204153604 Test: FrameworksNetTests Change-Id: I0ccabdfc5060f4b635e9a7009a67fbd5d32002fd --- .../src/com/android/server/IpSecService.java | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index d1e432e80f..179d9459fd 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -1236,37 +1236,53 @@ public class IpSecService extends IIpSecService.Stub { int callingUid = Binder.getCallingUid(); UserRecord userRecord = mUserResourceTracker.getUserRecord(callingUid); final int resourceId = mNextResourceId++; - FileDescriptor sockFd = null; + + ParcelFileDescriptor pFd = null; try { if (!userRecord.mSocketQuotaTracker.isAvailable()) { return new IpSecUdpEncapResponse(IpSecManager.Status.RESOURCE_UNAVAILABLE); } - sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); - mUidFdTagger.tag(sockFd, callingUid); + FileDescriptor sockFd = null; + try { + sockFd = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + pFd = ParcelFileDescriptor.dup(sockFd); + } finally { + IoUtils.closeQuietly(sockFd); + } + mUidFdTagger.tag(pFd.getFileDescriptor(), callingUid); // This code is common to both the unspecified and specified port cases Os.setsockoptInt( - sockFd, + pFd.getFileDescriptor(), OsConstants.IPPROTO_UDP, OsConstants.UDP_ENCAP, OsConstants.UDP_ENCAP_ESPINUDP); - mNetd.ipSecSetEncapSocketOwner(new ParcelFileDescriptor(sockFd), callingUid); + mNetd.ipSecSetEncapSocketOwner(pFd, callingUid); if (port != 0) { Log.v(TAG, "Binding to port " + port); - Os.bind(sockFd, INADDR_ANY, port); + Os.bind(pFd.getFileDescriptor(), INADDR_ANY, port); } else { - port = bindToRandomPort(sockFd); + port = bindToRandomPort(pFd.getFileDescriptor()); } userRecord.mEncapSocketRecords.put( resourceId, new RefcountedResource( - new EncapSocketRecord(resourceId, sockFd, port), binder)); - return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, sockFd); + new EncapSocketRecord(resourceId, pFd.getFileDescriptor(), port), + binder)); + return new IpSecUdpEncapResponse(IpSecManager.Status.OK, resourceId, port, + pFd.getFileDescriptor()); } catch (IOException | ErrnoException e) { - IoUtils.closeQuietly(sockFd); + try { + if (pFd != null) { + pFd.close(); + } + } catch (IOException ex) { + // Nothing can be done at this point + Log.e(TAG, "Failed to close pFd."); + } } // If we make it to here, then something has gone wrong and we couldn't open a socket. // The only reasonable condition that would cause that is resource unavailable. From 19332960f6b560ca90d76a1e452550119e2e0620 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 27 Dec 2021 13:56:00 +0000 Subject: [PATCH 1026/1150] [MS22] Move NetworkManagementSocketTagger into the module This is heavily used by TrafficStats, and no other modules are using it. Hence it should be moved to the module as well. Test: TH Bug: 204830222 Change-Id: I7ea1ccb916e796c786c29d53e4ecf3970a8af6dd --- framework-t/Sources.bp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 0bda923f23..90bb76a87d 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -25,15 +25,21 @@ filegroup { name: "framework-connectivity-netstats-internal-sources", srcs: [ "src/android/app/usage/*.java", - "src/android/net/DataUsage*.*", - "src/android/net/INetworkStats*.*", - "src/android/net/NetworkIdentity*.java", + "src/android/net/DataUsageRequest.*", + "src/android/net/INetworkStatsService.aidl", + "src/android/net/INetworkStatsSession.aidl", + "src/android/net/NetworkIdentity.java", + "src/android/net/NetworkIdentitySet.java", "src/android/net/NetworkStateSnapshot.*", - "src/android/net/NetworkStats*.*", + "src/android/net/NetworkStats.*", + "src/android/net/NetworkStatsAccess.*", + "src/android/net/NetworkStatsCollection.*", + "src/android/net/NetworkStatsHistory.*", "src/android/net/NetworkTemplate.*", "src/android/net/TrafficStats.java", "src/android/net/UnderlyingNetworkInfo.*", "src/android/net/netstats/**/*.*", + "src/com/android/server/NetworkManagementSocketTagger.java", ], path: "src", visibility: [ From 30eb3cc54a93c44edc7895c49e02a9571176a432 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 5 Jan 2022 07:35:49 +0000 Subject: [PATCH 1027/1150] [MS39.1] Remove the looper from NetworkStatsSubscriptionMonitor OnSubscriptionsChangedListenerHandler(Looper looper) is hidden, there is no way to pass a looper to it in the test. This change partially revert aosp/1340040 to fix hidden API dependency. And will use a different approach to address this problem in later stages. Test: atest NetworkStatsSubscriptionMonitorTest Bug: 204830222 Bug: 213280079 Change-Id: I429be3578d599de9a5a3f78b02387c20744b37d3 --- .../src/com/android/server/net/NetworkStatsService.java | 7 +++---- .../server/net/NetworkStatsSubscriptionsMonitor.java | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ced2e22f14..97281ed424 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -448,7 +448,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, - mHandler.getLooper(), new HandlerExecutor(mHandler), this); + new HandlerExecutor(mHandler), this); mContentResolver = mContext.getContentResolver(); mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); @@ -474,11 +474,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ @NonNull public NetworkStatsSubscriptionsMonitor makeSubscriptionsMonitor(@NonNull Context context, - @NonNull Looper looper, @NonNull Executor executor, - @NonNull NetworkStatsService service) { + @NonNull Executor executor, @NonNull NetworkStatsService service) { // TODO: Update RatType passively in NSS, instead of querying into the monitor // when notifyNetworkStatus. - return new NetworkStatsSubscriptionsMonitor(context, looper, executor, + return new NetworkStatsSubscriptionsMonitor(context, executor, (subscriberId, type) -> service.handleOnCollapsedRatTypeChanged()); } diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 9bb7bb8078..6df6de32da 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -21,7 +21,6 @@ import static android.net.NetworkTemplate.getCollapsedRatType; import android.annotation.NonNull; import android.content.Context; -import android.os.Looper; import android.telephony.Annotation; import android.telephony.NetworkRegistrationInfo; import android.telephony.PhoneStateListener; @@ -79,9 +78,9 @@ public class NetworkStatsSubscriptionsMonitor extends @NonNull private final Executor mExecutor; - NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Looper looper, + NetworkStatsSubscriptionsMonitor(@NonNull Context context, @NonNull Executor executor, @NonNull Delegate delegate) { - super(looper); + super(); mSubscriptionManager = (SubscriptionManager) context.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); mTeleManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); From 14a3baf2444378a9aa387cf389c6eb9885189399 Mon Sep 17 00:00:00 2001 From: lifr Date: Mon, 13 Dec 2021 16:15:51 +0800 Subject: [PATCH 1028/1150] [DU01]Remove INetworkManagementService from NetworkStatsService NetworkStatsService is using INetworkManagementService APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 209738761 Test: atest NetworkStatsServiceTest Change-Id: I5740f6d8a54e9a06c6dbb93203cb4c954383c3c8 --- .../server/net/NetworkStatsService.java | 109 ++++++++++-------- 1 file changed, 64 insertions(+), 45 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ced2e22f14..51e3f501b8 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -44,6 +44,7 @@ import static android.net.NetworkTemplate.buildTemplateMobileWildcard; import static android.net.NetworkTemplate.buildTemplateWifiWildcard; import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; +import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UNSUPPORTED; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; @@ -70,7 +71,7 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; -import static com.android.server.NetworkManagementService.LIMIT_GLOBAL_ALERT; +import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; @@ -89,7 +90,6 @@ import android.content.pm.PackageManager; import android.database.ContentObserver; import android.net.DataUsageRequest; import android.net.INetd; -import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; import android.net.Network; @@ -106,6 +106,7 @@ import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.TelephonyNetworkSpecifier; +import android.net.TetherStatsParcel; import android.net.TetheringManager; import android.net.TrafficStats; import android.net.UnderlyingNetworkInfo; @@ -120,12 +121,12 @@ import android.os.Handler; import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; -import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; import android.os.Messenger; import android.os.PowerManager; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; @@ -148,6 +149,7 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.FileRotator; +import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import com.android.net.module.util.BestClock; import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; @@ -208,7 +210,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG_NETSTATS_ERROR = "netstats_error"; private final Context mContext; - private final INetworkManagementService mNetworkManager; private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; private final Clock mClock; @@ -223,6 +224,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ContentObserver mContentObserver; private final ContentResolver mContentResolver; + protected INetd mNetd; + private final AlertObserver mAlertObserver = new AlertObserver(); + @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -405,15 +409,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public static NetworkStatsService create(Context context, - INetworkManagementService networkManager) { + /** Creates a new NetworkStatsService */ + public static NetworkStatsService create(Context context) { AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); final INetd netd = INetd.Stub.asInterface( (IBinder) context.getSystemService(Context.NETD_SERVICE)); - final NetworkStatsService service = new NetworkStatsService(context, networkManager, + final NetworkStatsService service = new NetworkStatsService(context, + INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), alarmManager, wakeLock, getDefaultClock(), new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), @@ -426,14 +431,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // This must not be called outside of tests, even within the same package, as this constructor // does not register the local service. Use the create() helper above. @VisibleForTesting - NetworkStatsService(Context context, INetworkManagementService networkManager, - AlarmManager alarmManager, PowerManager.WakeLock wakeLock, Clock clock, - NetworkStatsSettings settings, NetworkStatsFactory factory, - NetworkStatsObservers statsObservers, File systemDir, File baseDir, - @NonNull Dependencies deps) { + NetworkStatsService(Context context, INetd netd, AlarmManager alarmManager, + PowerManager.WakeLock wakeLock, Clock clock, NetworkStatsSettings settings, + NetworkStatsFactory factory, NetworkStatsObservers statsObservers, File systemDir, + File baseDir, @NonNull Dependencies deps) { mContext = Objects.requireNonNull(context, "missing Context"); - mNetworkManager = Objects.requireNonNull(networkManager, - "missing INetworkManagementService"); + mNetd = Objects.requireNonNull(netd, "missing Netd"); mAlarmManager = Objects.requireNonNull(alarmManager, "missing AlarmManager"); mClock = Objects.requireNonNull(clock, "missing Clock"); mSettings = Objects.requireNonNull(settings, "missing NetworkStatsSettings"); @@ -507,6 +510,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new NetworkStatsManagerInternalImpl()); } + /** + * Observer that watches for {@link INetdUnsolicitedEventListener} alerts. + */ + @VisibleForTesting + public class AlertObserver extends BaseNetdUnsolicitedEventListener { + @Override + public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { + PermissionUtils.enforceNetworkStackPermission(mContext); + + if (LIMIT_GLOBAL_ALERT.equals(alertName)) { + // kick off background poll to collect network stats unless there is already + // such a call pending; UID stats are handled during normal polling interval. + if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { + mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, + mSettings.getPollDelay()); + } + } + } + } + public void systemReady() { synchronized (mStatsLock) { mSystemReady = true; @@ -552,9 +575,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContext.registerReceiver(mShutdownReceiver, shutdownFilter); try { - mNetworkManager.registerObserver(mAlertObserver); - } catch (RemoteException e) { - // ignored; service lives in system_server + mNetd.registerUnsolicitedEventListener(mAlertObserver); + } catch (RemoteException | ServiceSpecificException e) { + Log.wtf(TAG, "Error registering event listener :", e); } // schedule periodic pall alarm based on {@link NetworkStatsSettings#getPollInterval()}. @@ -642,13 +665,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Register for a global alert that is delivered through {@link INetworkManagementEventObserver} + * Register for a global alert that is delivered through {@link AlertObserver} * or {@link NetworkStatsProviderCallback#onAlertReached()} once a threshold amount of data has * been transferred. */ private void registerGlobalAlert() { try { - mNetworkManager.setGlobalAlert(mGlobalAlertBytes); + mNetd.bandwidthSetGlobalAlert(mGlobalAlertBytes); } catch (IllegalStateException e) { Log.w(TAG, "problem registering for global alert: " + e); } catch (RemoteException e) { @@ -1226,26 +1249,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - /** - * Observer that watches for {@link INetworkManagementService} alerts. - */ - private final INetworkManagementEventObserver mAlertObserver = new BaseNetworkObserver() { - @Override - public void limitReached(String limitName, String iface) { - // only someone like NMS should be calling us - PermissionUtils.enforceNetworkStackPermission(mContext); - - if (LIMIT_GLOBAL_ALERT.equals(limitName)) { - // kick off background poll to collect network stats unless there is already - // such a call pending; UID stats are handled during normal polling interval. - if (!mHandler.hasMessages(MSG_PERFORM_POLL_REGISTER_ALERT)) { - mHandler.sendEmptyMessageDelayed(MSG_PERFORM_POLL_REGISTER_ALERT, - mSettings.getPollDelay()); - } - } - } - }; - /** * Handle collapsed RAT type changed event. */ @@ -1957,13 +1960,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ // TODO: Remove this by implementing {@link NetworkStatsProvider} for non-offloaded // tethering stats. - private NetworkStats getNetworkStatsTethering(int how) throws RemoteException { + private @NonNull NetworkStats getNetworkStatsTethering(int how) throws RemoteException { + // We only need to return per-UID stats. Per-device stats are already counted by + // interface counters. + if (how != STATS_PER_UID) { + return new NetworkStats(SystemClock.elapsedRealtime(), 0); + } + + final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 1); try { - return mNetworkManager.getNetworkStatsTethering(how); + final TetherStatsParcel[] tetherStatsParcels = mNetd.tetherGetStats(); + for (TetherStatsParcel tetherStats : tetherStatsParcels) { + try { + stats.combineValues(new NetworkStats.Entry(tetherStats.iface, UID_TETHERING, + SET_DEFAULT, TAG_NONE, tetherStats.rxBytes, tetherStats.rxPackets, + tetherStats.txBytes, tetherStats.txPackets, 0L)); + } catch (ArrayIndexOutOfBoundsException e) { + throw new IllegalStateException("invalid tethering stats " + e); + } + } } catch (IllegalStateException e) { Log.wtf(TAG, "problem reading network stats", e); - return new NetworkStats(0L, 10); } + return stats; } // TODO: It is copied from ConnectivityService, consider refactor these check permission @@ -2045,7 +2064,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull final INetworkStatsProvider mProvider; @NonNull private final Semaphore mSemaphore; - @NonNull final INetworkManagementEventObserver mAlertObserver; + @NonNull final AlertObserver mAlertObserver; @NonNull final CopyOnWriteArrayList mStatsProviderCbList; @NonNull private final Object mProviderStatsLock = new Object(); @@ -2059,7 +2078,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStatsProviderCallbackImpl( @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, - @NonNull INetworkManagementEventObserver alertObserver, + @NonNull AlertObserver alertObserver, @NonNull CopyOnWriteArrayList cbList) throws RemoteException { mTag = tag; @@ -2107,7 +2126,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // This binder object can only have been obtained by a process that holds // NETWORK_STATS_PROVIDER. Thus, no additional permission check is required. BinderUtils.withCleanCallingIdentity(() -> - mAlertObserver.limitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); + mAlertObserver.onQuotaLimitReached(LIMIT_GLOBAL_ALERT, null /* unused */)); } @Override From e75b506df26b66362296697ca88a7fd9c4a1db19 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Sat, 8 Jan 2022 17:16:24 -0800 Subject: [PATCH 1029/1150] Making NetworkCapabilities @NonNull Updating InternalNetworkUpdateRequest to require non-null network capabilities. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I660d039166451c22ffe5b5e603c649a43b71ebf1 --- .../android/net/InternalNetworkUpdateRequest.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/core/java/android/net/InternalNetworkUpdateRequest.java index 6f093835fb..f42c4b7c42 100644 --- a/core/java/android/net/InternalNetworkUpdateRequest.java +++ b/core/java/android/net/InternalNetworkUpdateRequest.java @@ -17,7 +17,6 @@ package android.net; import android.annotation.NonNull; -import android.annotation.Nullable; import android.os.Parcel; import android.os.Parcelable; @@ -27,7 +26,7 @@ import java.util.Objects; public final class InternalNetworkUpdateRequest implements Parcelable { @NonNull private final StaticIpConfiguration mIpConfig; - @Nullable + @NonNull private final NetworkCapabilities mNetworkCapabilities; @NonNull @@ -37,20 +36,16 @@ public final class InternalNetworkUpdateRequest implements Parcelable { @NonNull public NetworkCapabilities getNetworkCapabilities() { - return mNetworkCapabilities == null - ? null : new NetworkCapabilities(mNetworkCapabilities); + return new NetworkCapabilities(mNetworkCapabilities); } /** @hide */ public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, - @Nullable final NetworkCapabilities networkCapabilities) { + @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); + Objects.requireNonNull(networkCapabilities); mIpConfig = new StaticIpConfiguration(ipConfig); - if (null == networkCapabilities) { - mNetworkCapabilities = null; - } else { - mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); - } + mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } private InternalNetworkUpdateRequest(@NonNull final Parcel source) { From c44e042f070e90f7c527a1e7d0759d0be7297989 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 6 Jan 2022 01:12:47 +0000 Subject: [PATCH 1030/1150] [MS42.1] Replace PhoneStateListener with DisplayInfoListener Several methods and constants are hidden in PhoneStateListener and ServiceState to track Radio Access Technology(RAT) types. Replace them with public API instead. Test: atest NetworkStatsSubscriptionsMonitorTest Fix: 213021103 Change-Id: I588398da7f2b031910a8350a7d84405ff101232d --- .../net/NetworkStatsSubscriptionsMonitor.java | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 6df6de32da..4875f1cf5a 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -18,14 +18,16 @@ package com.android.server.net; import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; +import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; +import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; +import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; import android.content.Context; import android.telephony.Annotation; -import android.telephony.NetworkRegistrationInfo; -import android.telephony.PhoneStateListener; -import android.telephony.ServiceState; import android.telephony.SubscriptionManager; +import android.telephony.TelephonyCallback; +import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Log; @@ -63,7 +65,7 @@ public class NetworkStatsSubscriptionsMonitor extends private final Delegate mDelegate; /** - * Receivers that watches for {@link ServiceState} changes for each subscription, to + * Receivers that watches for {@link TelephonyDisplayInfo} changes for each subscription, to * monitor the transitioning between Radio Access Technology(RAT) types for each sub. */ @NonNull @@ -115,13 +117,12 @@ public class NetworkStatsSubscriptionsMonitor extends continue; } - final RatTypeListener listener = - new RatTypeListener(mExecutor, this, sub.first, sub.second); + final RatTypeListener listener = new RatTypeListener(this, sub.first, sub.second); mRatListeners.add(listener); // Register listener to the telephony manager that associated with specific sub. mTeleManager.createForSubscriptionId(sub.first) - .listen(listener, PhoneStateListener.LISTEN_SERVICE_STATE); + .registerTelephonyCallback(mExecutor, listener); Log.d(NetworkStatsService.TAG, "RAT type listener registered for sub " + sub.first); } @@ -175,7 +176,7 @@ public class NetworkStatsSubscriptionsMonitor extends private void handleRemoveRatTypeListener(@NonNull RatTypeListener listener) { mTeleManager.createForSubscriptionId(listener.mSubId) - .listen(listener, PhoneStateListener.LISTEN_NONE); + .unregisterTelephonyCallback(listener); Log.d(NetworkStatsService.TAG, "RAT type listener unregistered for sub " + listener.mSubId); mRatListeners.remove(listener); @@ -185,7 +186,8 @@ public class NetworkStatsSubscriptionsMonitor extends listener.mSubscriberId, TelephonyManager.NETWORK_TYPE_UNKNOWN); } - static class RatTypeListener extends PhoneStateListener { + static class RatTypeListener extends TelephonyCallback + implements TelephonyCallback.DisplayInfoListener { // Unique id for the subscription. See {@link SubscriptionInfo#getSubscriptionId}. @NonNull private final int mSubId; @@ -199,29 +201,27 @@ public class NetworkStatsSubscriptionsMonitor extends @NonNull private final NetworkStatsSubscriptionsMonitor mMonitor; - RatTypeListener(@NonNull Executor executor, - @NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, + RatTypeListener(@NonNull NetworkStatsSubscriptionsMonitor monitor, int subId, @NonNull String subscriberId) { - super(executor); mSubId = subId; mSubscriberId = subscriberId; mMonitor = monitor; } @Override - public void onServiceStateChanged(@NonNull ServiceState ss) { + public void onDisplayInfoChanged(TelephonyDisplayInfo displayInfo) { // In 5G SA (Stand Alone) mode, the primary cell itself will be 5G hence telephony // would report RAT = 5G_NR. // However, in 5G NSA (Non Stand Alone) mode, the primary cell is still LTE and // network allocates a secondary 5G cell so telephony reports RAT = LTE along with // NR state as connected. In such case, attributes the data usage to NR. // See b/160727498. - final boolean is5GNsa = (ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE - || ss.getDataNetworkType() == TelephonyManager.NETWORK_TYPE_LTE_CA) - && ss.getNrState() == NetworkRegistrationInfo.NR_STATE_CONNECTED; + final boolean is5GNsa = displayInfo.getNetworkType() == NETWORK_TYPE_LTE + && (displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_NSA + || displayInfo.getOverrideNetworkType() == OVERRIDE_NETWORK_TYPE_NR_ADVANCED); final int networkType = - (is5GNsa ? NETWORK_TYPE_5G_NSA : ss.getDataNetworkType()); + (is5GNsa ? NETWORK_TYPE_5G_NSA : displayInfo.getNetworkType()); final int collapsedRatType = getCollapsedRatType(networkType); if (collapsedRatType == mLastCollapsedRatType) return; From 711b873ba782496dff238c1547692689bad25713 Mon Sep 17 00:00:00 2001 From: lifr Date: Thu, 23 Dec 2021 15:13:29 +0800 Subject: [PATCH 1031/1150] [DU03]Remove INetworkStatsService from BatteryStatsImpl BatteryStatsImpl is using INetworkStatsService APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 210066922 Test: atest BatteryStatsImplTest WifiPowerCalculatorTest MobileRadioPowerCalculatorTest CTS-Coverage-Bug: 213437796 Change-Id: I584897ff8ba303c717a9df3756c9f6778c1cfb10 --- .../app/usage/NetworkStatsManager.java | 26 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 1 + 2 files changed, 27 insertions(+) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index a316b8a617..583f7ba8cd 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -54,6 +54,7 @@ import com.android.net.module.util.NetworkIdentityUtils; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Provides access to network usage history and statistics. Usage data is collected in @@ -535,6 +536,31 @@ public class NetworkStatsManager { return result; } + /** + * Query realtime network usage statistics details with interfaces constrains. + * Return snapshot of current UID statistics, including any {@link TrafficStats#UID_TETHERING}, + * video calling data usage and count of network operations that set by + * {@link TrafficStats#incrementOperationCount}. The returned data doesn't include any + * statistics that is reported by {@link NetworkStatsProvider}. + * + * @param requiredIfaces A list of interfaces the stats should be restricted to, or + * {@link NetworkStats#INTERFACES_ALL}. + * + * @hide + */ + //@SystemApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @NonNull public android.net.NetworkStats getDetailedUidStats( + @NonNull Set requiredIfaces) { + Objects.requireNonNull(requiredIfaces, "requiredIfaces cannot be null"); + try { + return mService.getDetailedUidStats(requiredIfaces.toArray(new String[0])); + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when get detailed uid stats"); + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ public void registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index a3de9e4ba7..7fd9569c86 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -919,6 +919,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); try { final String[] ifacesToQuery = mStatsFactory.augmentWithStackedInterfaces(requiredIfaces); From c9dedfbe95cd0b34462c67995eff57283b563c7c Mon Sep 17 00:00:00 2001 From: lifr Date: Thu, 23 Dec 2021 15:13:29 +0800 Subject: [PATCH 1032/1150] [DU03]Remove INetworkStatsService from BatteryStatsImpl BatteryStatsImpl is using INetworkStatsService APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 210066922 Test: atest BatteryStatsImplTest WifiPowerCalculatorTest MobileRadioPowerCalculatorTest CTS-Coverage-Bug: 213437796 (cherry-picked from ag/16548638) Change-Id: I584897ff8ba303c717a9df3756c9f6778c1cfb10 Merged-In: I584897ff8ba303c717a9df3756c9f6778c1cfb10 --- .../app/usage/NetworkStatsManager.java | 26 +++++++++++++++++++ .../server/net/NetworkStatsService.java | 1 + 2 files changed, 27 insertions(+) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index a316b8a617..583f7ba8cd 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -54,6 +54,7 @@ import com.android.net.module.util.NetworkIdentityUtils; import java.util.List; import java.util.Objects; +import java.util.Set; /** * Provides access to network usage history and statistics. Usage data is collected in @@ -535,6 +536,31 @@ public class NetworkStatsManager { return result; } + /** + * Query realtime network usage statistics details with interfaces constrains. + * Return snapshot of current UID statistics, including any {@link TrafficStats#UID_TETHERING}, + * video calling data usage and count of network operations that set by + * {@link TrafficStats#incrementOperationCount}. The returned data doesn't include any + * statistics that is reported by {@link NetworkStatsProvider}. + * + * @param requiredIfaces A list of interfaces the stats should be restricted to, or + * {@link NetworkStats#INTERFACES_ALL}. + * + * @hide + */ + //@SystemApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @NonNull public android.net.NetworkStats getDetailedUidStats( + @NonNull Set requiredIfaces) { + Objects.requireNonNull(requiredIfaces, "requiredIfaces cannot be null"); + try { + return mService.getDetailedUidStats(requiredIfaces.toArray(new String[0])); + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when get detailed uid stats"); + throw e.rethrowFromSystemServer(); + } + } + /** @hide */ public void registerUsageCallback(NetworkTemplate template, int networkType, long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 97281ed424..4db90c1b1a 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -922,6 +922,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); try { final String[] ifacesToQuery = mStatsFactory.augmentWithStackedInterfaces(requiredIfaces); From 77422187544271b04ce33d80718bcb4c3e73e565 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 12 Jan 2022 23:00:20 +0800 Subject: [PATCH 1033/1150] Check iface by TextUtils.equals In current equals method, if iface is null then it will cause null object reference when checking iface. Thus, use TextUtils.equals to check iface so that it can compare null iface. Bug: 210073043 Test: FrameworksNetTests, NetworkStaticLibTests Change-Id: I2bd8127cb030ea54438382ee89961590fffbc31a --- framework-t/src/android/net/NetworkStats.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index b00fea4de2..352849c1e8 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -28,6 +28,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.SystemClock; +import android.text.TextUtils; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; @@ -410,7 +411,7 @@ public final class NetworkStats implements Parcelable { && roaming == e.roaming && defaultNetwork == e.defaultNetwork && rxBytes == e.rxBytes && rxPackets == e.rxPackets && txBytes == e.txBytes && txPackets == e.txPackets - && operations == e.operations && iface.equals(e.iface); + && operations == e.operations && TextUtils.equals(iface, e.iface); } return false; } From 7fe4f60b74b643507a8ec495bfde43a746994aa6 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Wed, 12 Jan 2022 17:44:44 +0000 Subject: [PATCH 1034/1150] Revert "Migrate unsafe parcel APIs in framework-minus-apex" This reverts commit e82600c40cbf92c5a61f893ceb6b524628e17b1f. Reason for revert: b/214053959 Change-Id: Ic271bab1d3eaf677a5989dda9deb944ee2ad6850 --- framework-t/src/android/net/DataUsageRequest.java | 2 +- framework-t/src/android/net/IpSecConfig.java | 8 ++++---- framework-t/src/android/net/IpSecUdpEncapResponse.java | 2 +- framework-t/src/android/net/NetworkStateSnapshot.java | 6 +++--- framework-t/src/android/net/UnderlyingNetworkInfo.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/net/DataUsageRequest.java b/framework-t/src/android/net/DataUsageRequest.java index f0ff46522d..b06d515b3a 100644 --- a/framework-t/src/android/net/DataUsageRequest.java +++ b/framework-t/src/android/net/DataUsageRequest.java @@ -75,7 +75,7 @@ public final class DataUsageRequest implements Parcelable { @Override public DataUsageRequest createFromParcel(Parcel in) { int requestId = in.readInt(); - NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class); + NetworkTemplate template = in.readParcelable(null); long thresholdInBytes = in.readLong(); DataUsageRequest result = new DataUsageRequest(requestId, template, thresholdInBytes); diff --git a/framework-t/src/android/net/IpSecConfig.java b/framework-t/src/android/net/IpSecConfig.java index 03bb187f11..575c5ed968 100644 --- a/framework-t/src/android/net/IpSecConfig.java +++ b/framework-t/src/android/net/IpSecConfig.java @@ -267,14 +267,14 @@ public final class IpSecConfig implements Parcelable { mMode = in.readInt(); mSourceAddress = in.readString(); mDestinationAddress = in.readString(); - mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class); + mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); mSpiResourceId = in.readInt(); mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); diff --git a/framework-t/src/android/net/IpSecUdpEncapResponse.java b/framework-t/src/android/net/IpSecUdpEncapResponse.java index 4910b62646..4e7ba9b515 100644 --- a/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ b/framework-t/src/android/net/IpSecUdpEncapResponse.java @@ -80,7 +80,7 @@ public final class IpSecUdpEncapResponse implements Parcelable { status = in.readInt(); resourceId = in.readInt(); port = in.readInt(); - fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class); + fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); } public static final @android.annotation.NonNull Parcelable.Creator CREATOR = diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java index d577aa8fba..3915634392 100644 --- a/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/framework-t/src/android/net/NetworkStateSnapshot.java @@ -73,9 +73,9 @@ public final class NetworkStateSnapshot implements Parcelable { /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - mNetwork = in.readParcelable(null, android.net.Network.class); - mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class); - mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class); + mNetwork = in.readParcelable(null); + mNetworkCapabilities = in.readParcelable(null); + mLinkProperties = in.readParcelable(null); mSubscriberId = in.readString(); mLegacyType = in.readInt(); } diff --git a/framework-t/src/android/net/UnderlyingNetworkInfo.java b/framework-t/src/android/net/UnderlyingNetworkInfo.java index 7ab53b1da8..33f9375c03 100644 --- a/framework-t/src/android/net/UnderlyingNetworkInfo.java +++ b/framework-t/src/android/net/UnderlyingNetworkInfo.java @@ -60,7 +60,7 @@ public final class UnderlyingNetworkInfo implements Parcelable { mOwnerUid = in.readInt(); mIface = in.readString(); List underlyingIfaces = new ArrayList<>(); - in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class); + in.readList(underlyingIfaces, null /*classLoader*/); mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); } From 7577deee2135bcafe317e1fc8f319e0eaef5be0a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 7 Jan 2022 11:28:54 +0000 Subject: [PATCH 1035/1150] [MS44.1] Add API to query tagged UID summary Query tagged UID summary is currently needed by StatsPullAtomService to collect tagged traffic statistics. Add an Api via NetworkStatsManager to support this functionality. Test: atest NetworkStatsManagerTest Bug: 204830222 Change-Id: Iaa54482a8109b56e66e829c5bec5a8a8f466641a --- .../src/android/app/usage/NetworkStats.java | 9 +++++ .../app/usage/NetworkStatsManager.java | 35 ++++++++++++++++++- .../src/android/net/INetworkStatsSession.aidl | 4 +++ .../server/net/NetworkStatsService.java | 14 ++++++-- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java index f684a4d9d8..d33666d744 100644 --- a/framework-t/src/android/app/usage/NetworkStats.java +++ b/framework-t/src/android/app/usage/NetworkStats.java @@ -544,6 +544,15 @@ public final class NetworkStats implements AutoCloseable { mEnumerationIndex = 0; } + /** + * Collects tagged summary results and sets summary enumeration mode. + * @throws RemoteException + */ + void startTaggedSummaryEnumeration() throws RemoteException { + mSummary = mSession.getTaggedSummaryForAllUid(mTemplate, mStartTimeStamp, mEndTimeStamp); + mEnumerationIndex = 0; + } + /** * Collects history results for uid and resets history enumeration index. */ diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index a316b8a617..8043a374bd 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -368,7 +368,7 @@ public class NetworkStatsManager { * @return Statistics which is described above. * @hide */ - @Nullable + @NonNull // @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, @@ -384,6 +384,39 @@ public class NetworkStatsManager { return null; // To make the compiler happy. } + /** + * Query tagged network usage statistics summaries. + * + * The results will only include tagged traffic made by UIDs belonging to the calling user + * profile. The results are aggregated over time, so that all buckets will have the same + * start and end timestamps as the passed arguments. Not aggregated over state, uid, + * default network, metered, or roaming. + * This may take a long time, and apps should avoid calling this on their main thread. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param startTime Start of period, in milliseconds since the Unix epoch, see + * {@link System#currentTimeMillis}. + * @param endTime End of period, in milliseconds since the Unix epoch, see + * {@link System#currentTimeMillis}. + * @return Statistics which is described above. + * @hide + */ + @NonNull + // @SystemApi(client = MODULE_LIBRARIES) + @WorkerThread + public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime, + long endTime) throws SecurityException { + try { + NetworkStats result = + new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); + result.startTaggedSummaryEnumeration(); + return result; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + return null; // To make the compiler happy. + } + /** * Query network usage statistics details for a given uid. * This may take a long time, and apps should avoid calling this on their main thread. diff --git a/framework-t/src/android/net/INetworkStatsSession.aidl b/framework-t/src/android/net/INetworkStatsSession.aidl index dfedf6633d..babe0bfb97 100644 --- a/framework-t/src/android/net/INetworkStatsSession.aidl +++ b/framework-t/src/android/net/INetworkStatsSession.aidl @@ -46,6 +46,10 @@ interface INetworkStatsSession { */ @UnsupportedAppUsage NetworkStats getSummaryForAllUid(in NetworkTemplate template, long start, long end, boolean includeTags); + + /** Return network layer usage summary per UID for tagged traffic that matches template. */ + NetworkStats getTaggedSummaryForAllUid(in NetworkTemplate template, long start, long end); + /** Return historical network layer stats for specific UID traffic that matches template. */ @UnsupportedAppUsage NetworkStatsHistory getHistoryForUid(in NetworkTemplate template, int uid, int set, int tag, int fields); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 97281ed424..2b73eb6100 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -766,8 +766,18 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } return stats; } catch (NullPointerException e) { - // TODO: Track down and fix the cause of this crash and remove this catch block. - Log.wtf(TAG, "NullPointerException in getSummaryForAllUid", e); + throw e; + } + } + + @Override + public NetworkStats getTaggedSummaryForAllUid( + NetworkTemplate template, long start, long end) { + try { + final NetworkStats tagStats = getUidTagComplete() + .getSummary(template, start, end, mAccessLevel, mCallingUid); + return tagStats; + } catch (NullPointerException e) { throw e; } } From 595dc3b96e6de2b467fd7565bb35e066c3bfaefb Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 16 Dec 2021 00:11:15 +0800 Subject: [PATCH 1036/1150] Add PolicyDirection InfDef annotation to IpSecManager IpSec is going to be moved into Connectivity module and it needs to use PolicyDirection annotation. Add PolicyDirection IntDef annotation so that it can be used in the module. Bug: 204153604 Test: FrameworksNetTests Change-Id: Ib411d8c436d67574bfaf7f3aba43e5f31e7487e2 --- framework-t/src/android/net/IpSecManager.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index 0d15dffae9..49aa99b097 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -17,6 +17,7 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; @@ -25,7 +26,6 @@ import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; import android.content.pm.PackageManager; -import android.net.annotations.PolicyDirection; import android.os.Binder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -41,6 +41,8 @@ import dalvik.system.CloseGuard; import java.io.FileDescriptor; import java.io.IOException; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.Socket; @@ -88,6 +90,11 @@ public final class IpSecManager { @SystemApi(client = MODULE_LIBRARIES) public static final int DIRECTION_FWD = 2; + /** @hide */ + @IntDef(value = {DIRECTION_IN, DIRECTION_OUT}) + @Retention(RetentionPolicy.SOURCE) + public @interface PolicyDirection {} + /** * The Security Parameter Index (SPI) 0 indicates an unknown or invalid index. * From 5f631cf00b1770695de16b42f38c265296c51ed6 Mon Sep 17 00:00:00 2001 From: lifr Date: Mon, 27 Dec 2021 13:24:35 +0800 Subject: [PATCH 1037/1150] [DU04]Remove NetworkPolicyManagerInternal from NetworkStatsService NetworkStatsService is using NetworkPolicyManagerInternal APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 211843446 Test: atest NetworkStatsServiceTest NetworkPolicyManagerTest NetworkPolicyManagerServiceTest Change-Id: I0f3f02d1dc014967fab27ffcf37dd1918dbef5e0 --- .../android/server/net/NetworkStatsService.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 74f3156305..37f7118efe 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -96,6 +96,7 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkIdentity; import android.net.NetworkIdentitySet; +import android.net.NetworkPolicyManager; import android.net.NetworkSpecifier; import android.net.NetworkStack; import android.net.NetworkStateSnapshot; @@ -850,7 +851,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (LOGD) Log.d(TAG, "Resolving plan for " + template); final long token = Binder.clearCallingIdentity(); try { - plan = LocalServices.getService(NetworkPolicyManagerInternal.class) + plan = mContext.getSystemService(NetworkPolicyManager.class) .getSubscriptionPlan(template); } finally { Binder.restoreCallingIdentity(token); @@ -2021,10 +2022,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); Objects.requireNonNull(provider, "provider is null"); Objects.requireNonNull(tag, "tag is null"); + final NetworkPolicyManager netPolicyManager = mContext + .getSystemService(NetworkPolicyManager.class); try { NetworkStatsProviderCallbackImpl callback = new NetworkStatsProviderCallbackImpl( tag, provider, mStatsProviderSem, mAlertObserver, - mStatsProviderCbList); + mStatsProviderCbList, netPolicyManager); mStatsProviderCbList.add(callback); Log.d(TAG, "registerNetworkStatsProvider from " + callback.mTag + " uid/pid=" + getCallingUid() + "/" + getCallingPid()); @@ -2066,6 +2069,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final Semaphore mSemaphore; @NonNull final AlertObserver mAlertObserver; @NonNull final CopyOnWriteArrayList mStatsProviderCbList; + @NonNull final NetworkPolicyManager mNetworkPolicyManager; @NonNull private final Object mProviderStatsLock = new Object(); @@ -2079,7 +2083,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull String tag, @NonNull INetworkStatsProvider provider, @NonNull Semaphore semaphore, @NonNull AlertObserver alertObserver, - @NonNull CopyOnWriteArrayList cbList) + @NonNull CopyOnWriteArrayList cbList, + @NonNull NetworkPolicyManager networkPolicyManager) throws RemoteException { mTag = tag; mProvider = provider; @@ -2087,6 +2092,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSemaphore = semaphore; mAlertObserver = alertObserver; mStatsProviderCbList = cbList; + mNetworkPolicyManager = networkPolicyManager; } @NonNull @@ -2133,8 +2139,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void notifyWarningOrLimitReached() { Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); BinderUtils.withCleanCallingIdentity(() -> - LocalServices.getService(NetworkPolicyManagerInternal.class) - .onStatsProviderWarningOrLimitReached(mTag)); + mNetworkPolicyManager.onStatsProviderWarningOrLimitReached()); } @Override From 86adedf565d5eea95ca1f94db238a974cdc8a380 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 7 Jan 2022 06:55:30 +0000 Subject: [PATCH 1038/1150] [MS43] Remove EventLogTags depdendency Inline functions and copy constants to the service. Test: TH Bug: 204830222 Change-Id: Idf5c8ff7c7fec39530269b3c6b24475407198fbc --- .../com/android/server/net/NetworkStatsService.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 3273e88213..b99675e239 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -155,7 +155,6 @@ import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; -import com.android.server.EventLogTags; import com.android.server.LocalServices; import java.io.File; @@ -209,6 +208,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String TAG_NETSTATS_ERROR = "netstats_error"; + /** + * EventLog tags used when logging into the event log. Note the values must be sync with + * frameworks/base/services/core/java/com/android/server/EventLogTags.logtags to get correct + * name translation. + */ + private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100; + private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101; + private final Context mContext; private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; @@ -1624,7 +1631,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - EventLogTags.writeNetstatsMobileSample( + EventLog.writeEvent(LOG_TAG_NETSTATS_MOBILE_SAMPLE, devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, @@ -1636,7 +1643,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { xtTotal = mXtRecorder.getTotalSinceBootLocked(template); uidTotal = mUidRecorder.getTotalSinceBootLocked(template); - EventLogTags.writeNetstatsWifiSample( + EventLog.writeEvent(LOG_TAG_NETSTATS_WIFI_SAMPLE, devTotal.rxBytes, devTotal.rxPackets, devTotal.txBytes, devTotal.txPackets, xtTotal.rxBytes, xtTotal.rxPackets, xtTotal.txBytes, xtTotal.txPackets, uidTotal.rxBytes, uidTotal.rxPackets, uidTotal.txBytes, uidTotal.txPackets, From 4c0b80f6f190228ddb783bde94cc9564f8de7ba1 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 13 Jan 2022 16:17:01 +0000 Subject: [PATCH 1039/1150] Revert "Pivot network statistics to use DataInput/Output." This reverts commit 1b4f0a409db397bcf877f36edcf15ed16e801d96. Reason for revert: FastDataInput/Output is hidden and cannot be used in mainline module. Test: TH Bug: 204830222 Change-Id: I8cfa435bb6233818adb9cc99dadeeb06a03443d5 --- .../src/android/net/NetworkStatsCollection.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 7935d28f30..9f9d73f888 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -46,8 +46,6 @@ import android.util.Range; import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.FastDataInput; -import com.android.internal.util.FastDataOutput; import com.android.internal.util.FileRotator; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; @@ -58,6 +56,7 @@ import java.io.BufferedInputStream; import java.io.DataInput; import java.io.DataInputStream; import java.io.DataOutput; +import java.io.DataOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; @@ -83,9 +82,6 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** File header magic number: "ANET" */ private static final int FILE_MAGIC = 0x414E4554; - /** Default buffer size from BufferedInputStream */ - private static final int BUFFER_SIZE = 8192; - private static final int VERSION_NETWORK_INIT = 1; private static final int VERSION_UID_INIT = 1; @@ -439,8 +435,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W @Override public void read(InputStream in) throws IOException { - final FastDataInput dataIn = new FastDataInput(in, BUFFER_SIZE); - read(dataIn); + read((DataInput) new DataInputStream(in)); } private void read(DataInput in) throws IOException { @@ -479,9 +474,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W @Override public void write(OutputStream out) throws IOException { - final FastDataOutput dataOut = new FastDataOutput(out, BUFFER_SIZE); - write(dataOut); - dataOut.flush(); + write((DataOutput) new DataOutputStream(out)); + out.flush(); } private void write(DataOutput out) throws IOException { From 638f6667e943d90c181aceb44d5b73dd138681c0 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 24 Dec 2021 02:00:54 +0000 Subject: [PATCH 1040/1150] [MS35] Remove getNetwork[Total|Uid]Bytes dependencies from NPMS 1. getNetworkTotalBytes was used for querying overall statistics that regards of the NetworkPolicy to calculate the remaining data warning/limit quota that needs to be send to the lower layer. 2. getNetworkUidBytes was used for querying overall statistics of apps to find out the rapid traffic that caused by an abnormal app behavior. This change replaces getNetwork[Total|Uid]Bytes with APIs that are about to expose, and introduces a dependencies object for better unit test injection. Test: atest NetworkPolicyManagerServiceTest Bug: 204830222 Change-Id: I802d2316fb22886e951456df0941c09176c981f8 --- .../src/android/app/usage/NetworkStatsManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index cc7b2a5a30..f0af42d308 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -142,7 +142,15 @@ public class NetworkStatsManager { setAugmentWithSubscriptionPlan(true); } - /** @hide */ + /** + * Set poll on open flag to indicate the poll is needed before service gets statistics + * result. This is default enabled. However, for any non-privileged caller, the poll might + * be omitted in case of rate limiting. + * + * @param pollOnOpen true if poll is needed. + * @hide + */ + // @SystemApi(client = MODULE_LIBRARIES) public void setPollOnOpen(boolean pollOnOpen) { if (pollOnOpen) { mFlags |= FLAG_POLL_ON_OPEN; From 3715b37705e80920cd5e9e6135a4c2f69c0325bb Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 4 Jan 2022 03:55:28 +0000 Subject: [PATCH 1041/1150] [MS36] Remove unused getNetwork[Total|Uid]Bytes Since the usages are all removed, clean up the unused code accordingly. Test: TH Bug: 204830222 Change-Id: Ia6863a7098632580b411bd79550754e511ea2543 --- .../server/net/NetworkStatsService.java | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index b99675e239..dadc51883c 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1690,26 +1690,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal { - @Override - public long getNetworkTotalBytes(NetworkTemplate template, long start, long end) { - Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkTotalBytes"); - try { - return NetworkStatsService.this.getNetworkTotalBytes(template, start, end); - } finally { - Trace.traceEnd(TRACE_TAG_NETWORK); - } - } - - @Override - public NetworkStats getNetworkUidBytes(NetworkTemplate template, long start, long end) { - Trace.traceBegin(TRACE_TAG_NETWORK, "getNetworkUidBytes"); - try { - return NetworkStatsService.this.getNetworkUidBytes(template, start, end); - } finally { - Trace.traceEnd(TRACE_TAG_NETWORK); - } - } - @Override public void setUidForeground(int uid, boolean uidForeground) { NetworkStatsService.this.setUidForeground(uid, uidForeground); From 4161a040337f7b46eadd5be332c727ea9d343b20 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 4 Jan 2022 07:24:40 +0000 Subject: [PATCH 1042/1150] [MS37] Replace NetworkStatsManagerInternal usages in NPMS This is done by: 1. Add NetworkStatsManagerInternal APIs directly from NetworkStatsManager, these APIs are needed by NPMS. 2. Replace all usages with these APIs. 3. Delete NetworkStatsManagerInternal implementation. Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest Bug: 204830222 CTS-Coverage-Bug: 213124616 Change-Id: If51b6676915e3a0a8a9f95221d735306911442fc --- .../app/usage/NetworkStatsManager.java | 70 +++++++++++++++++++ .../src/android/net/INetworkStatsService.aidl | 12 ++++ .../server/net/NetworkStatsService.java | 52 +++++--------- 3 files changed, 100 insertions(+), 34 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index f0af42d308..f74edb1a01 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -871,4 +871,74 @@ public class NetworkStatsManager { return msg.getData().getParcelable(key); } } + + /** + * Mark given UID as being in foreground for stats purposes. + * + * @hide + */ + // @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void setUidForeground(int uid, boolean uidForeground) { + try { + mService.setUidForeground(uid, uidForeground); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Advise persistence threshold; may be overridden internally. + * + * @hide + */ + // @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void advisePersistThreshold(long thresholdBytes) { + try { + mService.advisePersistThreshold(thresholdBytes); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Force update of statistics. + * + * @hide + */ + // @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void forceUpdate() { + try { + mService.forceUpdate(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set the warning and limit to all registered custom network stats providers. + * Note that invocation of any interface will be sent to all providers. + * + * @hide + */ + // @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) + public void setStatsProviderWarningAndLimitAsync(@NonNull String iface, long warning, + long limit) { + try { + mService.setStatsProviderWarningAndLimitAsync(iface, warning, limit); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } } diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index 12937b5cb2..a4babb543d 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -94,4 +94,16 @@ interface INetworkStatsService { /** Registers a network stats provider */ INetworkStatsProviderCallback registerNetworkStatsProvider(String tag, in INetworkStatsProvider provider); + + /** Mark given UID as being in foreground for stats purposes. */ + void setUidForeground(int uid, boolean uidForeground); + + /** Advise persistence threshold; may be overridden internally. */ + void advisePersistThreshold(long thresholdBytes); + + /** + * Set the warning and limit to all registered custom network stats providers. + * Note that invocation of any interface will be sent to all providers. + */ + void setStatsProviderWarningAndLimitAsync(String iface, long warning, long limit); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index dadc51883c..4cc18af466 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -430,7 +430,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); - service.registerLocalService(); return service; } @@ -511,11 +510,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void registerLocalService() { - LocalServices.addService(NetworkStatsManagerInternal.class, - new NetworkStatsManagerInternalImpl()); - } - /** * Observer that watches for {@link INetdUnsolicitedEventListener} alerts. */ @@ -1006,7 +1000,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @VisibleForTesting - void setUidForeground(int uid, boolean uidForeground) { + public void setUidForeground(int uid, boolean uidForeground) { + PermissionUtils.enforceNetworkStackPermission(mContext); synchronized (mStatsLock) { final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; final int oldSet = mActiveUidCounterSet.get(uid, SET_DEFAULT); @@ -1042,7 +1037,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public void forceUpdate() { - mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); + PermissionUtils.enforceNetworkStackPermission(mContext); final long token = Binder.clearCallingIdentity(); try { @@ -1052,7 +1047,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - private void advisePersistThreshold(long thresholdBytes) { + /** Advise persistence threshold; may be overridden internally. */ + public void advisePersistThreshold(long thresholdBytes) { + PermissionUtils.enforceNetworkStackPermission(mContext); // clamp threshold into safe range mPersistThreshold = NetworkStatsUtils.constrain(thresholdBytes, 128 * KB_IN_BYTES, 2 * MB_IN_BYTES); @@ -1689,32 +1686,19 @@ public class NetworkStatsService extends INetworkStatsService.Stub { removeUidsLocked(CollectionUtils.toIntArray(uids)); } - private class NetworkStatsManagerInternalImpl extends NetworkStatsManagerInternal { - @Override - public void setUidForeground(int uid, boolean uidForeground) { - NetworkStatsService.this.setUidForeground(uid, uidForeground); - } - - @Override - public void advisePersistThreshold(long thresholdBytes) { - NetworkStatsService.this.advisePersistThreshold(thresholdBytes); - } - - @Override - public void forceUpdate() { - NetworkStatsService.this.forceUpdate(); - } - - @Override - public void setStatsProviderWarningAndLimitAsync( - @NonNull String iface, long warning, long limit) { - if (LOGV) { - Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" - + iface + "," + warning + "," + limit + ")"); - } - invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, - warning, limit)); + /** + * Set the warning and limit to all registered custom network stats providers. + * Note that invocation of any interface will be sent to all providers. + */ + public void setStatsProviderWarningAndLimitAsync( + @NonNull String iface, long warning, long limit) { + PermissionUtils.enforceNetworkStackPermission(mContext); + if (LOGV) { + Log.v(TAG, "setStatsProviderWarningAndLimitAsync(" + + iface + "," + warning + "," + limit + ")"); } + invokeForAllStatsProviderCallbacks((cb) -> cb.mProvider.onSetWarningAndLimit(iface, + warning, limit)); } @Override From 3b5180d80e056bc17b69ab2342835a97aefd6604 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 7 Jan 2022 23:43:09 +0800 Subject: [PATCH 1043/1150] Add getter for the fields of NetworkStats.Entry NetworkStats is going to be moved into mainline module and there're some external callers have dependencies on it. To replace those hidden APIs with formal APIs, NetworkStats needs to expose some getter methods to eliminate the dependencies on hidden API. Bug: 210073043 Bug: 204830222 CTS-Coverage-Bug: 214881138 Test: FrameworksNetTests Change-Id: I85bb6b27bd17bad16c9693d95b569d0ec5fbb785 --- framework-t/src/android/net/NetworkStats.java | 91 ++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index b00fea4de2..9d532e7929 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -383,6 +383,95 @@ public final class NetworkStats implements Parcelable { this.operations += another.operations; } + /** + * @return interface name of this entry. + * @hide + */ + @Nullable public String getIface() { + return iface; + } + + /** + * @return the uid of this entry. + */ + public int getUid() { + return uid; + } + + /** + * @return the set state of this entry. Should be one of the following + * values: {@link #SET_DEFAULT}, {@link #SET_FOREGROUND}. + */ + @State public int getSet() { + return set; + } + + /** + * @return the tag value of this entry. + */ + public int getTag() { + return tag; + } + + /** + * @return the metered state. Should be one of the following + * values: {link #METERED_YES}, {link #METERED_NO}. + */ + @Meteredness public int getMetered() { + return metered; + } + + /** + * @return the roaming state. Should be one of the following + * values: {link #ROAMING_YES}, {link #ROAMING_NO}. + */ + @Roaming public int getRoaming() { + return roaming; + } + + /** + * @return the default network state. Should be one of the following + * values: {link #DEFAULT_NETWORK_YES}, {link #DEFAULT_NETWORK_NO}. + */ + @DefaultNetwork public int getDefaultNetwork() { + return defaultNetwork; + } + + /** + * @return the number of received bytes. + */ + public long getRxBytes() { + return rxBytes; + } + + /** + * @return the number of received packets. + */ + public long getRxPackets() { + return rxPackets; + } + + /** + * @return the number of transmitted bytes. + */ + public long getTxBytes() { + return txBytes; + } + + /** + * @return the number of transmitted packets. + */ + public long getTxPackets() { + return txPackets; + } + + /** + * @return the count of network operations performed for this entry. + */ + public long getOperations() { + return operations; + } + @Override public String toString() { final StringBuilder builder = new StringBuilder(); @@ -593,7 +682,7 @@ public final class NetworkStats implements Parcelable { * @hide */ @UnsupportedAppUsage - public Entry getValues(int i, Entry recycle) { + public Entry getValues(int i, @Nullable Entry recycle) { final Entry entry = recycle != null ? recycle : new Entry(); entry.iface = iface[i]; entry.uid = uid[i]; From d3cb2bae4f11930a85294bcf0b320099de26557a Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 28 Dec 2021 16:18:43 +0000 Subject: [PATCH 1044/1150] [MS30] Remove ServiceManager#getService dependency Since TrafficStats is moving into the mainline module, ServiceManager#getService can no longer be accessed. This change use reflection to access getService, since there is no offical way to get the service binder, and TrafficStats is a static utility that doesn't have the context to invoke Context#getSystemService. This change also fixes minor lint errors. Test: atest CtsNetTestCases:TrafficStatsTest Bug: 204830222 Change-Id: I5caec42a71431b39f747fc791b8511d92e5cf7cc --- framework-t/src/android/net/TrafficStats.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index d8feb88f0f..032bc3f402 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -27,8 +28,8 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer; import android.os.Build; +import android.os.IBinder; import android.os.RemoteException; -import android.os.ServiceManager; import com.android.server.NetworkManagementSocketTagger; @@ -36,6 +37,8 @@ import dalvik.system.SocketTagger; import java.io.FileDescriptor; import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -53,6 +56,7 @@ import java.net.SocketException; * use {@link NetworkStatsManager} instead. */ public class TrafficStats { + private static final String TAG = TrafficStats.class.getSimpleName(); /** * The return value to indicate that the device does not support the statistic. */ @@ -173,12 +177,25 @@ public class TrafficStats { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { - sStatsService = INetworkStatsService.Stub.asInterface( - ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + sStatsService = getStatsBinder(); } return sStatsService; } + @Nullable + private static INetworkStatsService getStatsBinder() { + try { + final Method getServiceMethod = Class.forName("android.os.ServiceManager") + .getDeclaredMethod("getService", new Class[]{String.class}); + final IBinder binder = (IBinder) getServiceMethod.invoke( + null, Context.NETWORK_STATS_SERVICE); + return INetworkStatsService.Stub.asInterface(binder); + } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException + | InvocationTargetException e) { + throw new NullPointerException("Cannot get INetworkStatsService: " + e); + } + } + /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. From 69e220ccd89f6cfecd0fa2f7c406d332e6043313 Mon Sep 17 00:00:00 2001 From: lifr Date: Tue, 11 Jan 2022 11:17:36 +0800 Subject: [PATCH 1045/1150] [DU04-1]Remove NetworkPolicyManagerInternal from NetworkStatsService Expose system APIs for use by NetworkStatsService. Bug: 211843446 Test: atest NetworkStatsServiceTest NetworkPolicyManagerTest NetworkPolicyManagerServiceTest Change-Id: I56a066b7f4b4c2c8fefdd185c2e50de63b1e2629 --- service-t/src/com/android/server/net/NetworkStatsService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index e15acf3ef6..878056bbeb 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -156,7 +156,6 @@ import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; -import com.android.server.LocalServices; import java.io.File; import java.io.FileDescriptor; @@ -2120,7 +2119,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public void notifyWarningOrLimitReached() { Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.onStatsProviderWarningOrLimitReached()); + mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached()); } @Override From 2d34f3e72930ea562ea9826f0e584b9b949c5c37 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 18 Jan 2022 02:46:23 +0000 Subject: [PATCH 1046/1150] [MS63.1] Remove TrafficStats.TAG_SYSTEM_DOWNLOAD dependency Replace with system Api. Test: TH Bug: 204830222 CTS-Coverage-Bug: 215043101 Change-Id: Ic14b26d2862f6fe8bee18fe0c9eaf183052452ee --- framework-t/src/android/net/TrafficStats.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index 032bc3f402..1af32bf552 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -281,6 +281,18 @@ public class TrafficStats { setThreadStatsTag(TAG_SYSTEM_APP); } + /** + * Set active tag to use when accounting {@link Socket} traffic originating + * from the current thread. The tag used internally is well-defined to + * distinguish all download provider traffic. + * + * @hide + */ + @SystemApi + public static void setThreadStatsTagDownload() { + setThreadStatsTag(TAG_SYSTEM_DOWNLOAD); + } + /** * Get the active tag used when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. From 55b39355dd0bc40a84f9e19441e9bef9fa45f4f3 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 18 Jan 2022 04:49:55 +0000 Subject: [PATCH 1047/1150] Fix the Preconditions dependency in EthernetNetworkSpecifier. Ethernet service related files are going to be moved into Connectivity module. Replace the Preconditions class in the EthernetNetworkSpecifier, either add modules-utils-preconditions static lib dependency to fix it, however, notice that will result in the duplicate class import when moving ethernet stuff to p/m/Connectivity. Bug: 210586283 Test: atest FrameworksNetTests EthernetServiceTests Change-Id: I6163699be4126ef1b95dfb87ec9a6aba2c01195a --- framework-t/src/android/net/EthernetNetworkSpecifier.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkSpecifier.java b/framework-t/src/android/net/EthernetNetworkSpecifier.java index 62c5761442..925d12b574 100644 --- a/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ b/framework-t/src/android/net/EthernetNetworkSpecifier.java @@ -23,8 +23,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import com.android.internal.util.Preconditions; - import java.util.Objects; /** @@ -47,7 +45,9 @@ public final class EthernetNetworkSpecifier extends NetworkSpecifier implements * @param interfaceName Name of the ethernet interface the specifier refers to. */ public EthernetNetworkSpecifier(@NonNull String interfaceName) { - Preconditions.checkStringNotEmpty(interfaceName); + if (TextUtils.isEmpty(interfaceName)) { + throw new IllegalArgumentException(); + } mInterfaceName = interfaceName; } From ba8efd5c84dc025755ceb68d519f5a6429b137da Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Thu, 13 Jan 2022 15:54:41 +0000 Subject: [PATCH 1048/1150] [MS37.1] Expose APIs which is used by NPMS Test: TH Bug: 204830222 CTS-Coverage-Bug: 213124616 Change-Id: I16418791246b12fc3da7348ed36b58274e20db54 --- .../app/usage/NetworkStatsManager.java | 34 ++++++++++++++----- .../server/net/NetworkStatsService.java | 33 ++++++++++++------ 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index f74edb1a01..d00de3679e 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -18,6 +18,7 @@ package android.app.usage; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -150,7 +151,13 @@ public class NetworkStatsManager { * @param pollOnOpen true if poll is needed. * @hide */ - // @SystemApi(client = MODULE_LIBRARIES) + // The system will ignore any non-default values for non-privileged + // processes, so processes that don't hold the appropriate permissions + // can make no use of this API. + @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) public void setPollOnOpen(boolean pollOnOpen) { if (pollOnOpen) { mFlags |= FLAG_POLL_ON_OPEN; @@ -877,7 +884,7 @@ public class NetworkStatsManager { * * @hide */ - // @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @@ -890,17 +897,18 @@ public class NetworkStatsManager { } /** - * Advise persistence threshold; may be overridden internally. + * Set default value of global alert bytes, the value will be clamped to [128kB, 2MB]. * * @hide */ - // @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, - android.Manifest.permission.NETWORK_STACK}) - public void advisePersistThreshold(long thresholdBytes) { + Manifest.permission.NETWORK_STACK}) + public void setDefaultGlobalAlert(long alertBytes) { try { - mService.advisePersistThreshold(thresholdBytes); + // TODO: Sync internal naming with the API surface. + mService.advisePersistThreshold(alertBytes); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -911,7 +919,7 @@ public class NetworkStatsManager { * * @hide */ - // @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @@ -927,9 +935,17 @@ public class NetworkStatsManager { * Set the warning and limit to all registered custom network stats providers. * Note that invocation of any interface will be sent to all providers. * + * Asynchronicity notes : because traffic may be happening on the device at the same time, it + * doesn't make sense to wait for the warning and limit to be set – a caller still wouldn't + * know when exactly it was effective. All that can matter is that it's done quickly. Also, + * this method can't fail, so there is no status to return. All providers will see the new + * values soon. + * As such, this method returns immediately and sends the warning and limit to all providers + * as soon as possible through a one-way binder call. + * * @hide */ - // @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 4cc18af466..595f88d71e 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -707,12 +707,25 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return now - lastCallTime < POLL_RATE_LIMIT_MS; } - private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { + private int restrictFlagsForCaller(int flags) { + // All non-privileged callers are not allowed to turn off POLL_ON_OPEN. + final boolean isPrivileged = PermissionUtils.checkAnyPermissionOf(mContext, + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK); + if (!isPrivileged) { + flags |= NetworkStatsManager.FLAG_POLL_ON_OPEN; + } + // Non-system uids are rate limited for POLL_ON_OPEN. final int callingUid = Binder.getCallingUid(); - final int usedFlags = isRateLimitedForPoll(callingUid) + flags = isRateLimitedForPoll(callingUid) ? flags & (~NetworkStatsManager.FLAG_POLL_ON_OPEN) : flags; - if ((usedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN + return flags; + } + + private INetworkStatsSession openSessionInternal(final int flags, final String callingPackage) { + final int restrictedFlags = restrictFlagsForCaller(flags); + if ((restrictedFlags & (NetworkStatsManager.FLAG_POLL_ON_OPEN | NetworkStatsManager.FLAG_POLL_FORCE)) != 0) { final long ident = Binder.clearCallingIdentity(); try { @@ -726,7 +739,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // for its lifetime; when caller closes only weak references remain. return new INetworkStatsSession.Stub() { - private final int mCallingUid = callingUid; + private final int mCallingUid = Binder.getCallingUid(); private final String mCallingPackage = callingPackage; private final @NetworkStatsAccess.Level int mAccessLevel = checkAccessLevel( callingPackage); @@ -760,21 +773,21 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDeviceSummaryForNetwork( NetworkTemplate template, long start, long end) { - return internalGetSummaryForNetwork(template, usedFlags, start, end, mAccessLevel, - mCallingUid); + return internalGetSummaryForNetwork(template, restrictedFlags, start, end, + mAccessLevel, mCallingUid); } @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { - return internalGetSummaryForNetwork(template, usedFlags, start, end, mAccessLevel, - mCallingUid); + return internalGetSummaryForNetwork(template, restrictedFlags, start, end, + mAccessLevel, mCallingUid); } @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { - return internalGetHistoryForNetwork(template, usedFlags, fields, mAccessLevel, - mCallingUid); + return internalGetHistoryForNetwork(template, restrictedFlags, fields, + mAccessLevel, mCallingUid); } @Override From 1cad2ea6518cda5bd7031c80b529c466674b98bc Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 14 Jan 2022 23:34:54 +0800 Subject: [PATCH 1049/1150] Have NetworkStats implements iterable Make NetworkStats be iterable and expose iterator as system API which is better than expose size() and getValues(). This API could be used by the caller who needs to get entry from NetworkStats. Bug: 210073043 CTS-Coverage-Bug: 215061403 Test: build, TH Change-Id: I6cb4c8f63d7067133f2722b2be7e16b4098a697d --- framework-t/src/android/net/NetworkStats.java | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index 9d532e7929..9175809d9c 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -41,6 +41,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -57,7 +58,7 @@ import java.util.function.Predicate; */ // @NotThreadSafe @SystemApi -public final class NetworkStats implements Parcelable { +public final class NetworkStats implements Parcelable, Iterable { private static final String TAG = "NetworkStats"; /** @@ -677,6 +678,35 @@ public final class NetworkStats implements Parcelable { operations[i] = entry.operations; } + /** + * Iterate over Entry objects. + * + * Return an iterator of this object that will iterate through all contained Entry objects. + * + * This iterator does not support concurrent modification and makes no guarantee of fail-fast + * behavior. If any method that can mutate the contents of this object is called while + * iteration is in progress, either inside the loop or in another thread, then behavior is + * undefined. + * The remove() method is not implemented and will throw UnsupportedOperationException. + * @hide + */ + @SystemApi + @NonNull public Iterator iterator() { + return new Iterator() { + int mIndex = 0; + + @Override + public boolean hasNext() { + return mIndex < size; + } + + @Override + public Entry next() { + return getValues(mIndex++, null); + } + }; + } + /** * Return specific stats entry. * @hide From 172aa68e5dbf484c5a316b77bf47c20b3b03a21a Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 14 Dec 2021 23:09:55 +0800 Subject: [PATCH 1050/1150] Split out the nsd API surface and use framework-connectivity-tiramisu - Split out nsd APIs and hidden APIs to Connectivity module. - Keep the all files in f/b/packages/Connectivity-T and add framework-connectivity-tiramisu library on p/m/Connectivity. Then make framework to use this module library. - Remove NsdService from SystemServer which will register from ConnectivityServiceInitializer Bug: 206893064 Test: m online-sdk-dev-docs Test: atest FrameworksNetTests CtsNetTestCases CTS-Coverage-Bug: 207804007 Merged-In: I72c7de124b9cc53f2263bd452ecd5f39e88e485b Change-Id: I72c7de124b9cc53f2263bd452ecd5f39e88e485b --- framework-t/Sources.bp | 14 ++++++++++++-- service-t/Sources.bp | 12 +++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 90bb76a87d..d3d8bba16c 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -156,8 +156,18 @@ filegroup { ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", - ":framework-connectivity-nsd-sources", - ":framework-connectivity-tiramisu-internal-sources", ], visibility: ["//frameworks/base"], } + +filegroup { + name: "framework-connectivity-tiramisu-updatable-sources", + srcs: [ + ":framework-connectivity-nsd-sources", + ":framework-connectivity-tiramisu-internal-sources", + ], + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +} diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 97dfb64b33..b261e165a1 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -82,8 +82,18 @@ filegroup { ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", - ":services.connectivity-nsd-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], } + +filegroup { + name: "services.connectivity-tiramisu-updatable-sources", + srcs: [ + ":services.connectivity-nsd-sources", + ], + path: "src", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} From 0b275143fc90cf56ecc6460820152c8fd93386cf Mon Sep 17 00:00:00 2001 From: paulhu Date: Tue, 14 Dec 2021 23:09:55 +0800 Subject: [PATCH 1051/1150] Split out the nsd API surface and use framework-connectivity-tiramisu - Split out nsd APIs and hidden APIs to Connectivity module. - Keep the all files in f/b/packages/Connectivity-T and add framework-connectivity-tiramisu library on p/m/Connectivity. Then make framework to use this module library. - Remove NsdService from SystemServer which will register from ConnectivityServiceInitializer Bug: 206893064 Test: m online-sdk-dev-docs Test: atest FrameworksNetTests CtsNetTestCases CTS-Coverage-Bug: 207804007 Merged-In: I72c7de124b9cc53f2263bd452ecd5f39e88e485b Change-Id: I72c7de124b9cc53f2263bd452ecd5f39e88e485b --- framework-t/Sources.bp | 14 ++++++++++++-- service-t/Sources.bp | 12 +++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 90bb76a87d..d3d8bba16c 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -156,8 +156,18 @@ filegroup { ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", - ":framework-connectivity-nsd-sources", - ":framework-connectivity-tiramisu-internal-sources", ], visibility: ["//frameworks/base"], } + +filegroup { + name: "framework-connectivity-tiramisu-updatable-sources", + srcs: [ + ":framework-connectivity-nsd-sources", + ":framework-connectivity-tiramisu-internal-sources", + ], + visibility: [ + "//frameworks/base", + "//packages/modules/Connectivity:__subpackages__", + ], +} diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 97dfb64b33..b261e165a1 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -82,8 +82,18 @@ filegroup { ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", - ":services.connectivity-nsd-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], } + +filegroup { + name: "services.connectivity-tiramisu-updatable-sources", + srcs: [ + ":services.connectivity-nsd-sources", + ], + path: "src", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} From 2ace102c5ebe0efdc0943e2c3f3419b5aa451e7a Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Fri, 14 Jan 2022 17:35:36 +0000 Subject: [PATCH 1052/1150] Revert "Revert "Migrate unsafe parcel APIs in framework-minus-apex"" This reverts commit 7fe4f60b74b643507a8ec495bfde43a746994aa6. Reintroducing ag/16366278 since it seems unrelated to b/214053959 (more details on b/214053959#comment55). Original commit message: Migrate unsafe parcel APIs in framework-minus-apex Migrate the following unsafe parcel APIs in framework-minus-apex: * Parcel.readSerializable() * Parcel.readArrayList() * Parcel.readList() * Parcel.readParcelable() * Parcel.readParcelableList() * Parcel.readSparseArray() This CL was generated by applying lint fixes that infer the expected type from the caller code and provide that as the type parameter (ag/16365240). A few observations: * In some classes we couldn't migrate because the class also belonged to another build module whose min SDK wasn't current (as is the case for framework-minus-apex), hence I suppressed the lint check (since I'll eventually submit the lint check to the tree). * In some cases, I needed to do the cast in https://stackoverflow.com/a/1080525/5765705 to make the compiler happy since there isn't another way of providing a class of type Class>. * In the readSerializable() case, the new API also requires the class loader, that was inferred to by InferredClass.class.getClassLoader(). * Note that automatic formatting and import rely on running hooked up to the IDE, which wasn't the case here. Bug: 195622897 Change-Id: I272432e6e082a973f7a50492ec35d79c2b577c93 Test: TH passes --- framework-t/src/android/net/DataUsageRequest.java | 2 +- framework-t/src/android/net/IpSecConfig.java | 8 ++++---- framework-t/src/android/net/IpSecUdpEncapResponse.java | 2 +- framework-t/src/android/net/NetworkStateSnapshot.java | 6 +++--- framework-t/src/android/net/UnderlyingNetworkInfo.java | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/net/DataUsageRequest.java b/framework-t/src/android/net/DataUsageRequest.java index b06d515b3a..f0ff46522d 100644 --- a/framework-t/src/android/net/DataUsageRequest.java +++ b/framework-t/src/android/net/DataUsageRequest.java @@ -75,7 +75,7 @@ public final class DataUsageRequest implements Parcelable { @Override public DataUsageRequest createFromParcel(Parcel in) { int requestId = in.readInt(); - NetworkTemplate template = in.readParcelable(null); + NetworkTemplate template = in.readParcelable(null, android.net.NetworkTemplate.class); long thresholdInBytes = in.readLong(); DataUsageRequest result = new DataUsageRequest(requestId, template, thresholdInBytes); diff --git a/framework-t/src/android/net/IpSecConfig.java b/framework-t/src/android/net/IpSecConfig.java index 575c5ed968..03bb187f11 100644 --- a/framework-t/src/android/net/IpSecConfig.java +++ b/framework-t/src/android/net/IpSecConfig.java @@ -267,14 +267,14 @@ public final class IpSecConfig implements Parcelable { mMode = in.readInt(); mSourceAddress = in.readString(); mDestinationAddress = in.readString(); - mNetwork = (Network) in.readParcelable(Network.class.getClassLoader()); + mNetwork = (Network) in.readParcelable(Network.class.getClassLoader(), android.net.Network.class); mSpiResourceId = in.readInt(); mEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mAuthentication = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mAuthenticatedEncryption = - (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader()); + (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader(), android.net.IpSecAlgorithm.class); mEncapType = in.readInt(); mEncapSocketResourceId = in.readInt(); mEncapRemotePort = in.readInt(); diff --git a/framework-t/src/android/net/IpSecUdpEncapResponse.java b/framework-t/src/android/net/IpSecUdpEncapResponse.java index 732cf198a9..390af82366 100644 --- a/framework-t/src/android/net/IpSecUdpEncapResponse.java +++ b/framework-t/src/android/net/IpSecUdpEncapResponse.java @@ -81,7 +81,7 @@ public final class IpSecUdpEncapResponse implements Parcelable { status = in.readInt(); resourceId = in.readInt(); port = in.readInt(); - fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader()); + fileDescriptor = in.readParcelable(ParcelFileDescriptor.class.getClassLoader(), android.os.ParcelFileDescriptor.class); } @android.annotation.NonNull diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java index 3915634392..d577aa8fba 100644 --- a/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/framework-t/src/android/net/NetworkStateSnapshot.java @@ -73,9 +73,9 @@ public final class NetworkStateSnapshot implements Parcelable { /** @hide */ public NetworkStateSnapshot(@NonNull Parcel in) { - mNetwork = in.readParcelable(null); - mNetworkCapabilities = in.readParcelable(null); - mLinkProperties = in.readParcelable(null); + mNetwork = in.readParcelable(null, android.net.Network.class); + mNetworkCapabilities = in.readParcelable(null, android.net.NetworkCapabilities.class); + mLinkProperties = in.readParcelable(null, android.net.LinkProperties.class); mSubscriberId = in.readString(); mLegacyType = in.readInt(); } diff --git a/framework-t/src/android/net/UnderlyingNetworkInfo.java b/framework-t/src/android/net/UnderlyingNetworkInfo.java index 33f9375c03..7ab53b1da8 100644 --- a/framework-t/src/android/net/UnderlyingNetworkInfo.java +++ b/framework-t/src/android/net/UnderlyingNetworkInfo.java @@ -60,7 +60,7 @@ public final class UnderlyingNetworkInfo implements Parcelable { mOwnerUid = in.readInt(); mIface = in.readString(); List underlyingIfaces = new ArrayList<>(); - in.readList(underlyingIfaces, null /*classLoader*/); + in.readList(underlyingIfaces, null /*classLoader*/, java.lang.String.class); mUnderlyingIfaces = Collections.unmodifiableList(underlyingIfaces); } From 504e9b3587010d4eb54687add3976f2920b6685b Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jan 2022 15:07:06 +0000 Subject: [PATCH 1053/1150] [MS64] Remove subscriberId and NetworkId in proto netstats.proto is about to move into mainline module. And it can no longer see privacy.proto definition. Thus, this change remove PII data that is not very useful when debugging and any reference to privacy.proto. Test: adb bugreport and check output at transponder Bug: 204830222 Change-Id: I755530f356d2c16b336d62785c4c17c557f792db --- framework-t/src/android/net/NetworkIdentity.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 8f1115e065..04d1d68851 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -160,11 +160,6 @@ public class NetworkIdentity implements Comparable { // Not dumping mSubType, subtypes are no longer supported. - if (mSubscriberId != null) { - proto.write(NetworkIdentityProto.SUBSCRIBER_ID, - NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); - } - proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId); proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); From 878641336d5e41fee220c11feb66a8ecae256d7c Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 20 Jan 2022 16:05:04 +0800 Subject: [PATCH 1054/1150] [DU05]Remove the android.provider.Settings.Global in NetworkStatsService Replace android.provider.Settings.Global methods that return the default value and hardcoding them inside the methods. Bug: 213329727 Test: atest NetworkStatsServiceTest Change-Id: I51d686222f983c8deb71d4b32f9e443e87a5e53e --- .../server/net/NetworkStatsService.java | 73 +++++-------------- 1 file changed, 20 insertions(+), 53 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index e15acf3ef6..a0ee1b6a40 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -47,23 +47,6 @@ import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UNSUPPORTED; import static android.os.Trace.TRACE_TAG_NETWORK; -import static android.provider.Settings.Global.NETSTATS_AUGMENT_ENABLED; -import static android.provider.Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED; -import static android.provider.Settings.Global.NETSTATS_DEV_BUCKET_DURATION; -import static android.provider.Settings.Global.NETSTATS_DEV_DELETE_AGE; -import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; -import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE; -import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES; -import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED; -import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION; -import static android.provider.Settings.Global.NETSTATS_UID_DELETE_AGE; -import static android.provider.Settings.Global.NETSTATS_UID_PERSIST_BYTES; -import static android.provider.Settings.Global.NETSTATS_UID_ROTATE_AGE; -import static android.provider.Settings.Global.NETSTATS_UID_TAG_BUCKET_DURATION; -import static android.provider.Settings.Global.NETSTATS_UID_TAG_DELETE_AGE; -import static android.provider.Settings.Global.NETSTATS_UID_TAG_PERSIST_BYTES; -import static android.provider.Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; @@ -156,7 +139,6 @@ import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; -import com.android.server.LocalServices; import java.io.File; import java.io.FileDescriptor; @@ -217,6 +199,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final int LOG_TAG_NETSTATS_MOBILE_SAMPLE = 51100; private static final int LOG_TAG_NETSTATS_WIFI_SAMPLE = 51101; + // TODO: Replace the hardcoded string and move it into ConnectivitySettingsManager. + private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = + "netstats_combine_subtype_enabled"; + private final Context mContext; private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; @@ -428,7 +414,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsService service = new NetworkStatsService(context, INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), alarmManager, wakeLock, getDefaultClock(), - new DefaultNetworkStatsSettings(context), new NetworkStatsFactory(netd), + new DefaultNetworkStatsSettings(), new NetworkStatsFactory(netd), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -591,13 +577,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mSettings.getPollInterval(), pollIntent); mContentResolver.registerContentObserver(Settings.Global - .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED), + .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED), false /* notifyForDescendants */, mContentObserver); // Post a runnable on handler thread to call onChange(). It's for getting current value of // NETSTATS_COMBINE_SUBTYPE_ENABLED to decide start or stop monitoring RAT type changes. mHandler.post(() -> mContentObserver.onChange(false, Settings.Global - .getUriFor(Settings.Global.NETSTATS_COMBINE_SUBTYPE_ENABLED))); + .getUriFor(NETSTATS_COMBINE_SUBTYPE_ENABLED))); registerGlobalAlert(); } @@ -2179,24 +2165,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link android.provider.Settings.Global}. */ private static class DefaultNetworkStatsSettings implements NetworkStatsSettings { - private final ContentResolver mResolver; - - public DefaultNetworkStatsSettings(Context context) { - mResolver = Objects.requireNonNull(context.getContentResolver()); - // TODO: adjust these timings for production builds - } - - private long getGlobalLong(String name, long def) { - return Settings.Global.getLong(mResolver, name, def); - } - private boolean getGlobalBoolean(String name, boolean def) { - final int defInt = def ? 1 : 0; - return Settings.Global.getInt(mResolver, name, defInt) != 0; - } + DefaultNetworkStatsSettings() {} @Override public long getPollInterval() { - return getGlobalLong(NETSTATS_POLL_INTERVAL, 30 * MINUTE_IN_MILLIS); + return 30 * MINUTE_IN_MILLIS; } @Override public long getPollDelay() { @@ -2204,25 +2177,23 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override public long getGlobalAlertBytes(long def) { - return getGlobalLong(NETSTATS_GLOBAL_ALERT_BYTES, def); + return def; } @Override public boolean getSampleEnabled() { - return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true); + return true; } @Override public boolean getAugmentEnabled() { - return getGlobalBoolean(NETSTATS_AUGMENT_ENABLED, true); + return true; } @Override public boolean getCombineSubtypeEnabled() { - return getGlobalBoolean(NETSTATS_COMBINE_SUBTYPE_ENABLED, false); + return false; } @Override public Config getDevConfig() { - return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), - getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), - getGlobalLong(NETSTATS_DEV_DELETE_AGE, 90 * DAY_IN_MILLIS)); + return new Config(HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); } @Override public Config getXtConfig() { @@ -2230,31 +2201,27 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override public Config getUidConfig() { - return new Config(getGlobalLong(NETSTATS_UID_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getGlobalLong(NETSTATS_UID_ROTATE_AGE, 15 * DAY_IN_MILLIS), - getGlobalLong(NETSTATS_UID_DELETE_AGE, 90 * DAY_IN_MILLIS)); + return new Config(2 * HOUR_IN_MILLIS, 15 * DAY_IN_MILLIS, 90 * DAY_IN_MILLIS); } @Override public Config getUidTagConfig() { - return new Config(getGlobalLong(NETSTATS_UID_TAG_BUCKET_DURATION, 2 * HOUR_IN_MILLIS), - getGlobalLong(NETSTATS_UID_TAG_ROTATE_AGE, 5 * DAY_IN_MILLIS), - getGlobalLong(NETSTATS_UID_TAG_DELETE_AGE, 15 * DAY_IN_MILLIS)); + return new Config(2 * HOUR_IN_MILLIS, 5 * DAY_IN_MILLIS, 15 * DAY_IN_MILLIS); } @Override public long getDevPersistBytes(long def) { - return getGlobalLong(NETSTATS_DEV_PERSIST_BYTES, def); + return def; } @Override public long getXtPersistBytes(long def) { - return getDevPersistBytes(def); + return def; } @Override public long getUidPersistBytes(long def) { - return getGlobalLong(NETSTATS_UID_PERSIST_BYTES, def); + return def; } @Override public long getUidTagPersistBytes(long def) { - return getGlobalLong(NETSTATS_UID_TAG_PERSIST_BYTES, def); + return def; } } From bb459aeababb9bdbc50d4325e178919dba9ec210 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 5 Jan 2022 13:45:29 +0000 Subject: [PATCH 1055/1150] [MS41.1] Prepare for APIs for querying usage with template This CL includes: 1. Prepare for queryDetailsForDevice which allows callers to query history of networks that matches the given template. 2. Prepare for queryDetailsForUidTagState, which allows callers to query history uid stats with the given template, uid and other conditions. 3. Enforce fine location permission if the caller is querying data usage with a template which contains wifi network keys. Test: atest NetworkStatsServiceTest NetworkStatsManagerTest Bug: 204830222 Bug: 200768422 Change-Id: I6783d6bfd6e075e0b3ec8a3c91836377f1d71c7a --- .../src/android/app/usage/NetworkStats.java | 16 +++- .../app/usage/NetworkStatsManager.java | 85 +++++++++++++++++-- .../src/android/net/INetworkStatsSession.aidl | 5 ++ .../server/net/NetworkStatsService.java | 62 ++++++++++++-- 4 files changed, 153 insertions(+), 15 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java index d33666d744..2b6570a6ec 100644 --- a/framework-t/src/android/app/usage/NetworkStats.java +++ b/framework-t/src/android/app/usage/NetworkStats.java @@ -556,7 +556,7 @@ public final class NetworkStats implements AutoCloseable { /** * Collects history results for uid and resets history enumeration index. */ - void startHistoryEnumeration(int uid, int tag, int state) { + void startHistoryUidEnumeration(int uid, int tag, int state) { mHistory = null; try { mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid, @@ -570,6 +570,20 @@ public final class NetworkStats implements AutoCloseable { mEnumerationIndex = 0; } + /** + * Collects history results for network and resets history enumeration index. + */ + void startHistoryDeviceEnumeration() { + try { + mHistory = mSession.getHistoryIntervalForNetwork( + mTemplate, NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp); + } catch (RemoteException e) { + Log.w(TAG, e); + mHistory = null; + } + mEnumerationIndex = 0; + } + /** * Starts uid enumeration for current user. * @throws RemoteException diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index d00de3679e..4b906c9089 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -433,6 +433,42 @@ public class NetworkStatsManager { return null; // To make the compiler happy. } + /** + * Query usage statistics details for networks matching a given {@link NetworkTemplate}. + * + * Result is not aggregated over time. This means buckets' start and + * end timestamps will be between 'startTime' and 'endTime' parameters. + *

            Only includes buckets whose entire time period is included between + * startTime and endTime. Doesn't interpolate or return partial buckets. + * Since bucket length is in the order of hours, this + * method cannot be used to measure data usage on a fine grained time scale. + * This may take a long time, and apps should avoid calling this on their main thread. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param startTime Start of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @return Statistics which is described above. + * @hide + */ + @NonNull + // @SystemApi(client = MODULE_LIBRARIES) + @WorkerThread + public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template, + long startTime, long endTime) { + try { + final NetworkStats result = + new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); + result.startHistoryDeviceEnumeration(); + return result; + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + } + + return null; // To make the compiler happy. + } + /** * Query network usage statistics details for a given uid. * This may take a long time, and apps should avoid calling this on their main thread. @@ -499,7 +535,8 @@ public class NetworkStatsManager { * @param endTime End of period. Defined in terms of "Unix time", see * {@link java.lang.System#currentTimeMillis}. * @param uid UID of app - * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for no tags. + * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data + * across all the tags. * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate * traffic from all states. * @return Statistics object or null if an error happened during statistics collection. @@ -514,21 +551,51 @@ public class NetworkStatsManager { return queryDetailsForUidTagState(template, startTime, endTime, uid, tag, state); } - /** @hide */ - public NetworkStats queryDetailsForUidTagState(NetworkTemplate template, + /** + * Query network usage statistics details for a given template, uid, tag, and state. + * + * Only usable for uids belonging to calling user. Result is not aggregated over time. + * This means buckets' start and end timestamps are going to be between 'startTime' and + * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag + * the same as the 'tag' parameter, and the state the same as the 'state' parameter. + * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and + * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. + *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't + * interpolate across partial buckets. Since bucket length is in the order of hours, this + * method cannot be used to measure data usage on a fine grained time scale. + * This may take a long time, and apps should avoid calling this on their main thread. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param startTime Start of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period, in milliseconds since the Unix epoch, see + * {@link java.lang.System#currentTimeMillis}. + * @param uid UID of app + * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data + * across all the tags. + * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate + * traffic from all states. + * @return Statistics which is described above. + * @hide + */ + @NonNull + // @SystemApi(client = MODULE_LIBRARIES) + @WorkerThread + public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { - - NetworkStats result; try { - result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); - result.startHistoryEnumeration(uid, tag, state); + final NetworkStats result = new NetworkStats( + mContext, template, mFlags, startTime, endTime, mService); + result.startHistoryUidEnumeration(uid, tag, state); + return result; } catch (RemoteException e) { Log.e(TAG, "Error while querying stats for uid=" + uid + " tag=" + tag + " state=" + state, e); - return null; + e.rethrowFromSystemServer(); } - return result; + return null; // To make the compiler happy. } /** diff --git a/framework-t/src/android/net/INetworkStatsSession.aidl b/framework-t/src/android/net/INetworkStatsSession.aidl index babe0bfb97..ab70be826f 100644 --- a/framework-t/src/android/net/INetworkStatsSession.aidl +++ b/framework-t/src/android/net/INetworkStatsSession.aidl @@ -32,6 +32,11 @@ interface INetworkStatsSession { /** Return historical network layer stats for traffic that matches template. */ @UnsupportedAppUsage NetworkStatsHistory getHistoryForNetwork(in NetworkTemplate template, int fields); + /** + * Return historical network layer stats for traffic that matches template, start and end + * timestamp. + */ + NetworkStatsHistory getHistoryIntervalForNetwork(in NetworkTemplate template, int fields, long start, long end); /** * Return network layer usage summary per UID for traffic that matches template. diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 0abc52309a..a0710f77b4 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -154,6 +154,7 @@ import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import com.android.net.module.util.BestClock; import com.android.net.module.util.BinderUtils; import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; @@ -365,6 +366,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final NetworkStatsSubscriptionsMonitor mNetworkStatsSubscriptionsMonitor; + @NonNull + private final LocationPermissionChecker mLocationPermissionChecker; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -461,6 +465,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContentResolver = mContext.getContentResolver(); mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); + mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); } /** @@ -508,6 +513,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; } + + /** + * @see LocationPermissionChecker + */ + public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { + return new LocationPermissionChecker(context); + } } /** @@ -773,6 +785,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getDeviceSummaryForNetwork( NetworkTemplate template, long start, long end) { + enforceTemplatePermissions(template, callingPackage); return internalGetSummaryForNetwork(template, restrictedFlags, start, end, mAccessLevel, mCallingUid); } @@ -780,19 +793,33 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getSummaryForNetwork( NetworkTemplate template, long start, long end) { + enforceTemplatePermissions(template, callingPackage); return internalGetSummaryForNetwork(template, restrictedFlags, start, end, mAccessLevel, mCallingUid); } + // TODO: Remove this after all callers are removed. @Override public NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) { + enforceTemplatePermissions(template, callingPackage); return internalGetHistoryForNetwork(template, restrictedFlags, fields, - mAccessLevel, mCallingUid); + mAccessLevel, mCallingUid, Long.MIN_VALUE, Long.MAX_VALUE); + } + + @Override + public NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template, + int fields, long start, long end) { + enforceTemplatePermissions(template, callingPackage); + // TODO(b/200768422): Redact returned history if the template is location + // sensitive but the caller is not privileged. + return internalGetHistoryForNetwork(template, restrictedFlags, fields, + mAccessLevel, mCallingUid, start, end); } @Override public NetworkStats getSummaryForAllUid( NetworkTemplate template, long start, long end, boolean includeTags) { + enforceTemplatePermissions(template, callingPackage); try { final NetworkStats stats = getUidComplete() .getSummary(template, start, end, mAccessLevel, mCallingUid); @@ -810,6 +837,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getTaggedSummaryForAllUid( NetworkTemplate template, long start, long end) { + enforceTemplatePermissions(template, callingPackage); try { final NetworkStats tagStats = getUidTagComplete() .getSummary(template, start, end, mAccessLevel, mCallingUid); @@ -822,6 +850,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStatsHistory getHistoryForUid( NetworkTemplate template, int uid, int set, int tag, int fields) { + enforceTemplatePermissions(template, callingPackage); // NOTE: We don't augment UID-level statistics if (tag == TAG_NONE) { return getUidComplete().getHistory(template, null, uid, set, tag, fields, @@ -836,6 +865,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public NetworkStatsHistory getHistoryIntervalForUid( NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) { + enforceTemplatePermissions(template, callingPackage); + // TODO(b/200768422): Redact returned history if the template is location + // sensitive but the caller is not privileged. // NOTE: We don't augment UID-level statistics if (tag == TAG_NONE) { return getUidComplete().getHistory(template, null, uid, set, tag, fields, @@ -857,6 +889,26 @@ public class NetworkStatsService extends INetworkStatsService.Stub { }; } + private void enforceTemplatePermissions(@NonNull NetworkTemplate template, + @NonNull String callingPackage) { + // For a template with wifi network keys, it is possible for a malicious + // client to track the user locations via querying data usage. Thus, enforce + // fine location permission check. + if (!template.getWifiNetworkKeys().isEmpty()) { + final boolean canAccessFineLocation = mLocationPermissionChecker + .checkCallersLocationPermission(callingPackage, + null /* featureId */, + Binder.getCallingUid(), + false /* coarseForTargetSdkLessThanQ */, + null /* message */); + if (!canAccessFineLocation) { + throw new SecurityException("Access fine location is required when querying" + + " with wifi network keys, make sure the app has the necessary" + + "permissions and the location toggle is on."); + } + } + } + private @NetworkStatsAccess.Level int checkAccessLevel(String callingPackage) { return NetworkStatsAccess.checkAccessLevel( mContext, Binder.getCallingPid(), Binder.getCallingUid(), callingPackage); @@ -893,7 +945,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. final NetworkStatsHistory history = internalGetHistoryForNetwork(template, flags, FIELD_ALL, - accessLevel, callingUid); + accessLevel, callingUid, start, end); final long now = System.currentTimeMillis(); final NetworkStatsHistory.Entry entry = history.getValues(start, end, now, null); @@ -910,14 +962,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * appropriate. */ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, - int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid) { + int flags, int fields, @NetworkStatsAccess.Level int accessLevel, int callingUid, + long start, long end) { // We've been using pure XT stats long enough that we no longer need to // splice DEV and XT together. final SubscriptionPlan augmentPlan = resolveSubscriptionPlan(template, flags); synchronized (mStatsLock) { return mXtStatsCached.getHistory(template, augmentPlan, - UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, Long.MAX_VALUE, - accessLevel, callingUid); + UID_ALL, SET_ALL, TAG_NONE, fields, start, end, accessLevel, callingUid); } } From 84316eb4b62ab173213cccbaf030ccc62b821098 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 7 Jan 2022 14:46:26 +0000 Subject: [PATCH 1056/1150] [MS45] Expose SystemApis to query summary and history with template This includes: 1. queryDetailsForDevice: get history of network stats that matches the given template. 2. querySummaryForDevice: similar to the above one, but the result is aggregated over time. 3. queryDetailsForUidTagState: get history of uid stats that matches the given template, uid, tag and other conditions. 4. querySummary: similar to the above one, but the result is aggregated over time. 5. queryTaggedSummary: similar to the above one, but only return tagged data. Test: TH Bug: 204830222 Change-Id: Ic18010822a33e340b954e9c53dc515f3b6224d6d --- .../android/app/usage/NetworkStatsManager.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 4b906c9089..903983da07 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -211,9 +211,10 @@ public class NetworkStatsManager { */ @NonNull @WorkerThread - // @SystemApi(client = MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) public Bucket querySummaryForDevice(@NonNull NetworkTemplate template, long startTime, long endTime) { + Objects.requireNonNull(template); try { NetworkStats stats = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); @@ -385,10 +386,11 @@ public class NetworkStatsManager { * @hide */ @NonNull - // @SystemApi(client = MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats querySummary(@NonNull NetworkTemplate template, long startTime, long endTime) throws SecurityException { + Objects.requireNonNull(template); try { NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); @@ -418,10 +420,11 @@ public class NetworkStatsManager { * @hide */ @NonNull - // @SystemApi(client = MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryTaggedSummary(@NonNull NetworkTemplate template, long startTime, long endTime) throws SecurityException { + Objects.requireNonNull(template); try { NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); @@ -453,10 +456,11 @@ public class NetworkStatsManager { * @hide */ @NonNull - // @SystemApi(client = MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryDetailsForDevice(@NonNull NetworkTemplate template, long startTime, long endTime) { + Objects.requireNonNull(template); try { final NetworkStats result = new NetworkStats(mContext, template, mFlags, startTime, endTime, mService); @@ -580,10 +584,11 @@ public class NetworkStatsManager { * @hide */ @NonNull - // @SystemApi(client = MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) @WorkerThread public NetworkStats queryDetailsForUidTagState(@NonNull NetworkTemplate template, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { + Objects.requireNonNull(template); try { final NetworkStats result = new NetworkStats( mContext, template, mFlags, startTime, endTime, mService); From a8dc50de05a445adf6d79c66f1108a7804b073a4 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Sun, 16 Jan 2022 11:04:16 +0000 Subject: [PATCH 1057/1150] [MS57.1] Prepare APIs for data migration utility This includes: 1. Move PREFIX_* constants to NetworkStatsManager to expose in later changes. 2. Rename networkId to wifiNetworkKey. 3. Rename subType to ratType. 4. Replace SUBTYPE_COMBINED with NETWORK_TYPE_ALL 5. Fix lint errors when exposing system api. Test: TH Bug: 204830222 Change-Id: I2b7c34958bc59c3225c96f12abba008b83101585 --- .../app/usage/NetworkStatsManager.java | 13 +++ .../src/android/net/NetworkIdentity.java | 96 ++++++++++++------- .../src/android/net/NetworkIdentitySet.java | 38 ++++++-- .../android/net/NetworkStatsCollection.java | 71 ++++++++++++-- .../src/android/net/NetworkStatsHistory.java | 54 ++++++++++- .../src/android/net/NetworkTemplate.java | 30 +++--- .../server/net/NetworkStatsService.java | 28 +++--- 7 files changed, 245 insertions(+), 85 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 903983da07..8d93354ea9 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -125,6 +125,19 @@ public class NetworkStatsManager { private final Context mContext; private final INetworkStatsService mService; + /** + * Type constants for reading different types of Data Usage. + * @hide + */ + // @SystemApi(client = MODULE_LIBRARIES) + public static final String PREFIX_DEV = "dev"; + /** @hide */ + public static final String PREFIX_XT = "xt"; + /** @hide */ + public static final String PREFIX_UID = "uid"; + /** @hide */ + public static final String PREFIX_UID_TAG = "uid_tag"; + /** @hide */ public static final int FLAG_POLL_ON_OPEN = 1 << 0; /** @hide */ diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 04d1d68851..097b9bea90 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -17,12 +17,15 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; +import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; -import android.telephony.Annotation.NetworkType; +import android.telephony.Annotation; +import android.telephony.TelephonyManager; import android.util.proto.ProtoOutputStream; import com.android.net.module.util.NetworkCapabilitiesUtils; @@ -37,9 +40,13 @@ import java.util.Objects; * * @hide */ +// @SystemApi(client = MODULE_LIBRARIES) public class NetworkIdentity implements Comparable { private static final String TAG = "NetworkIdentity"; + /** @hide */ + // TODO: Remove this after migrating all callers to use + // {@link NetworkTemplate#NETWORK_TYPE_ALL} instead. public static final int SUBTYPE_COMBINED = -1; /** @@ -59,21 +66,22 @@ public class NetworkIdentity implements Comparable { public static final int OEM_PRIVATE = 0x2; final int mType; - final int mSubType; + final int mRatType; final String mSubscriberId; - final String mNetworkId; + final String mWifiNetworkKey; final boolean mRoaming; final boolean mMetered; final boolean mDefaultNetwork; final int mOemManaged; + /** @hide */ public NetworkIdentity( - int type, int subType, String subscriberId, String networkId, boolean roaming, - boolean metered, boolean defaultNetwork, int oemManaged) { + int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, + boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged) { mType = type; - mSubType = subType; + mRatType = ratType; mSubscriberId = subscriberId; - mNetworkId = networkId; + mWifiNetworkKey = wifiNetworkKey; mRoaming = roaming; mMetered = metered; mDefaultNetwork = defaultNetwork; @@ -82,7 +90,7 @@ public class NetworkIdentity implements Comparable { @Override public int hashCode() { - return Objects.hash(mType, mSubType, mSubscriberId, mNetworkId, mRoaming, mMetered, + return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, mDefaultNetwork, mOemManaged); } @@ -90,9 +98,9 @@ public class NetworkIdentity implements Comparable { public boolean equals(@Nullable Object obj) { if (obj instanceof NetworkIdentity) { final NetworkIdentity ident = (NetworkIdentity) obj; - return mType == ident.mType && mSubType == ident.mSubType && mRoaming == ident.mRoaming + return mType == ident.mType && mRatType == ident.mRatType && mRoaming == ident.mRoaming && Objects.equals(mSubscriberId, ident.mSubscriberId) - && Objects.equals(mNetworkId, ident.mNetworkId) + && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) && mMetered == ident.mMetered && mDefaultNetwork == ident.mDefaultNetwork && mOemManaged == ident.mOemManaged; @@ -104,18 +112,18 @@ public class NetworkIdentity implements Comparable { public String toString() { final StringBuilder builder = new StringBuilder("{"); builder.append("type=").append(mType); - builder.append(", subType="); - if (mSubType == SUBTYPE_COMBINED) { + builder.append(", ratType="); + if (mRatType == NETWORK_TYPE_ALL) { builder.append("COMBINED"); } else { - builder.append(mSubType); + builder.append(mRatType); } if (mSubscriberId != null) { builder.append(", subscriberId=") .append(NetworkIdentityUtils.scrubSubscriberId(mSubscriberId)); } - if (mNetworkId != null) { - builder.append(", networkId=").append(mNetworkId); + if (mWifiNetworkKey != null) { + builder.append(", wifiNetworkKey=").append(mWifiNetworkKey); } if (mRoaming) { builder.append(", ROAMING"); @@ -153,12 +161,13 @@ public class NetworkIdentity implements Comparable { } } + /** @hide */ public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); proto.write(NetworkIdentityProto.TYPE, mType); - // Not dumping mSubType, subtypes are no longer supported. + // TODO: dump mRatType as well. proto.write(NetworkIdentityProto.ROAMING, mRoaming); proto.write(NetworkIdentityProto.METERED, mMetered); @@ -168,50 +177,68 @@ public class NetworkIdentity implements Comparable { proto.end(start); } + /** @hide */ public int getType() { return mType; } - public int getSubType() { - return mSubType; + /** @hide */ + public int getRatType() { + return mRatType; } + /** @hide */ public String getSubscriberId() { return mSubscriberId; } - public String getNetworkId() { - return mNetworkId; + /** @hide */ + public String getWifiNetworkKey() { + return mWifiNetworkKey; } + /** @hide */ public boolean getRoaming() { return mRoaming; } + /** @hide */ public boolean getMetered() { return mMetered; } + /** @hide */ public boolean getDefaultNetwork() { return mDefaultNetwork; } + /** @hide */ public int getOemManaged() { return mOemManaged; } /** - * Build a {@link NetworkIdentity} from the given {@link NetworkStateSnapshot} and - * {@code subType}, assuming that any mobile networks are using the current IMSI. - * The subType if applicable, should be set as one of the TelephonyManager.NETWORK_TYPE_* - * constants, or {@link android.telephony.TelephonyManager#NETWORK_TYPE_UNKNOWN} if not. + * Assemble a {@link NetworkIdentity} from the passed arguments. + * + * This methods builds an identity based on the capabilities of the network in the + * snapshot and other passed arguments. The identity is used as a key to record data usage. + * + * @param snapshot the snapshot of network state. See {@link NetworkStateSnapshot}. + * @param defaultNetwork whether the network is a default network. + * @param ratType the Radio Access Technology(RAT) type of the network. Or + * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable. + * See {@code TelephonyManager.NETWORK_TYPE_*}. + * @hide */ + // TODO: Remove this after all callers are migrated to use new Api. + @NonNull public static NetworkIdentity buildNetworkIdentity(Context context, - NetworkStateSnapshot snapshot, boolean defaultNetwork, @NetworkType int subType) { + @NonNull NetworkStateSnapshot snapshot, + boolean defaultNetwork, @Annotation.NetworkType int ratType) { final int legacyType = snapshot.getLegacyType(); final String subscriberId = snapshot.getSubscriberId(); - String networkId = null; + String wifiNetworkKey = null; boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( @@ -226,19 +253,19 @@ public class NetworkIdentity implements Comparable { .getTransportInfo(); if (transportInfo instanceof WifiInfo) { final WifiInfo info = (WifiInfo) transportInfo; - networkId = info != null ? info.getCurrentNetworkKey() : null; + wifiNetworkKey = info != null ? info.getCurrentNetworkKey() : null; } } - return new NetworkIdentity(legacyType, subType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemManaged); + return new NetworkIdentity(legacyType, ratType, subscriberId, wifiNetworkKey, roaming, + metered, defaultNetwork, oemManaged); } /** * Builds a bitfield of {@code NetworkIdentity.OEM_*} based on {@link NetworkCapabilities}. * @hide */ - public static int getOemBitfield(NetworkCapabilities nc) { + public static int getOemBitfield(@NonNull NetworkCapabilities nc) { int oemManaged = OEM_NONE; if (nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_OEM_PAID)) { @@ -252,16 +279,17 @@ public class NetworkIdentity implements Comparable { } @Override - public int compareTo(NetworkIdentity another) { + public int compareTo(@NonNull NetworkIdentity another) { + Objects.requireNonNull(another); int res = Integer.compare(mType, another.mType); if (res == 0) { - res = Integer.compare(mSubType, another.mSubType); + res = Integer.compare(mRatType, another.mRatType); } if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) { res = mSubscriberId.compareTo(another.mSubscriberId); } - if (res == 0 && mNetworkId != null && another.mNetworkId != null) { - res = mNetworkId.compareTo(another.mNetworkId); + if (res == 0 && mWifiNetworkKey != null && another.mWifiNetworkKey != null) { + res = mWifiNetworkKey.compareTo(another.mWifiNetworkKey); } if (res == 0) { res = Boolean.compare(mRoaming, another.mRoaming); diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index abbebef85c..c2d8ea1f96 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -18,6 +18,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import android.annotation.NonNull; import android.service.NetworkIdentitySetProto; import android.util.proto.ProtoOutputStream; @@ -25,6 +26,7 @@ import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.HashSet; +import java.util.Objects; /** * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} @@ -32,6 +34,7 @@ import java.util.HashSet; * * @hide */ +// @SystemApi(client = MODULE_LIBRARIES) public class NetworkIdentitySet extends HashSet implements Comparable { private static final int VERSION_INIT = 1; @@ -41,9 +44,14 @@ public class NetworkIdentitySet extends HashSet implements private static final int VERSION_ADD_DEFAULT_NETWORK = 5; private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; + /** + * Construct a {@link NetworkIdentitySet} object. + */ public NetworkIdentitySet() { + super(); } + /** @hide */ public NetworkIdentitySet(DataInput in) throws IOException { final int version = in.readInt(); final int size = in.readInt(); @@ -52,7 +60,7 @@ public class NetworkIdentitySet extends HashSet implements final int ignored = in.readInt(); } final int type = in.readInt(); - final int subType = in.readInt(); + final int ratType = in.readInt(); final String subscriberId = readOptionalString(in); final String networkId; if (version >= VERSION_ADD_NETWORK_ID) { @@ -91,22 +99,23 @@ public class NetworkIdentitySet extends HashSet implements oemNetCapabilities = NetworkIdentity.OEM_NONE; } - add(new NetworkIdentity(type, subType, subscriberId, networkId, roaming, metered, + add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, defaultNetwork, oemNetCapabilities)); } } /** * Method to serialize this object into a {@code DataOutput}. + * @hide */ public void writeToStream(DataOutput out) throws IOException { out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); - out.writeInt(ident.getSubType()); + out.writeInt(ident.getRatType()); writeOptionalString(out, ident.getSubscriberId()); - writeOptionalString(out, ident.getNetworkId()); + writeOptionalString(out, ident.getWifiNetworkKey()); out.writeBoolean(ident.getRoaming()); out.writeBoolean(ident.getMetered()); out.writeBoolean(ident.getDefaultNetwork()); @@ -114,7 +123,10 @@ public class NetworkIdentitySet extends HashSet implements } } - /** @return whether any {@link NetworkIdentity} in this set is considered metered. */ + /** + * @return whether any {@link NetworkIdentity} in this set is considered metered. + * @hide + */ public boolean isAnyMemberMetered() { if (isEmpty()) { return false; @@ -127,7 +139,10 @@ public class NetworkIdentitySet extends HashSet implements return false; } - /** @return whether any {@link NetworkIdentity} in this set is considered roaming. */ + /** + * @return whether any {@link NetworkIdentity} in this set is considered roaming. + * @hide + */ public boolean isAnyMemberRoaming() { if (isEmpty()) { return false; @@ -140,8 +155,11 @@ public class NetworkIdentitySet extends HashSet implements return false; } - /** @return whether any {@link NetworkIdentity} in this set is considered on the default - network. */ + /** + * @return whether any {@link NetworkIdentity} in this set is considered on the default + * network. + * @hide + */ public boolean areAllMembersOnDefaultNetwork() { if (isEmpty()) { return true; @@ -172,7 +190,8 @@ public class NetworkIdentitySet extends HashSet implements } @Override - public int compareTo(NetworkIdentitySet another) { + public int compareTo(@NonNull NetworkIdentitySet another) { + Objects.requireNonNull(another); if (isEmpty()) return -1; if (another.isEmpty()) return 1; @@ -183,6 +202,7 @@ public class NetworkIdentitySet extends HashSet implements /** * Method to dump this object into proto debug file. + * @hide */ public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 9f9d73f888..f169fed6b9 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -32,6 +32,8 @@ import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; import android.service.NetworkStatsCollectionProto; @@ -77,6 +79,7 @@ import java.util.Objects; * * @hide */ +// @SystemApi(client = MODULE_LIBRARIES) public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { private static final String TAG = NetworkStatsCollection.class.getSimpleName(); /** File header magic number: "ANET" */ @@ -100,15 +103,23 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private long mTotalBytes; private boolean mDirty; + /** + * Construct a {@link NetworkStatsCollection} object. + * + * @param bucketDuration duration of the buckets in this object, in milliseconds. + * @hide + */ public NetworkStatsCollection(long bucketDuration) { mBucketDuration = bucketDuration; reset(); } + /** @hide */ public void clear() { reset(); } + /** @hide */ public void reset() { mStats.clear(); mStartMillis = Long.MAX_VALUE; @@ -117,6 +128,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W mDirty = false; } + /** @hide */ public long getStartMillis() { return mStartMillis; } @@ -124,6 +136,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Return first atomic bucket in this collection, which is more conservative * than {@link #mStartMillis}. + * @hide */ public long getFirstAtomicBucketMillis() { if (mStartMillis == Long.MAX_VALUE) { @@ -133,26 +146,32 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ public long getEndMillis() { return mEndMillis; } + /** @hide */ public long getTotalBytes() { return mTotalBytes; } + /** @hide */ public boolean isDirty() { return mDirty; } + /** @hide */ public void clearDirty() { mDirty = false; } + /** @hide */ public boolean isEmpty() { return mStartMillis == Long.MAX_VALUE && mEndMillis == Long.MIN_VALUE; } + /** @hide */ @VisibleForTesting public long roundUp(long time) { if (time == Long.MIN_VALUE || time == Long.MAX_VALUE @@ -168,6 +187,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ @VisibleForTesting public long roundDown(long time) { if (time == Long.MIN_VALUE || time == Long.MAX_VALUE @@ -182,10 +202,12 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel) { return getRelevantUids(accessLevel, Binder.getCallingUid()); } + /** @hide */ public int[] getRelevantUids(@NetworkStatsAccess.Level int accessLevel, final int callerUid) { final ArrayList uids = new ArrayList<>(); @@ -206,6 +228,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Combine all {@link NetworkStatsHistory} in this collection which match * the requested parameters. + * @hide */ public NetworkStatsHistory getHistory(NetworkTemplate template, SubscriptionPlan augmentPlan, int uid, int set, int tag, int fields, long start, long end, @@ -331,6 +354,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * @param end - end of the range, timestamp in milliseconds since the epoch. * @param accessLevel - caller access level. * @param callerUid - caller UID. + * @hide */ public NetworkStats getSummary(NetworkTemplate template, long start, long end, @NetworkStatsAccess.Level int accessLevel, int callerUid) { @@ -377,6 +401,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Record given {@link android.net.NetworkStats.Entry} into this collection. + * @hide */ public void recordData(NetworkIdentitySet ident, int uid, int set, int tag, long start, long end, NetworkStats.Entry entry) { @@ -387,8 +412,12 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Record given {@link NetworkStatsHistory} into this collection. + * + * @hide */ - private void recordHistory(Key key, NetworkStatsHistory history) { + public void recordHistory(@NonNull Key key, @NonNull NetworkStatsHistory history) { + Objects.requireNonNull(key); + Objects.requireNonNull(history); if (history.size() == 0) return; noteRecordedHistory(history.getStart(), history.getEnd(), history.getTotalBytes()); @@ -403,8 +432,11 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W /** * Record all {@link NetworkStatsHistory} contained in the given collection * into this collection. + * + * @hide */ - public void recordCollection(NetworkStatsCollection another) { + public void recordCollection(@NonNull NetworkStatsCollection another) { + Objects.requireNonNull(another); for (int i = 0; i < another.mStats.size(); i++) { final Key key = another.mStats.keyAt(i); final NetworkStatsHistory value = another.mStats.valueAt(i); @@ -433,6 +465,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ @Override public void read(InputStream in) throws IOException { read((DataInput) new DataInputStream(in)); @@ -472,6 +505,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ @Override public void write(OutputStream out) throws IOException { write((DataOutput) new DataOutputStream(out)); @@ -514,6 +548,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. * * @deprecated + * @hide */ @Deprecated public void readLegacyNetwork(File file) throws IOException { @@ -559,6 +594,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * See {@code NetworkStatsService#maybeUpgradeLegacyStatsLocked}. * * @deprecated + * @hide */ @Deprecated public void readLegacyUid(File file, boolean onlyTags) throws IOException { @@ -629,6 +665,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * Remove any {@link NetworkStatsHistory} attributed to the requested UID, * moving any {@link NetworkStats#TAG_NONE} series to * {@link TrafficStats#UID_REMOVED}. + * @hide */ public void removeUids(int[] uids) { final ArrayList knownKeys = new ArrayList<>(); @@ -669,6 +706,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W return keys; } + /** @hide */ public void dump(IndentingPrintWriter pw) { for (Key key : getSortedKeys()) { pw.print("ident="); pw.print(key.ident.toString()); @@ -683,6 +721,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } } + /** @hide */ public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); @@ -706,6 +745,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W proto.end(start); } + /** @hide */ public void dumpCheckin(PrintWriter pw, long start, long end) { dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell"); dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi"); @@ -768,16 +808,32 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W return false; } - private static class Key implements Comparable { + /** + * the identifier that associate with the {@link NetworkStatsHistory} object to identify + * a certain record in the {@link NetworkStatsCollection} object. + */ + public static class Key implements Comparable { + /** @hide */ public final NetworkIdentitySet ident; + /** @hide */ public final int uid; + /** @hide */ public final int set; + /** @hide */ public final int tag; private final int mHashCode; - Key(NetworkIdentitySet ident, int uid, int set, int tag) { - this.ident = ident; + /** + * Construct a {@link Key} object. + * + * @param ident a Set of {@link NetworkIdentity} that associated with the record. + * @param uid Uid of the record. + * @param set Set of the record, see {@code NetworkStats#SET_*}. + * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}. + */ + public Key(@NonNull NetworkIdentitySet ident, int uid, int set, int tag) { + this.ident = Objects.requireNonNull(ident); this.uid = uid; this.set = set; this.tag = tag; @@ -790,7 +846,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } @Override - public boolean equals(Object obj) { + public boolean equals(@Nullable Object obj) { if (obj instanceof Key) { final Key key = (Key) obj; return uid == key.uid && set == key.set && tag == key.tag @@ -800,7 +856,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W } @Override - public int compareTo(Key another) { + public int compareTo(@NonNull Key another) { + Objects.requireNonNull(another); int res = 0; if (ident != null && another.ident != null) { res = ident.compareTo(another.ident); diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 428bc6df26..90054c683d 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -30,6 +30,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; +import android.annotation.NonNull; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -64,18 +65,25 @@ import java.util.Random; * * @hide */ -public class NetworkStatsHistory implements Parcelable { +// @SystemApi(client = MODULE_LIBRARIES) +public final class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_PACKETS = 2; private static final int VERSION_ADD_ACTIVE = 3; + /** @hide */ public static final int FIELD_ACTIVE_TIME = 0x01; + /** @hide */ public static final int FIELD_RX_BYTES = 0x02; + /** @hide */ public static final int FIELD_RX_PACKETS = 0x04; + /** @hide */ public static final int FIELD_TX_BYTES = 0x08; + /** @hide */ public static final int FIELD_TX_PACKETS = 0x10; + /** @hide */ public static final int FIELD_OPERATIONS = 0x20; - + /** @hide */ public static final int FIELD_ALL = 0xFFFFFFFF; private long bucketDuration; @@ -108,15 +116,18 @@ public class NetworkStatsHistory implements Parcelable { public long operations; } + /** @hide */ @UnsupportedAppUsage public NetworkStatsHistory(long bucketDuration) { this(bucketDuration, 10, FIELD_ALL); } + /** @hide */ public NetworkStatsHistory(long bucketDuration, int initialSize) { this(bucketDuration, initialSize, FIELD_ALL); } + /** @hide */ public NetworkStatsHistory(long bucketDuration, int initialSize, int fields) { this.bucketDuration = bucketDuration; bucketStart = new long[initialSize]; @@ -130,11 +141,13 @@ public class NetworkStatsHistory implements Parcelable { totalBytes = 0; } + /** @hide */ public NetworkStatsHistory(NetworkStatsHistory existing, long bucketDuration) { this(bucketDuration, existing.estimateResizeBuckets(bucketDuration)); recordEntireHistory(existing); } + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public NetworkStatsHistory(Parcel in) { bucketDuration = in.readLong(); @@ -150,7 +163,7 @@ public class NetworkStatsHistory implements Parcelable { } @Override - public void writeToParcel(Parcel out, int flags) { + public void writeToParcel(@NonNull Parcel out, int flags) { out.writeLong(bucketDuration); writeLongArray(out, bucketStart, bucketCount); writeLongArray(out, activeTime, bucketCount); @@ -162,6 +175,7 @@ public class NetworkStatsHistory implements Parcelable { out.writeLong(totalBytes); } + /** @hide */ public NetworkStatsHistory(DataInput in) throws IOException { final int version = in.readInt(); switch (version) { @@ -204,6 +218,7 @@ public class NetworkStatsHistory implements Parcelable { } } + /** @hide */ public void writeToStream(DataOutput out) throws IOException { out.writeInt(VERSION_ADD_ACTIVE); out.writeLong(bucketDuration); @@ -221,15 +236,18 @@ public class NetworkStatsHistory implements Parcelable { return 0; } + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int size() { return bucketCount; } + /** @hide */ public long getBucketDuration() { return bucketDuration; } + /** @hide */ @UnsupportedAppUsage public long getStart() { if (bucketCount > 0) { @@ -239,6 +257,7 @@ public class NetworkStatsHistory implements Parcelable { } } + /** @hide */ @UnsupportedAppUsage public long getEnd() { if (bucketCount > 0) { @@ -250,6 +269,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return total bytes represented by this history. + * @hide */ public long getTotalBytes() { return totalBytes; @@ -258,6 +278,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return index of bucket that contains or is immediately before the * requested time. + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public int getIndexBefore(long time) { @@ -273,6 +294,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return index of bucket that contains or is immediately after the * requested time. + * @hide */ public int getIndexAfter(long time) { int index = Arrays.binarySearch(bucketStart, 0, bucketCount, time); @@ -286,6 +308,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Return specific stats entry. + * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public Entry getValues(int i, Entry recycle) { @@ -301,6 +324,7 @@ public class NetworkStatsHistory implements Parcelable { return entry; } + /** @hide */ public void setValues(int i, Entry entry) { // Unwind old values if (rxBytes != null) totalBytes -= rxBytes[i]; @@ -322,6 +346,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Record that data traffic occurred in the given time range. Will * distribute across internal buckets, creating new buckets as needed. + * @hide */ @Deprecated public void recordData(long start, long end, long rxBytes, long txBytes) { @@ -332,6 +357,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Record that data traffic occurred in the given time range. Will * distribute across internal buckets, creating new buckets as needed. + * @hide */ public void recordData(long start, long end, NetworkStats.Entry entry) { long rxBytes = entry.rxBytes; @@ -392,6 +418,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Record an entire {@link NetworkStatsHistory} into this history. Usually * for combining together stats for external reporting. + * @hide */ @UnsupportedAppUsage public void recordEntireHistory(NetworkStatsHistory input) { @@ -402,6 +429,7 @@ public class NetworkStatsHistory implements Parcelable { * Record given {@link NetworkStatsHistory} into this history, copying only * buckets that atomically occur in the inclusive time range. Doesn't * interpolate across partial buckets. + * @hide */ public void recordHistory(NetworkStatsHistory input, long start, long end) { final NetworkStats.Entry entry = new NetworkStats.Entry( @@ -483,6 +511,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Clear all data stored in this object. + * @hide */ public void clear() { bucketStart = EmptyArray.LONG; @@ -498,9 +527,10 @@ public class NetworkStatsHistory implements Parcelable { /** * Remove buckets older than requested cutoff. + * @hide */ - @Deprecated public void removeBucketsBefore(long cutoff) { + // TODO: Consider use getIndexBefore. int i; for (i = 0; i < bucketCount; i++) { final long curStart = bucketStart[i]; @@ -522,7 +552,9 @@ public class NetworkStatsHistory implements Parcelable { if (operations != null) operations = Arrays.copyOfRange(operations, i, length); bucketCount -= i; - // TODO: subtract removed values from totalBytes + totalBytes = 0; + if (rxBytes != null) totalBytes += CollectionUtils.total(rxBytes); + if (txBytes != null) totalBytes += CollectionUtils.total(txBytes); } } @@ -536,6 +568,7 @@ public class NetworkStatsHistory implements Parcelable { * @param start - start of the range, timestamp in milliseconds since the epoch. * @param end - end of the range, timestamp in milliseconds since the epoch. * @param recycle - entry instance for performance, could be null. + * @hide */ @UnsupportedAppUsage public Entry getValues(long start, long end, Entry recycle) { @@ -550,6 +583,7 @@ public class NetworkStatsHistory implements Parcelable { * @param end - end of the range, timestamp in milliseconds since the epoch. * @param now - current timestamp in milliseconds since the epoch (wall clock). * @param recycle - entry instance for performance, could be null. + * @hide */ @UnsupportedAppUsage public Entry getValues(long start, long end, long now, Entry recycle) { @@ -613,6 +647,7 @@ public class NetworkStatsHistory implements Parcelable { /** * @deprecated only for temporary testing + * @hide */ @Deprecated public void generateRandom(long start, long end, long bytes) { @@ -631,6 +666,7 @@ public class NetworkStatsHistory implements Parcelable { /** * @deprecated only for temporary testing + * @hide */ @Deprecated public void generateRandom(long start, long end, long rxBytes, long rxPackets, long txBytes, @@ -660,12 +696,14 @@ public class NetworkStatsHistory implements Parcelable { } } + /** @hide */ public static long randomLong(Random r, long start, long end) { return (long) (start + (r.nextFloat() * (end - start))); } /** * Quickly determine if this history intersects with given window. + * @hide */ public boolean intersects(long start, long end) { final long dataStart = getStart(); @@ -677,6 +715,7 @@ public class NetworkStatsHistory implements Parcelable { return false; } + /** @hide */ public void dump(IndentingPrintWriter pw, boolean fullHistory) { pw.print("NetworkStatsHistory: bucketDuration="); pw.println(bucketDuration / SECOND_IN_MILLIS); @@ -700,6 +739,7 @@ public class NetworkStatsHistory implements Parcelable { pw.decreaseIndent(); } + /** @hide */ public void dumpCheckin(PrintWriter pw) { pw.print("d,"); pw.print(bucketDuration / SECOND_IN_MILLIS); @@ -717,6 +757,7 @@ public class NetworkStatsHistory implements Parcelable { } } + /** @hide */ public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); @@ -776,6 +817,7 @@ public class NetworkStatsHistory implements Parcelable { if (array != null) array[i] += value; } + /** @hide */ public int estimateResizeBuckets(long newBucketDuration) { return (int) (size() * getBucketDuration() / newBucketDuration); } @@ -783,6 +825,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Utility methods for interacting with {@link DataInputStream} and * {@link DataOutputStream}, mostly dealing with writing partial arrays. + * @hide */ public static class DataStreamUtils { @Deprecated @@ -857,6 +900,7 @@ public class NetworkStatsHistory implements Parcelable { /** * Utility methods for interacting with {@link Parcel} structures, mostly * dealing with writing partial arrays. + * @hide */ public static class ParcelUtils { public static long[] readLongArray(Parcel in) { diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index e9084b0196..a7e48d4363 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -364,7 +364,7 @@ public final class NetworkTemplate implements Parcelable { private final int mMetered; private final int mRoaming; private final int mDefaultNetwork; - private final int mSubType; + private final int mRatType; /** * The subscriber Id match rule defines how the template should match networks with * specific subscriberId(s). See NetworkTemplate#SUBSCRIBER_ID_MATCH_RULE_* for more detail. @@ -413,18 +413,18 @@ public final class NetworkTemplate implements Parcelable { /** @hide */ // TODO: Remove it after updating all of the caller. public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, - String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int subType, + String wifiNetworkKey, int metered, int roaming, int defaultNetwork, int ratType, int oemManaged) { this(matchRule, subscriberId, matchSubscriberIds, wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0], - metered, roaming, defaultNetwork, subType, oemManaged, + metered, roaming, defaultNetwork, ratType, oemManaged, NetworkStatsUtils.SUBSCRIBER_ID_MATCH_RULE_EXACT); } /** @hide */ public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds, String[] matchWifiNetworkKeys, int metered, int roaming, - int defaultNetwork, int subType, int oemManaged, int subscriberIdMatchRule) { + int defaultNetwork, int ratType, int oemManaged, int subscriberIdMatchRule) { Objects.requireNonNull(matchWifiNetworkKeys); mMatchRule = matchRule; mSubscriberId = subscriberId; @@ -435,7 +435,7 @@ public final class NetworkTemplate implements Parcelable { mMetered = metered; mRoaming = roaming; mDefaultNetwork = defaultNetwork; - mSubType = subType; + mRatType = ratType; mOemManaged = oemManaged; mSubscriberIdMatchRule = subscriberIdMatchRule; checkValidSubscriberIdMatchRule(matchRule, subscriberIdMatchRule); @@ -453,7 +453,7 @@ public final class NetworkTemplate implements Parcelable { mMetered = in.readInt(); mRoaming = in.readInt(); mDefaultNetwork = in.readInt(); - mSubType = in.readInt(); + mRatType = in.readInt(); mOemManaged = in.readInt(); mSubscriberIdMatchRule = in.readInt(); } @@ -467,7 +467,7 @@ public final class NetworkTemplate implements Parcelable { dest.writeInt(mMetered); dest.writeInt(mRoaming); dest.writeInt(mDefaultNetwork); - dest.writeInt(mSubType); + dest.writeInt(mRatType); dest.writeInt(mOemManaged); dest.writeInt(mSubscriberIdMatchRule); } @@ -500,8 +500,8 @@ public final class NetworkTemplate implements Parcelable { builder.append(", defaultNetwork=").append(NetworkStats.defaultNetworkToString( mDefaultNetwork)); } - if (mSubType != NETWORK_TYPE_ALL) { - builder.append(", subType=").append(mSubType); + if (mRatType != NETWORK_TYPE_ALL) { + builder.append(", ratType=").append(mRatType); } if (mOemManaged != OEM_MANAGED_ALL) { builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); @@ -514,7 +514,7 @@ public final class NetworkTemplate implements Parcelable { @Override public int hashCode() { return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys), - mMetered, mRoaming, mDefaultNetwork, mSubType, mOemManaged, mSubscriberIdMatchRule); + mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged, mSubscriberIdMatchRule); } @Override @@ -526,7 +526,7 @@ public final class NetworkTemplate implements Parcelable { && mMetered == other.mMetered && mRoaming == other.mRoaming && mDefaultNetwork == other.mDefaultNetwork - && mSubType == other.mSubType + && mRatType == other.mRatType && mOemManaged == other.mOemManaged && mSubscriberIdMatchRule == other.mSubscriberIdMatchRule && Arrays.equals(mMatchWifiNetworkKeys, other.mMatchWifiNetworkKeys); @@ -635,7 +635,7 @@ public final class NetworkTemplate implements Parcelable { * Get the Radio Access Technology(RAT) type filter of the template. */ public int getRatType() { - return mSubType; + return mRatType; } /** @@ -708,8 +708,8 @@ public final class NetworkTemplate implements Parcelable { } private boolean matchesCollapsedRatType(NetworkIdentity ident) { - return mSubType == NETWORK_TYPE_ALL - || getCollapsedRatType(mSubType) == getCollapsedRatType(ident.mSubType); + return mRatType == NETWORK_TYPE_ALL + || getCollapsedRatType(mRatType) == getCollapsedRatType(ident.mRatType); } /** @@ -837,7 +837,7 @@ public final class NetworkTemplate implements Parcelable { switch (ident.mType) { case TYPE_WIFI: return matchesSubscriberId(ident.mSubscriberId) - && matchesWifiNetworkKey(ident.mNetworkId); + && matchesWifiNetworkKey(ident.mWifiNetworkKey); default: return false; } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index a0710f77b4..4bb61bd090 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -19,12 +19,15 @@ package com.android.server.net; import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; +import static android.app.usage.NetworkStatsManager.PREFIX_DEV; +import static android.app.usage.NetworkStatsManager.PREFIX_UID; +import static android.app.usage.NetworkStatsManager.PREFIX_UID_TAG; +import static android.app.usage.NetworkStatsManager.PREFIX_XT; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; -import static android.net.NetworkIdentity.SUBTYPE_COMBINED; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.IFACE_VT; @@ -243,11 +246,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private PendingIntent mPollIntent; - private static final String PREFIX_DEV = "dev"; - private static final String PREFIX_XT = "xt"; - private static final String PREFIX_UID = "uid"; - private static final String PREFIX_UID_TAG = "uid_tag"; - /** * Settings that can be changed externally. */ @@ -257,9 +255,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { boolean getSampleEnabled(); boolean getAugmentEnabled(); /** - * When enabled, all mobile data is reported under {@link NetworkIdentity#SUBTYPE_COMBINED}. - * When disabled, mobile data is broken down by a granular subtype representative of the - * actual subtype. {@see NetworkTemplate#getCollapsedRatType}. + * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}. + * When disabled, mobile data is broken down by a granular ratType representative of the + * actual ratType. {@see NetworkTemplate#getCollapsedRatType}. * Enabling this decreases the level of detail but saves performance, disk space and * amount of data logged. */ @@ -1389,10 +1387,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); final boolean isDefault = CollectionUtils.contains( mDefaultNetworks, snapshot.getNetwork()); - final int subType = combineSubtypeEnabled ? SUBTYPE_COMBINED - : getSubTypeForStateSnapshot(snapshot); + final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL + : getRatTypeForStateSnapshot(snapshot); final NetworkIdentity ident = NetworkIdentity.buildNetworkIdentity(mContext, snapshot, - isDefault, subType); + isDefault, ratType); // Traffic occurring on the base interface is always counted for // both total usage and UID details. @@ -1411,7 +1409,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Copy the identify from IMS one but mark it as metered. NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), - ident.getSubType(), ident.getSubscriberId(), ident.getNetworkId(), + ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(), ident.getRoaming(), true /* metered */, true /* onDefaultNetwork */, ident.getOemManaged()); final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); @@ -1492,11 +1490,11 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * For networks with {@code TRANSPORT_CELLULAR}, get subType that was obtained through + * For networks with {@code TRANSPORT_CELLULAR}, get ratType that was obtained through * {@link PhoneStateListener}. Otherwise, return 0 given that other networks with different * transport types do not actually fill this value. */ - private int getSubTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { + private int getRatTypeForStateSnapshot(@NonNull NetworkStateSnapshot state) { if (!state.getNetworkCapabilities().hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) { return 0; } From 86377eba46902ea42f065f7df020cfd6751eab86 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jan 2022 18:25:03 +0000 Subject: [PATCH 1058/1150] [MS65.1] Add NetworkIdentity#Builder Test: atest NetworkIdentityTest#testBuilder Bug: 204830222 Change-Id: Ifdb6482a54fb1e6999c82647d2710cb833c78d02 --- .../src/android/net/NetworkIdentity.java | 259 ++++++++++++++++-- .../src/android/net/NetworkIdentitySet.java | 12 +- .../server/net/NetworkStatsService.java | 4 +- 3 files changed, 238 insertions(+), 37 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 097b9bea90..9b9d38a360 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -19,8 +19,10 @@ package android.net; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.content.Context; import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; @@ -31,6 +33,8 @@ import android.util.proto.ProtoOutputStream; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.NetworkIdentityUtils; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; @@ -49,6 +53,15 @@ public class NetworkIdentity implements Comparable { // {@link NetworkTemplate#NETWORK_TYPE_ALL} instead. public static final int SUBTYPE_COMBINED = -1; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "OEM_MANAGED_" }, value = { + NetworkTemplate.OEM_MANAGED_NO, + NetworkTemplate.OEM_MANAGED_PAID, + NetworkTemplate.OEM_MANAGED_PRIVATE + }) + public @interface OemManaged{} + /** * Network has no {@code NetworkCapabilities#NET_CAPABILITY_OEM_*}. * @hide @@ -177,42 +190,62 @@ public class NetworkIdentity implements Comparable { proto.end(start); } - /** @hide */ + /** Get the network type of this instance. */ public int getType() { return mType; } - /** @hide */ + /** Get the Radio Access Technology(RAT) type of this instance. */ public int getRatType() { return mRatType; } - /** @hide */ + /** Get the Subscriber Id of this instance. */ + @Nullable public String getSubscriberId() { return mSubscriberId; } - /** @hide */ + /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getCurrentNetworkKey()}. */ + @Nullable public String getWifiNetworkKey() { return mWifiNetworkKey; } /** @hide */ + // TODO: Remove this function after all callers are removed. public boolean getRoaming() { return mRoaming; } + /** Return the roaming status of this instance. */ + public boolean isRoaming() { + return mRoaming; + } + /** @hide */ + // TODO: Remove this function after all callers are removed. public boolean getMetered() { return mMetered; } + /** Return the meteredness of this instance. */ + public boolean isMetered() { + return mMetered; + } + /** @hide */ + // TODO: Remove this function after all callers are removed. public boolean getDefaultNetwork() { return mDefaultNetwork; } - /** @hide */ + /** Return the default network status of this instance. */ + public boolean isDefaultNetwork() { + return mDefaultNetwork; + } + + /** Get the OEM managed type of this instance. */ public int getOemManaged() { return mOemManaged; } @@ -229,36 +262,16 @@ public class NetworkIdentity implements Comparable { * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable. * See {@code TelephonyManager.NETWORK_TYPE_*}. * @hide + * @deprecated See {@link NetworkIdentity#Builder}. */ // TODO: Remove this after all callers are migrated to use new Api. + @Deprecated @NonNull public static NetworkIdentity buildNetworkIdentity(Context context, @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, @Annotation.NetworkType int ratType) { - final int legacyType = snapshot.getLegacyType(); - - final String subscriberId = snapshot.getSubscriberId(); - String wifiNetworkKey = null; - boolean roaming = !snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); - boolean metered = !(snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_NOT_METERED) - || snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED)); - - final int oemManaged = getOemBitfield(snapshot.getNetworkCapabilities()); - - if (legacyType == TYPE_WIFI) { - final TransportInfo transportInfo = snapshot.getNetworkCapabilities() - .getTransportInfo(); - if (transportInfo instanceof WifiInfo) { - final WifiInfo info = (WifiInfo) transportInfo; - wifiNetworkKey = info != null ? info.getCurrentNetworkKey() : null; - } - } - - return new NetworkIdentity(legacyType, ratType, subscriberId, wifiNetworkKey, roaming, - metered, defaultNetwork, oemManaged); + return new NetworkIdentity.Builder().setNetworkStateSnapshot(snapshot) + .setDefaultNetwork(defaultNetwork).setRatType(ratType).build(); } /** @@ -305,4 +318,192 @@ public class NetworkIdentity implements Comparable { } return res; } + + /** + * Builder class for {@link NetworkIdentity}. + */ + public static final class Builder { + private int mType; + private int mRatType; + private String mSubscriberId; + private String mWifiNetworkKey; + private boolean mRoaming; + private boolean mMetered; + private boolean mDefaultNetwork; + private int mOemManaged; + + /** + * Creates a new Builder. + */ + public Builder() { + // Initialize with default values. Will be overwritten by setters. + mType = ConnectivityManager.TYPE_NONE; + mRatType = NetworkTemplate.NETWORK_TYPE_ALL; + mSubscriberId = null; + mWifiNetworkKey = null; + mRoaming = false; + mMetered = false; + mDefaultNetwork = false; + mOemManaged = NetworkTemplate.OEM_MANAGED_NO; + } + + /** + * Add an {@link NetworkStateSnapshot} into the {@link NetworkIdentity} instance. + * This is to read roaming, metered, wifikey... from the snapshot for convenience. + * + * @param snapshot The target {@link NetworkStateSnapshot} object. + * @return The builder object. + */ + @SuppressLint("MissingGetterMatchingBuilder") + @NonNull + public Builder setNetworkStateSnapshot(@NonNull NetworkStateSnapshot snapshot) { + setType(snapshot.getLegacyType()); + + setSubscriberId(snapshot.getSubscriberId()); + setRoaming(!snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)); + setMetered(!(snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_NOT_METERED) + || snapshot.getNetworkCapabilities().hasCapability( + NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED))); + + setOemManaged(getOemBitfield(snapshot.getNetworkCapabilities())); + + if (mType == TYPE_WIFI) { + final TransportInfo transportInfo = snapshot.getNetworkCapabilities() + .getTransportInfo(); + if (transportInfo instanceof WifiInfo) { + final WifiInfo info = (WifiInfo) transportInfo; + if (info != null) { + setWifiNetworkKey(info.getCurrentNetworkKey()); + } + } + } + return this; + } + + /** + * Set the network type of the network. + * + * @param type the network type. See {@link ConnectivityManager#TYPE_*}. + * + * @return this builder. + */ + @NonNull + public Builder setType(int type) { + mType = type; + return this; + } + + /** + * Set the Radio Access Technology(RAT) type of the network. + * + * @param ratType the Radio Access Technology(RAT) type if applicable. See + * {@code TelephonyManager.NETWORK_TYPE_*}. + * + * @return this builder. + */ + @NonNull + public Builder setRatType(@Annotation.NetworkType int ratType) { + mRatType = ratType; + return this; + } + + /** + * Clear the Radio Access Technology(RAT) type of the network. + * + * @return this builder. + */ + @NonNull + public Builder clearRatType() { + mRatType = NetworkTemplate.NETWORK_TYPE_ALL; + return this; + } + + /** + * Set the Subscriber Id. + * + * @param subscriberId the Subscriber Id of the network. Or null if not applicable. + * @return this builder. + */ + @NonNull + public Builder setSubscriberId(@Nullable String subscriberId) { + mSubscriberId = subscriberId; + return this; + } + + /** + * Set the Wifi Network Key. + * + * @param wifiNetworkKey Wifi Network Key of the network, + * see {@link WifiInfo#getCurrentNetworkKey()}. + * Or null if not applicable. + * @return this builder. + */ + @NonNull + public Builder setWifiNetworkKey(@Nullable String wifiNetworkKey) { + mWifiNetworkKey = wifiNetworkKey; + return this; + } + + /** + * Set the roaming. + * + * @param roaming the roaming status of the network. + * @return this builder. + */ + @NonNull + public Builder setRoaming(boolean roaming) { + mRoaming = roaming; + return this; + } + + /** + * Set the meteredness. + * + * @param metered the meteredness of the network. + * @return this builder. + */ + @NonNull + public Builder setMetered(boolean metered) { + mMetered = metered; + return this; + } + + /** + * Set the default network status. + * + * @param defaultNetwork the default network status of the network. + * @return this builder. + */ + @NonNull + public Builder setDefaultNetwork(boolean defaultNetwork) { + mDefaultNetwork = defaultNetwork; + return this; + } + + /** + * Set the OEM managed type. + * + * @param oemManaged Type of OEM managed network or unmanaged networks. + * See {@code NetworkTemplate#OEM_MANAGED_*}. + * @return this builder. + */ + @NonNull + public Builder setOemManaged(@OemManaged int oemManaged) { + mOemManaged = oemManaged; + return this; + } + + /** + * Builds the instance of the {@link NetworkIdentity}. + * + * @return the built instance of {@link NetworkIdentity}. + */ + @NonNull + public NetworkIdentity build() { + return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, + mRoaming, mMetered, mDefaultNetwork, mOemManaged); + } + } } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index c2d8ea1f96..041f070512 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -116,9 +116,9 @@ public class NetworkIdentitySet extends HashSet implements out.writeInt(ident.getRatType()); writeOptionalString(out, ident.getSubscriberId()); writeOptionalString(out, ident.getWifiNetworkKey()); - out.writeBoolean(ident.getRoaming()); - out.writeBoolean(ident.getMetered()); - out.writeBoolean(ident.getDefaultNetwork()); + out.writeBoolean(ident.isRoaming()); + out.writeBoolean(ident.isMetered()); + out.writeBoolean(ident.isDefaultNetwork()); out.writeInt(ident.getOemManaged()); } } @@ -132,7 +132,7 @@ public class NetworkIdentitySet extends HashSet implements return false; } for (NetworkIdentity ident : this) { - if (ident.getMetered()) { + if (ident.isMetered()) { return true; } } @@ -148,7 +148,7 @@ public class NetworkIdentitySet extends HashSet implements return false; } for (NetworkIdentity ident : this) { - if (ident.getRoaming()) { + if (ident.isRoaming()) { return true; } } @@ -165,7 +165,7 @@ public class NetworkIdentitySet extends HashSet implements return true; } for (NetworkIdentity ident : this) { - if (!ident.getDefaultNetwork()) { + if (!ident.isDefaultNetwork()) { return false; } } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 4bb61bd090..577de215d8 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1405,12 +1405,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // VT is considered always metered in framework's layer. If VT is not metered // per carrier's policy, modem will report 0 usage for VT calls. if (snapshot.getNetworkCapabilities().hasCapability( - NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.getMetered()) { + NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { // Copy the identify from IMS one but mark it as metered. NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(), - ident.getRoaming(), true /* metered */, + ident.isRoaming(), true /* metered */, true /* onDefaultNetwork */, ident.getOemManaged()); final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); From 02eb422cb48283b7011424281f9c00c4759e89df Mon Sep 17 00:00:00 2001 From: lifr Date: Wed, 12 Jan 2022 00:54:40 +0800 Subject: [PATCH 1059/1150] [DU03-1]Remove INetworkStatsService from BatteryStatsImpl Expose systemapi NetworkStats.getDetailedUidStats for use by BatteryStats. BatteryStatsImpl is using INetworkStatsService APIs, which cannot be accessed after moving into the mainline module. So, replace and remove those hidden API usages. Bug: 210066922 Test: atest BatteryStatsImplTest WifiPowerCalculatorTest MobileRadioPowerCalculatorTest NetworkStatsServiceTest CTS-Coverage-Bug: 213437796 Change-Id: I40d713923278f4654d67bb4d12155cea85c10447 --- .../app/usage/NetworkStatsManager.java | 52 ++++++++++++++----- .../src/android/net/INetworkStatsService.aidl | 10 +--- .../server/net/NetworkStatsService.java | 25 ++++++++- 3 files changed, 63 insertions(+), 24 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 8d93354ea9..683678ad46 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -17,6 +17,8 @@ package android.app.usage; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.Manifest; import android.annotation.NonNull; @@ -55,7 +57,6 @@ import com.android.net.module.util.NetworkIdentityUtils; import java.util.List; import java.util.Objects; -import java.util.Set; /** * Provides access to network usage history and statistics. Usage data is collected in @@ -670,26 +671,49 @@ public class NetworkStatsManager { } /** - * Query realtime network usage statistics details with interfaces constrains. - * Return snapshot of current UID statistics, including any {@link TrafficStats#UID_TETHERING}, - * video calling data usage and count of network operations that set by - * {@link TrafficStats#incrementOperationCount}. The returned data doesn't include any - * statistics that is reported by {@link NetworkStatsProvider}. + * Query realtime mobile network usage statistics. * - * @param requiredIfaces A list of interfaces the stats should be restricted to, or - * {@link NetworkStats#INTERFACES_ALL}. + * Return a snapshot of current UID network statistics, as it applies + * to the mobile radios of the device. The snapshot will include any + * tethering traffic, video calling data usage and count of + * network operations set by {@link TrafficStats#incrementOperationCount} + * made over a mobile radio. + * The snapshot will not include any statistics that cannot be seen by + * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. * * @hide */ - //@SystemApi + @SystemApi @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) - @NonNull public android.net.NetworkStats getDetailedUidStats( - @NonNull Set requiredIfaces) { - Objects.requireNonNull(requiredIfaces, "requiredIfaces cannot be null"); + @NonNull public android.net.NetworkStats getMobileUidStats() { try { - return mService.getDetailedUidStats(requiredIfaces.toArray(new String[0])); + return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); } catch (RemoteException e) { - if (DBG) Log.d(TAG, "Remote exception when get detailed uid stats"); + if (DBG) Log.d(TAG, "Remote exception when get Mobile uid stats"); + throw e.rethrowFromSystemServer(); + } + } + + /** + * Query realtime Wi-Fi network usage statistics. + * + * Return a snapshot of current UID network statistics, as it applies + * to the Wi-Fi radios of the device. The snapshot will include any + * tethering traffic, video calling data usage and count of + * network operations set by {@link TrafficStats#incrementOperationCount} + * made over a Wi-Fi radio. + * The snapshot will not include any statistics that cannot be seen by + * the kernel, e.g. statistics reported by {@link NetworkStatsProvider}s. + * + * @hide + */ + @SystemApi + @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @NonNull public android.net.NetworkStats getWifiUidStats() { + try { + return mService.getUidStatsForTransport(TRANSPORT_WIFI); + } catch (RemoteException e) { + if (DBG) Log.d(TAG, "Remote exception when get WiFi uid stats"); throw e.rethrowFromSystemServer(); } } diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index a4babb543d..da0aa99b93 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -49,14 +49,8 @@ interface INetworkStatsService { @UnsupportedAppUsage NetworkStats getDataLayerSnapshotForUid(int uid); - /** Get a detailed snapshot of stats since boot for all UIDs. - * - *

            Results will not always be limited to stats on requiredIfaces when specified: stats for - * interfaces stacked on the specified interfaces, or for interfaces on which the specified - * interfaces are stacked on, will also be included. - * @param requiredIfaces Interface names to get data for, or {@link NetworkStats#INTERFACES_ALL}. - */ - NetworkStats getDetailedUidStats(in String[] requiredIfaces); + /** Get the transport NetworkStats for all UIDs since boot. */ + NetworkStats getUidStatsForTransport(int transport); /** Return set of any ifaces associated with mobile networks since boot. */ @UnsupportedAppUsage diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 8e15f799c3..192c5c1297 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -28,6 +28,7 @@ import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; import static android.content.Intent.EXTRA_UID; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.net.NetworkStats.DEFAULT_NETWORK_ALL; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.IFACE_VT; @@ -291,6 +292,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** Set of any ifaces associated with mobile networks since boot. */ private volatile String[] mMobileIfaces = new String[0]; + /** Set of any ifaces associated with wifi networks since boot. */ + private volatile String[] mWifiIfaces = new String[0]; + /** Set of all ifaces currently used by traffic that does not explicitly specify a Network. */ @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; @@ -1005,11 +1009,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public NetworkStats getDetailedUidStats(String[] requiredIfaces) { + public NetworkStats getUidStatsForTransport(int transport) { enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); try { + final String[] relevantIfaces = + transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; + // TODO(b/215633405) : mMobileIfaces and mWifiIfaces already contain the stacked + // interfaces, so this is not useful, remove it. final String[] ifacesToQuery = - mStatsFactory.augmentWithStackedInterfaces(requiredIfaces); + mStatsFactory.augmentWithStackedInterfaces(relevantIfaces); return getNetworkStatsUidDetail(ifacesToQuery); } catch (RemoteException e) { Log.wtf(TAG, "Error compiling UID stats", e); @@ -1368,10 +1376,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final boolean combineSubtypeEnabled = mSettings.getCombineSubtypeEnabled(); final ArraySet mobileIfaces = new ArraySet<>(); + final ArraySet wifiIfaces = new ArraySet<>(); for (NetworkStateSnapshot snapshot : snapshots) { final int displayTransport = getDisplayTransport(snapshot.getNetworkCapabilities().getTransportTypes()); final boolean isMobile = (NetworkCapabilities.TRANSPORT_CELLULAR == displayTransport); + final boolean isWifi = (NetworkCapabilities.TRANSPORT_WIFI == displayTransport); final boolean isDefault = CollectionUtils.contains( mDefaultNetworks, snapshot.getNetwork()); final int ratType = combineSubtypeEnabled ? NetworkTemplate.NETWORK_TYPE_ALL @@ -1407,6 +1417,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (isMobile) { mobileIfaces.add(baseIface); } + if (isWifi) { + wifiIfaces.add(baseIface); + } } // Traffic occurring on stacked interfaces is usually clatd. @@ -1448,6 +1461,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { if (isMobile) { mobileIfaces.add(iface); } + if (isWifi) { + wifiIfaces.add(iface); + } mStatsFactory.noteStackedIface(iface, baseIface); } @@ -1455,11 +1471,16 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } mMobileIfaces = mobileIfaces.toArray(new String[0]); + mWifiIfaces = wifiIfaces.toArray(new String[0]); // TODO (b/192758557): Remove debug log. if (CollectionUtils.contains(mMobileIfaces, null)) { throw new NullPointerException( "null element in mMobileIfaces: " + Arrays.toString(mMobileIfaces)); } + if (CollectionUtils.contains(mWifiIfaces, null)) { + throw new NullPointerException( + "null element in mWifiIfaces: " + Arrays.toString(mWifiIfaces)); + } } private static int getSubIdForMobile(@NonNull NetworkStateSnapshot state) { From 9703eb291cd736ae5a119b1898436ba92fad5d6b Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 14 Jan 2022 22:20:03 +0800 Subject: [PATCH 1060/1150] Replace INetd#trafficSwapActiveStatsMap with ConnectivityManager API INetd#trafficSwapActiveStatsMap is deprecated and the implementaion is moved into tethering (connectivity) mainline module. A new ConnectivityManager API swapActiveStatsMap is temprary exposed for NetworkStatsFactory. Once NetworkStatsFactory move into tethering module, swapActiveStatsMap API would be removed and NetworkStatsFactory should could call the implemeneted inside the module directly. This should happen before T sdk finalization. Bug: 209935649 Test: atest NetworkStatsFactoryTest Change-Id: I6685fe513511e7af9fa6521601891c66d1297da0 --- .../server/net/NetworkStatsFactory.java | 23 ++++++++++--------- .../server/net/NetworkStatsService.java | 15 +++++++++--- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index bb123a38eb..17f3455d20 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -26,10 +26,10 @@ import static com.android.server.NetworkManagementSocketTagger.kernelToTag; import android.annotation.NonNull; import android.annotation.Nullable; -import android.net.INetd; +import android.content.Context; +import android.net.ConnectivityManager; import android.net.NetworkStats; import android.net.UnderlyingNetworkInfo; -import android.os.RemoteException; import android.os.StrictMode; import android.os.SystemClock; @@ -70,7 +70,7 @@ public class NetworkStatsFactory { private final boolean mUseBpfStats; - private final INetd mNetd; + private final Context mContext; /** * Guards persistent data access in this class @@ -158,12 +158,12 @@ public class NetworkStatsFactory { NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } - public NetworkStatsFactory(@NonNull INetd netd) { - this(new File("/proc/"), true, netd); + public NetworkStatsFactory(@NonNull Context ctx) { + this(ctx, new File("/proc/"), true); } @VisibleForTesting - public NetworkStatsFactory(File procRoot, boolean useBpfStats, @NonNull INetd netd) { + public NetworkStatsFactory(@NonNull Context ctx, File procRoot, boolean useBpfStats) { mStatsXtIfaceAll = new File(procRoot, "net/xt_qtaguid/iface_stat_all"); mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); @@ -172,7 +172,7 @@ public class NetworkStatsFactory { mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); } - mNetd = netd; + mContext = ctx; } public NetworkStats readBpfNetworkStatsDev() throws IOException { @@ -295,11 +295,12 @@ public class NetworkStatsFactory { } @GuardedBy("mPersistentDataLock") - private void requestSwapActiveStatsMapLocked() throws RemoteException { - // Ask netd to do a active map stats swap. When the binder call successfully returns, + private void requestSwapActiveStatsMapLocked() { + // Do a active map stats swap. When the binder call successfully returns, // the system server should be able to safely read and clean the inactive map // without race problem. - mNetd.trafficSwapActiveStatsMap(); + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.swapActiveStatsMap(); } /** @@ -327,7 +328,7 @@ public class NetworkStatsFactory { if (mUseBpfStats) { try { requestSwapActiveStatsMapLocked(); - } catch (RemoteException e) { + } catch (RuntimeException e) { throw new IOException(e); } // Stats are always read from the inactive map, so they must be read after the diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index d0db938837..815fc592f9 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -418,7 +418,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { final NetworkStatsService service = new NetworkStatsService(context, INetd.Stub.asInterface((IBinder) context.getSystemService(Context.NETD_SERVICE)), alarmManager, wakeLock, getDefaultClock(), - new DefaultNetworkStatsSettings(), new NetworkStatsFactory(netd), + new DefaultNetworkStatsSettings(), new NetworkStatsFactory(context), new NetworkStatsObservers(), getDefaultSystemDir(), getDefaultBaseDir(), new Dependencies()); @@ -987,8 +987,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // TODO: switch to data layer stats once kernel exports - // for now, read network layer stats and flatten across all ifaces - final NetworkStats networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); + // for now, read network layer stats and flatten across all ifaces. + // This function is used to query NeworkStats for calle's uid. The only caller method + // TrafficStats#getDataLayerSnapshotForUid alrady claim no special permission to query + // its own NetworkStats. + final long ident = Binder.clearCallingIdentity(); + final NetworkStats networkLayer; + try { + networkLayer = readNetworkStatsUidDetail(uid, INTERFACES_ALL, TAG_ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } // splice in operation counts networkLayer.spliceOperationsFrom(mUidOperations); From 909741d0c23df302fffe5d98acc5bd183159c896 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Thu, 20 Jan 2022 11:06:46 +0800 Subject: [PATCH 1061/1150] wifi data usage: Update calling API name Bug: 213387087 Test: atest -c FrameworksWifiApiTests Test: atest -c NetworkPolicyManagerServiceTest Change-Id: I02d7f57de1acfd7b03be0a3e1c957ec1e1c5b4d4 Ignore-AOSP-First: Related API conflict in wifi module, need master first. --- framework-t/src/android/net/NetworkIdentity.java | 6 +++--- framework-t/src/android/net/NetworkTemplate.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 9b9d38a360..a62aa519a9 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -206,7 +206,7 @@ public class NetworkIdentity implements Comparable { return mSubscriberId; } - /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getCurrentNetworkKey()}. */ + /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getNetworkKey()}. */ @Nullable public String getWifiNetworkKey() { return mWifiNetworkKey; @@ -375,7 +375,7 @@ public class NetworkIdentity implements Comparable { if (transportInfo instanceof WifiInfo) { final WifiInfo info = (WifiInfo) transportInfo; if (info != null) { - setWifiNetworkKey(info.getCurrentNetworkKey()); + setWifiNetworkKey(info.getNetworkKey()); } } } @@ -436,7 +436,7 @@ public class NetworkIdentity implements Comparable { * Set the Wifi Network Key. * * @param wifiNetworkKey Wifi Network Key of the network, - * see {@link WifiInfo#getCurrentNetworkKey()}. + * see {@link WifiInfo#getNetworkKey()}. * Or null if not applicable. * @return this builder. */ diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index a7e48d4363..cad80752b8 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -263,7 +263,7 @@ public final class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given key of the wifi network. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. * @hide */ @@ -283,7 +283,7 @@ public final class NetworkTemplate implements Parcelable { * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless * of key of the wifi network. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. * @param subscriberId the IMSI associated to this wifi network. * @@ -593,7 +593,7 @@ public final class NetworkTemplate implements Parcelable { /** * Get the set of Wifi Network Keys of the template. - * See {@link WifiInfo#getCurrentNetworkKey()}. + * See {@link WifiInfo#getNetworkKey()}. */ @NonNull public Set getWifiNetworkKeys() { @@ -729,7 +729,7 @@ public final class NetworkTemplate implements Parcelable { * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is * empty. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. */ private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { @@ -1059,9 +1059,9 @@ public final class NetworkTemplate implements Parcelable { * the intention of matching any Wifi Network Key. * * @param wifiNetworkKeys the list of Wifi Network Key, - * see {@link WifiInfo#getCurrentNetworkKey()}. + * see {@link WifiInfo#getNetworkKey()}. * Or an empty list to match all networks. - * Note that {@code getCurrentNetworkKey()} might get null key + * Note that {@code getNetworkKey()} might get null key * when wifi disconnects. However, the caller should never invoke * this function with a null Wifi Network Key since such statistics * never exists. From debfc4015b2105b03b2cbb65be1aef7bcbb4aea8 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 18 Jan 2022 18:26:28 +0800 Subject: [PATCH 1062/1150] Monitor interface added and update bpf interface map Have BpfInterfaceMapUpdater to update bpf interface map: adding the interface and index mapping to bpf interface map when interface added. Bug: 215095957 Test: atest FrameworkNetTests Change-Id: I2189a50c4869cfc0c33fc6f0228f40ee9f3ac1d4 --- service-t/Sources.bp | 27 ++++ service-t/jni/onload.cpp | 38 +++++ .../server/net/BpfInterfaceMapUpdater.java | 139 ++++++++++++++++++ .../android/server/net/InterfaceMapValue.java | 35 +++++ .../server/net/NetworkStatsService.java | 12 ++ 5 files changed, 251 insertions(+) create mode 100644 service-t/jni/onload.cpp create mode 100644 service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java create mode 100644 service-t/src/com/android/server/net/InterfaceMapValue.java diff --git a/service-t/Sources.bp b/service-t/Sources.bp index b261e165a1..3fd3d8caab 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -26,6 +26,8 @@ filegroup { srcs: [ "src/com/android/server/net/NetworkIdentity*.java", "src/com/android/server/net/NetworkStats*.java", + "src/com/android/server/net/BpfInterfaceMapUpdater.java", + "src/com/android/server/net/InterfaceMapValue.java", ], path: "src", visibility: [ @@ -97,3 +99,28 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } + +cc_library_shared { + name: "libcom_android_net_module_util_jni", + min_sdk_version: "30", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + "-Wthread-safety", + ], + srcs: [ + "jni/onload.cpp", + ], + stl: "libc++_static", + static_libs: [ + "libnet_utils_device_common_bpfjni", + ], + shared_libs: [ + "liblog", + "libnativehelper", + ], + apex_available: [ + "//apex_available:platform", + ], +} diff --git a/service-t/jni/onload.cpp b/service-t/jni/onload.cpp new file mode 100644 index 0000000000..bca4697560 --- /dev/null +++ b/service-t/jni/onload.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +namespace android { + +int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + ALOGE("GetEnv failed"); + return JNI_ERR; + } + + if (register_com_android_net_module_util_BpfMap(env, + "com/android/net/module/util/BpfMap") < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} + +}; + diff --git a/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java b/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java new file mode 100644 index 0000000000..25c88eb6bd --- /dev/null +++ b/service-t/src/com/android/server/net/BpfInterfaceMapUpdater.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.net; + +import android.content.Context; +import android.net.INetd; +import android.os.Handler; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.system.ErrnoException; +import android.util.Log; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.net.module.util.BaseNetdUnsolicitedEventListener; +import com.android.net.module.util.BpfMap; +import com.android.net.module.util.IBpfMap; +import com.android.net.module.util.InterfaceParams; +import com.android.net.module.util.Struct.U32; + +/** + * Monitor interface added (without removed) and right interface name and its index to bpf map. + */ +public class BpfInterfaceMapUpdater { + private static final String TAG = BpfInterfaceMapUpdater.class.getSimpleName(); + // This is current path but may be changed soon. + private static final String IFACE_INDEX_NAME_MAP_PATH = + "/sys/fs/bpf/map_netd_iface_index_name_map"; + private final IBpfMap mBpfMap; + private final INetd mNetd; + private final Handler mHandler; + private final Dependencies mDeps; + + public BpfInterfaceMapUpdater(Context ctx, Handler handler) { + this(ctx, handler, new Dependencies()); + } + + @VisibleForTesting + public BpfInterfaceMapUpdater(Context ctx, Handler handler, Dependencies deps) { + mDeps = deps; + mBpfMap = deps.getInterfaceMap(); + mNetd = deps.getINetd(ctx); + mHandler = handler; + } + + /** + * Dependencies of BpfInerfaceMapUpdater, for injection in tests. + */ + @VisibleForTesting + public static class Dependencies { + /** Create BpfMap for updating interface and index mapping. */ + public IBpfMap getInterfaceMap() { + try { + return new BpfMap<>(IFACE_INDEX_NAME_MAP_PATH, BpfMap.BPF_F_RDWR, + U32.class, InterfaceMapValue.class); + } catch (ErrnoException e) { + Log.e(TAG, "Cannot create interface map: " + e); + return null; + } + } + + /** Get InterfaceParams for giving interface name. */ + public InterfaceParams getInterfaceParams(String ifaceName) { + return InterfaceParams.getByName(ifaceName); + } + + /** Get INetd binder object. */ + public INetd getINetd(Context ctx) { + return INetd.Stub.asInterface((IBinder) ctx.getSystemService(Context.NETD_SERVICE)); + } + } + + /** + * Start listening interface update event. + * Query current interface names before listening. + */ + public void start() { + mHandler.post(() -> { + if (mBpfMap == null) { + Log.wtf(TAG, "Fail to start: Null bpf map"); + return; + } + + try { + // TODO: use a NetlinkMonitor and listen for RTM_NEWLINK messages instead. + mNetd.registerUnsolicitedEventListener(new InterfaceChangeObserver()); + } catch (RemoteException e) { + Log.wtf(TAG, "Unable to register netd UnsolicitedEventListener, " + e); + } + + final String[] ifaces; + try { + // TODO: use a netlink dump to get the current interface list. + ifaces = mNetd.interfaceGetList(); + } catch (RemoteException | ServiceSpecificException e) { + Log.wtf(TAG, "Unable to query interface names by netd, " + e); + return; + } + + for (String ifaceName : ifaces) { + addInterface(ifaceName); + } + }); + } + + private void addInterface(String ifaceName) { + final InterfaceParams iface = mDeps.getInterfaceParams(ifaceName); + if (iface == null) { + Log.e(TAG, "Unable to get InterfaceParams for " + ifaceName); + return; + } + + try { + mBpfMap.updateEntry(new U32(iface.index), new InterfaceMapValue(ifaceName)); + } catch (ErrnoException e) { + Log.e(TAG, "Unable to update entry for " + ifaceName + ", " + e); + } + } + + private class InterfaceChangeObserver extends BaseNetdUnsolicitedEventListener { + @Override + public void onInterfaceAdded(String ifName) { + mHandler.post(() -> addInterface(ifName)); + } + } +} diff --git a/service-t/src/com/android/server/net/InterfaceMapValue.java b/service-t/src/com/android/server/net/InterfaceMapValue.java new file mode 100644 index 0000000000..061f323447 --- /dev/null +++ b/service-t/src/com/android/server/net/InterfaceMapValue.java @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * The value of bpf interface index map which is used for NetworkStatsService. + */ +public class InterfaceMapValue extends Struct { + @Field(order = 0, type = Type.ByteArray, arraysize = 16) + public final byte[] interfaceName; + + public InterfaceMapValue(String iface) { + final byte[] ifaceArray = iface.getBytes(); + interfaceName = new byte[16]; + // All array bytes after the interface name, if any, must be 0. + System.arraycopy(ifaceArray, 0, interfaceName, 0, ifaceArray.length); + } +} diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index d0db938837..ad15c3c0c2 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -356,6 +356,9 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull private final LocationPermissionChecker mLocationPermissionChecker; + @NonNull + private final BpfInterfaceMapUpdater mInterfaceMapUpdater; + private static @NonNull File getDefaultSystemDir() { return new File(Environment.getDataDirectory(), "system"); } @@ -453,6 +456,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); + mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); + mInterfaceMapUpdater.start(); } /** @@ -507,6 +512,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public LocationPermissionChecker makeLocationPermissionChecker(final Context context) { return new LocationPermissionChecker(context); } + + /** Create BpfInterfaceMapUpdater to update bpf interface map. */ + @NonNull + public BpfInterfaceMapUpdater makeBpfInterfaceMapUpdater( + @NonNull Context ctx, @NonNull Handler handler) { + return new BpfInterfaceMapUpdater(ctx, handler); + } } /** From 6f39e805a1c82ae6c32bde6d750544e620a55b21 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 19 Jan 2022 08:33:21 +0000 Subject: [PATCH 1063/1150] [MS66] Initialize TrafficStats with context MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TrafficStats has static methods created in API level 8 that need access to NetworkStatsManager but doesn't take a context. Previously this was achieved by using ServiceManager, but with TrafficStats moving to the connectivity module, this is no longer possible. Instead, make sure TrafficStats has an appropriate context by the time any client code can call the relevant methods. • In app code, this achieved by passing the application context from ActivityThread#handleBindApplication, before any app code can run. • In the system server, this is achieved by passing the context right after creating service. Test: atest TrafficStatsTest CtsWebkitTestCases Bug: 204830222 Change-Id: I251bb8a4431ad12ff61929879ef1363cf06b9244 --- .../app/usage/NetworkStatsManager.java | 5 +++ framework-t/src/android/net/TrafficStats.java | 42 ++++++++++--------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 683678ad46..8813f98451 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -157,6 +157,11 @@ public class NetworkStatsManager { setAugmentWithSubscriptionPlan(true); } + /** @hide */ + public INetworkStatsService getBinder() { + return mService; + } + /** * Set poll on open flag to indicate the poll is needed before service gets statistics * result. This is default enabled. However, for any non-privileged caller, the poll might diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index 1af32bf552..c803a723ba 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -17,7 +17,6 @@ package android.net; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.annotation.TestApi; @@ -27,8 +26,8 @@ import android.app.usage.NetworkStatsManager; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.media.MediaPlayer; +import android.os.Binder; import android.os.Build; -import android.os.IBinder; import android.os.RemoteException; import com.android.server.NetworkManagementSocketTagger; @@ -37,8 +36,6 @@ import dalvik.system.SocketTagger; import java.io.FileDescriptor; import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.net.DatagramSocket; import java.net.Socket; import java.net.SocketException; @@ -177,25 +174,12 @@ public class TrafficStats { @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 130143562) private synchronized static INetworkStatsService getStatsService() { if (sStatsService == null) { - sStatsService = getStatsBinder(); + throw new IllegalStateException("TrafficStats not initialized, uid=" + + Binder.getCallingUid()); } return sStatsService; } - @Nullable - private static INetworkStatsService getStatsBinder() { - try { - final Method getServiceMethod = Class.forName("android.os.ServiceManager") - .getDeclaredMethod("getService", new Class[]{String.class}); - final IBinder binder = (IBinder) getServiceMethod.invoke( - null, Context.NETWORK_STATS_SERVICE); - return INetworkStatsService.Stub.asInterface(binder); - } catch (NoSuchMethodException | ClassNotFoundException | IllegalAccessException - | InvocationTargetException e) { - throw new NullPointerException("Cannot get INetworkStatsService: " + e); - } - } - /** * Snapshot of {@link NetworkStats} when the currently active profiling * session started, or {@code null} if no session active. @@ -209,6 +193,26 @@ public class TrafficStats { private static final String LOOPBACK_IFACE = "lo"; + /** + * Initialization {@link TrafficStats} with the context, to + * allow {@link TrafficStats} to fetch the needed binder. + * + * @param context a long-lived context, such as the application context or system + * server context. + * @hide + */ + @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SuppressLint("VisiblySynchronized") + public static synchronized void init(@NonNull final Context context) { + if (sStatsService != null) { + throw new IllegalStateException("TrafficStats is already initialized, uid=" + + Binder.getCallingUid()); + } + final NetworkStatsManager statsManager = + context.getSystemService(NetworkStatsManager.class); + sStatsService = statsManager.getBinder(); + } + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. From 8efe3482f33d9df358c087a2f8fb9a1d5f0b09e4 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 17 Jan 2022 17:05:30 +0000 Subject: [PATCH 1064/1150] [MS61] Remove NetworkManagementSocketTagger#install dependency Expose TrafficStats#attachSocketTagger and use it instead. Test: atest TrafficStatsTest Bug: 204830222 CTS-Coverage-Bug: 214979748 Change-Id: I1748d349b499053ad08bd62202325fa759ad8da5 --- framework-t/src/android/net/TrafficStats.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index c803a723ba..77b7f16671 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -16,6 +16,8 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.NonNull; import android.annotation.SuppressLint; import android.annotation.SystemApi; @@ -213,6 +215,18 @@ public class TrafficStats { sStatsService = statsManager.getBinder(); } + /** + * Attach the socket tagger implementation to the current process, to + * get notified when a socket's {@link FileDescriptor} is assigned to + * a thread. See {@link SocketTagger#set(SocketTagger)}. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static void attachSocketTagger() { + NetworkManagementSocketTagger.install(); + } + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. From 103f53789d6054087b2644cb6bf7f740d3c01aa3 Mon Sep 17 00:00:00 2001 From: Les Lee Date: Thu, 20 Jan 2022 11:06:46 +0800 Subject: [PATCH 1065/1150] wifi data usage: Update calling API name Bug: 213387087 Test: atest -c FrameworksWifiApiTests Test: atest -c NetworkPolicyManagerServiceTest Merged-In: I02d7f57de1acfd7b03be0a3e1c957ec1e1c5b4d4 Change-Id: I02d7f57de1acfd7b03be0a3e1c957ec1e1c5b4d4 --- framework-t/src/android/net/NetworkIdentity.java | 6 +++--- framework-t/src/android/net/NetworkTemplate.java | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 9b9d38a360..a62aa519a9 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -206,7 +206,7 @@ public class NetworkIdentity implements Comparable { return mSubscriberId; } - /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getCurrentNetworkKey()}. */ + /** Get the Wifi Network Key of this instance. See {@link WifiInfo#getNetworkKey()}. */ @Nullable public String getWifiNetworkKey() { return mWifiNetworkKey; @@ -375,7 +375,7 @@ public class NetworkIdentity implements Comparable { if (transportInfo instanceof WifiInfo) { final WifiInfo info = (WifiInfo) transportInfo; if (info != null) { - setWifiNetworkKey(info.getCurrentNetworkKey()); + setWifiNetworkKey(info.getNetworkKey()); } } } @@ -436,7 +436,7 @@ public class NetworkIdentity implements Comparable { * Set the Wifi Network Key. * * @param wifiNetworkKey Wifi Network Key of the network, - * see {@link WifiInfo#getCurrentNetworkKey()}. + * see {@link WifiInfo#getNetworkKey()}. * Or null if not applicable. * @return this builder. */ diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index a7e48d4363..cad80752b8 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -263,7 +263,7 @@ public final class NetworkTemplate implements Parcelable { * Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the * given key of the wifi network. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. * @hide */ @@ -283,7 +283,7 @@ public final class NetworkTemplate implements Parcelable { * Call with {@link #WIFI_NETWORK_KEY_ALL} for {@code wifiNetworkKey} to get result regardless * of key of the wifi network. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. * @param subscriberId the IMSI associated to this wifi network. * @@ -593,7 +593,7 @@ public final class NetworkTemplate implements Parcelable { /** * Get the set of Wifi Network Keys of the template. - * See {@link WifiInfo#getCurrentNetworkKey()}. + * See {@link WifiInfo#getNetworkKey()}. */ @NonNull public Set getWifiNetworkKeys() { @@ -729,7 +729,7 @@ public final class NetworkTemplate implements Parcelable { * Returns true when the key matches, or when {@code mMatchWifiNetworkKeys} is * empty. * - * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getCurrentNetworkKey()} + * @param wifiNetworkKey key of the wifi network. see {@link WifiInfo#getNetworkKey()} * to know details about the key. */ private boolean matchesWifiNetworkKey(@NonNull String wifiNetworkKey) { @@ -1059,9 +1059,9 @@ public final class NetworkTemplate implements Parcelable { * the intention of matching any Wifi Network Key. * * @param wifiNetworkKeys the list of Wifi Network Key, - * see {@link WifiInfo#getCurrentNetworkKey()}. + * see {@link WifiInfo#getNetworkKey()}. * Or an empty list to match all networks. - * Note that {@code getCurrentNetworkKey()} might get null key + * Note that {@code getNetworkKey()} might get null key * when wifi disconnects. However, the caller should never invoke * this function with a null Wifi Network Key since such statistics * never exists. From 4489b71b9a158630cba9478301cc366bdb7c9f22 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Fri, 21 Jan 2022 12:41:45 +0000 Subject: [PATCH 1066/1150] [MS65.3] Address comments at aosp/1954383 This change also remove dependencies from NetworkPolicyManagerService. Test: atest NetworkIdentityTest#testBuilder \ NetworkPolicyManagerServiceTest Bug: 204830222 Change-Id: Ib1ec1968746d88165cbf5421d4ba30a00f4b678f --- .../src/android/net/NetworkIdentity.java | 69 +++++++++++++++---- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index a62aa519a9..ae0e8aa02e 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -16,6 +16,7 @@ package android.net; +import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; @@ -30,6 +31,7 @@ import android.telephony.Annotation; import android.telephony.TelephonyManager; import android.util.proto.ProtoOutputStream; +import com.android.net.module.util.CollectionUtils; import com.android.net.module.util.NetworkCapabilitiesUtils; import com.android.net.module.util.NetworkIdentityUtils; @@ -55,7 +57,7 @@ public class NetworkIdentity implements Comparable { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "OEM_MANAGED_" }, value = { + @IntDef(prefix = { "OEM_MANAGED_" }, flag = true, value = { NetworkTemplate.OEM_MANAGED_NO, NetworkTemplate.OEM_MANAGED_PAID, NetworkTemplate.OEM_MANAGED_PRIVATE @@ -71,12 +73,14 @@ public class NetworkIdentity implements Comparable { * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PAID}. * @hide */ - public static final int OEM_PAID = 0x1; + public static final int OEM_PAID = 1 << 0; /** * Network has {@link NetworkCapabilities#NET_CAPABILITY_OEM_PRIVATE}. * @hide */ - public static final int OEM_PRIVATE = 0x2; + public static final int OEM_PRIVATE = 1 << 1; + + private static final long SUPPORTED_OEM_MANAGED_TYPES = OEM_PAID | OEM_PRIVATE; final int mType; final int mRatType; @@ -218,7 +222,7 @@ public class NetworkIdentity implements Comparable { return mRoaming; } - /** Return the roaming status of this instance. */ + /** Return whether this network is roaming. */ public boolean isRoaming() { return mRoaming; } @@ -229,7 +233,7 @@ public class NetworkIdentity implements Comparable { return mMetered; } - /** Return the meteredness of this instance. */ + /** Return whether this network is metered. */ public boolean isMetered() { return mMetered; } @@ -240,7 +244,7 @@ public class NetworkIdentity implements Comparable { return mDefaultNetwork; } - /** Return the default network status of this instance. */ + /** Return whether this network is the default network. */ public boolean isDefaultNetwork() { return mDefaultNetwork; } @@ -262,7 +266,7 @@ public class NetworkIdentity implements Comparable { * {@link TelephonyManager#NETWORK_TYPE_UNKNOWN} if not applicable. * See {@code TelephonyManager.NETWORK_TYPE_*}. * @hide - * @deprecated See {@link NetworkIdentity#Builder}. + * @deprecated See {@link NetworkIdentity.Builder}. */ // TODO: Remove this after all callers are migrated to use new Api. @Deprecated @@ -270,8 +274,12 @@ public class NetworkIdentity implements Comparable { public static NetworkIdentity buildNetworkIdentity(Context context, @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, @Annotation.NetworkType int ratType) { - return new NetworkIdentity.Builder().setNetworkStateSnapshot(snapshot) - .setDefaultNetwork(defaultNetwork).setRatType(ratType).build(); + final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() + .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork); + if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { + builder.setRatType(ratType); + } + return builder.build(); } /** @@ -323,6 +331,11 @@ public class NetworkIdentity implements Comparable { * Builder class for {@link NetworkIdentity}. */ public static final class Builder { + // Need to be synchronized with ConnectivityManager. + // TODO: Use {@link ConnectivityManager#MAX_NETWORK_TYPE} when this file is in the module. + private static final int MAX_NETWORK_TYPE = 18; // TYPE_TEST + private static final int MIN_NETWORK_TYPE = TYPE_MOBILE; + private int mType; private int mRatType; private String mSubscriberId; @@ -374,9 +387,7 @@ public class NetworkIdentity implements Comparable { .getTransportInfo(); if (transportInfo instanceof WifiInfo) { final WifiInfo info = (WifiInfo) transportInfo; - if (info != null) { - setWifiNetworkKey(info.getNetworkKey()); - } + setWifiNetworkKey(info.getNetworkKey()); } } return this; @@ -391,6 +402,12 @@ public class NetworkIdentity implements Comparable { */ @NonNull public Builder setType(int type) { + // Include TYPE_NONE for compatibility, type field might not be filled by some + // networks such as test networks. + if ((type < MIN_NETWORK_TYPE || MAX_NETWORK_TYPE < type) + && type != ConnectivityManager.TYPE_NONE) { + throw new IllegalArgumentException("Invalid network type: " + type); + } mType = type; return this; } @@ -405,6 +422,10 @@ public class NetworkIdentity implements Comparable { */ @NonNull public Builder setRatType(@Annotation.NetworkType int ratType) { + if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) + && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + throw new IllegalArgumentException("Invalid ratType " + ratType); + } mRatType = ratType; return this; } @@ -447,7 +468,7 @@ public class NetworkIdentity implements Comparable { } /** - * Set the roaming. + * Set whether this network is roaming. * * @param roaming the roaming status of the network. * @return this builder. @@ -459,7 +480,7 @@ public class NetworkIdentity implements Comparable { } /** - * Set the meteredness. + * Set whether this network is metered. * * @param metered the meteredness of the network. * @return this builder. @@ -471,7 +492,7 @@ public class NetworkIdentity implements Comparable { } /** - * Set the default network status. + * Set whether this network is the default network. * * @param defaultNetwork the default network status of the network. * @return this builder. @@ -491,10 +512,27 @@ public class NetworkIdentity implements Comparable { */ @NonNull public Builder setOemManaged(@OemManaged int oemManaged) { + // Assert input does not contain illegal oemManage bits. + if ((~SUPPORTED_OEM_MANAGED_TYPES & oemManaged) != 0) { + throw new IllegalArgumentException("Invalid value for OemManaged : " + oemManaged); + } mOemManaged = oemManaged; return this; } + private void ensureValidParameters() { + // Assert non-mobile network cannot have a ratType. + if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { + throw new IllegalArgumentException( + "Invalid ratType " + mRatType + " for type " + mType); + } + + // Assert non-wifi network cannot have a wifi network key. + if (mType != TYPE_WIFI && mWifiNetworkKey != null) { + throw new IllegalArgumentException("Invalid wifi network key for type " + mType); + } + } + /** * Builds the instance of the {@link NetworkIdentity}. * @@ -502,6 +540,7 @@ public class NetworkIdentity implements Comparable { */ @NonNull public NetworkIdentity build() { + ensureValidParameters(); return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, mDefaultNetwork, mOemManaged); } From c0d66230eaccf03561ecf85fd2816c1b8b8305e7 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Sun, 16 Jan 2022 16:43:39 +0000 Subject: [PATCH 1067/1150] [MS56.1] Add NetworkStatsHistory#Builder NetworkStatsHistory will need to be exposed and constructed from the data migration tool in the follow-up changes. Add a Builder class to prevent from exposing internal array structures. Test: atest NetworkStatsHistoryTest#testBuilder Bug: 204830222 Change-Id: I5f8ea1c825d601de0aac8623034ef896999fc1a0 --- .../src/android/net/NetworkStatsHistory.java | 230 +++++++++++++++++- 1 file changed, 229 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 90054c683d..a09b3bb7db 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -51,7 +51,9 @@ import java.io.DataOutput; import java.io.IOException; import java.io.PrintWriter; import java.net.ProtocolException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.Random; /** @@ -97,23 +99,157 @@ public final class NetworkStatsHistory implements Parcelable { private long[] operations; private long totalBytes; - public static class Entry { + /** @hide */ + public NetworkStatsHistory(long bucketDuration, long[] bucketStart, long[] activeTime, + long[] rxBytes, long[] rxPackets, long[] txBytes, long[] txPackets, + long[] operations, int bucketCount, long totalBytes) { + this.bucketDuration = bucketDuration; + this.bucketStart = bucketStart; + this.activeTime = activeTime; + this.rxBytes = rxBytes; + this.rxPackets = rxPackets; + this.txBytes = txBytes; + this.txPackets = txPackets; + this.operations = operations; + this.bucketCount = bucketCount; + this.totalBytes = totalBytes; + } + + /** + * An instance to represent a single record in a {@link NetworkStatsHistory} object. + */ + public static final class Entry { + /** @hide */ public static final long UNKNOWN = -1; + /** @hide */ + // TODO: Migrate all callers to get duration from the history object and remove this field. @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketDuration; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long bucketStart; + /** @hide */ public long activeTime; + /** @hide */ @UnsupportedAppUsage public long rxBytes; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long rxPackets; + /** @hide */ @UnsupportedAppUsage public long txBytes; + /** @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public long txPackets; + /** @hide */ public long operations; + /** @hide */ + Entry() {} + + /** + * Construct a {@link Entry} instance to represent a single record in a + * {@link NetworkStatsHistory} object. + * + * @param bucketStart Start of period for this {@link Entry}, in milliseconds since the + * Unix epoch, see {@link java.lang.System#currentTimeMillis}. + * @param activeTime Active time for this {@link Entry}, in milliseconds. + * @param rxBytes Number of bytes received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param rxPackets Number of packets received for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txBytes Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param txPackets Number of bytes transmitted for this {@link Entry}. Statistics should + * represent the contents of IP packets, including IP headers. + * @param operations count of network operations performed for this {@link Entry}. This can + * be used to derive bytes-per-operation. + */ + public Entry(long bucketStart, long activeTime, long rxBytes, + long rxPackets, long txBytes, long txPackets, long operations) { + this.bucketStart = bucketStart; + this.activeTime = activeTime; + this.rxBytes = rxBytes; + this.rxPackets = rxPackets; + this.txBytes = txBytes; + this.txPackets = txPackets; + this.operations = operations; + } + + /** + * Get start timestamp of the bucket's time interval, in milliseconds since the Unix epoch. + */ + public long getBucketStart() { + return bucketStart; + } + + /** + * Get active time of the bucket's time interval, in milliseconds. + */ + public long getActiveTime() { + return activeTime; + } + + /** Get number of bytes received for this {@link Entry}. */ + public long getRxBytes() { + return rxBytes; + } + + /** Get number of packets received for this {@link Entry}. */ + public long getRxPackets() { + return rxPackets; + } + + /** Get number of bytes transmitted for this {@link Entry}. */ + public long getTxBytes() { + return txBytes; + } + + /** Get number of packets transmitted for this {@link Entry}. */ + public long getTxPackets() { + return txPackets; + } + + /** Get count of network operations performed for this {@link Entry}. */ + public long getOperations() { + return operations; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o.getClass() != getClass()) return false; + Entry entry = (Entry) o; + return bucketStart == entry.bucketStart + && activeTime == entry.activeTime && rxBytes == entry.rxBytes + && rxPackets == entry.rxPackets && txBytes == entry.txBytes + && txPackets == entry.txPackets && operations == entry.operations; + } + + @Override + public int hashCode() { + return (int) (bucketStart * 2 + + activeTime * 3 + + rxBytes * 5 + + rxPackets * 7 + + txBytes * 11 + + txPackets * 13 + + operations * 17); + } + + @Override + public String toString() { + return "Entry{" + + "bucketStart=" + bucketStart + + ", activeTime=" + activeTime + + ", rxBytes=" + rxBytes + + ", rxPackets=" + rxPackets + + ", txBytes=" + txBytes + + ", txPackets=" + txPackets + + ", operations=" + operations + + "}"; + } } /** @hide */ @@ -324,6 +460,22 @@ public final class NetworkStatsHistory implements Parcelable { return entry; } + /** + * Get List of {@link Entry} of the {@link NetworkStatsHistory} instance. + * + * @return + */ + @NonNull + public List getEntries() { + // TODO: Return a wrapper that uses this list instead, to prevent the returned result + // from being changed. + final ArrayList ret = new ArrayList<>(size()); + for (int i = 0; i < size(); i++) { + ret.add(getValues(i, null /* recycle */)); + } + return ret; + } + /** @hide */ public void setValues(int i, Entry entry) { // Unwind old values @@ -928,4 +1080,80 @@ public final class NetworkStatsHistory implements Parcelable { } } + /** + * Builder class for {@link NetworkStatsHistory}. + */ + public static final class Builder { + private final long mBucketDuration; + private final List mBucketStart; + private final List mActiveTime; + private final List mRxBytes; + private final List mRxPackets; + private final List mTxBytes; + private final List mTxPackets; + private final List mOperations; + + /** + * Creates a new Builder with given bucket duration and initial capacity to construct + * {@link NetworkStatsHistory} objects. + * + * @param bucketDuration Duration of the buckets of the object, in milliseconds. + * @param initialCapacity Estimated number of records. + */ + public Builder(long bucketDuration, int initialCapacity) { + mBucketDuration = bucketDuration; + mBucketStart = new ArrayList<>(initialCapacity); + mActiveTime = new ArrayList<>(initialCapacity); + mRxBytes = new ArrayList<>(initialCapacity); + mRxPackets = new ArrayList<>(initialCapacity); + mTxBytes = new ArrayList<>(initialCapacity); + mTxPackets = new ArrayList<>(initialCapacity); + mOperations = new ArrayList<>(initialCapacity); + } + + /** + * Add an {@link Entry} into the {@link NetworkStatsHistory} instance. + * + * @param entry The target {@link Entry} object. + * @return The builder object. + */ + @NonNull + public Builder addEntry(@NonNull Entry entry) { + mBucketStart.add(entry.bucketStart); + mActiveTime.add(entry.activeTime); + mRxBytes.add(entry.rxBytes); + mRxPackets.add(entry.rxPackets); + mTxBytes.add(entry.txBytes); + mTxPackets.add(entry.txPackets); + mOperations.add(entry.operations); + return this; + } + + private static long sum(@NonNull List list) { + long sum = 0; + for (long entry : list) { + sum += entry; + } + return sum; + } + + /** + * Builds the instance of the {@link NetworkStatsHistory}. + * + * @return the built instance of {@link NetworkStatsHistory}. + */ + @NonNull + public NetworkStatsHistory build() { + return new NetworkStatsHistory(mBucketDuration, + CollectionUtils.toLongArray(mBucketStart), + CollectionUtils.toLongArray(mActiveTime), + CollectionUtils.toLongArray(mRxBytes), + CollectionUtils.toLongArray(mRxPackets), + CollectionUtils.toLongArray(mTxBytes), + CollectionUtils.toLongArray(mTxPackets), + CollectionUtils.toLongArray(mOperations), + mBucketStart.size(), + sum(mRxBytes) + sum(mTxBytes)); + } + } } From ed76c1b8ea2d40c1f2ea44d4e0157b2a57400cf2 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 28 Dec 2021 06:33:23 +0000 Subject: [PATCH 1068/1150] Move Ethernet related files to f/b/packages/ConnectivityT. ethernet-service is going to be moved into Connectivity mainline module. Notice that below sources are also only used in the ethernet framework during compiling the filegroup: framework-connectivity-ethernet-sources. Move them from f/b to f/b/packages/ConnectivityT as well. Ethernet framework only related files: - IInternalNetworkManagementListener.aidl - InternalNetworkManagementException.java - InternalNetworkManagementException.aidl - InternalNetworkUpdateRequest.java - InternalNetworkUpdateRequest.aidl Ethernet service only related files: - DelayedDiskWrite.java(IpConfigStore imports this class) Bug: 210586283 Test: build pass atest FrameworksNetTests atest EthernetServiceTests Change-Id: I1ec2d1d182c04f3f2acc9b757d5061ca749a4a3c --- framework-t/Sources.bp | 5 +++++ .../InternalNetworkManagementException.aidl | 0 .../InternalNetworkManagementException.java | 0 .../net/InternalNetworkUpdateRequest.aidl | 0 .../net/InternalNetworkUpdateRequest.java | 0 service-t/Sources.bp | 1 + .../android/server/net/DelayedDiskWrite.java | 22 ++++++++++++++++--- 7 files changed, 25 insertions(+), 3 deletions(-) rename {core/java => framework-t/src}/android/net/InternalNetworkManagementException.aidl (100%) rename {core/java => framework-t/src}/android/net/InternalNetworkManagementException.java (100%) rename {core/java => framework-t/src}/android/net/InternalNetworkUpdateRequest.aidl (100%) rename {core/java => framework-t/src}/android/net/InternalNetworkUpdateRequest.java (100%) rename {services/core/java => service-t/src}/com/android/server/net/DelayedDiskWrite.java (82%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index d3d8bba16c..223bdcdd9c 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -129,6 +129,11 @@ filegroup { "src/android/net/EthernetNetworkSpecifier.java", "src/android/net/IEthernetManager.aidl", "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/IInternalNetworkManagementListener.aidl", + "src/android/net/InternalNetworkUpdateRequest.java", + "src/android/net/InternalNetworkUpdateRequest.aidl", + "src/android/net/InternalNetworkManagementException.java", + "src/android/net/InternalNetworkManagementException.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/core/java/android/net/InternalNetworkManagementException.aidl b/framework-t/src/android/net/InternalNetworkManagementException.aidl similarity index 100% rename from core/java/android/net/InternalNetworkManagementException.aidl rename to framework-t/src/android/net/InternalNetworkManagementException.aidl diff --git a/core/java/android/net/InternalNetworkManagementException.java b/framework-t/src/android/net/InternalNetworkManagementException.java similarity index 100% rename from core/java/android/net/InternalNetworkManagementException.java rename to framework-t/src/android/net/InternalNetworkManagementException.java diff --git a/core/java/android/net/InternalNetworkUpdateRequest.aidl b/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl similarity index 100% rename from core/java/android/net/InternalNetworkUpdateRequest.aidl rename to framework-t/src/android/net/InternalNetworkUpdateRequest.aidl diff --git a/core/java/android/net/InternalNetworkUpdateRequest.java b/framework-t/src/android/net/InternalNetworkUpdateRequest.java similarity index 100% rename from core/java/android/net/InternalNetworkUpdateRequest.java rename to framework-t/src/android/net/InternalNetworkUpdateRequest.java diff --git a/service-t/Sources.bp b/service-t/Sources.bp index b261e165a1..36dd20054c 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -66,6 +66,7 @@ filegroup { filegroup { name: "services.connectivity-ethernet-sources", srcs: [ + "src/com/android/server/net/DelayedDiskWrite.java", "src/com/android/server/net/IpConfigStore.java", ], path: "src", diff --git a/services/core/java/com/android/server/net/DelayedDiskWrite.java b/service-t/src/com/android/server/net/DelayedDiskWrite.java similarity index 82% rename from services/core/java/com/android/server/net/DelayedDiskWrite.java rename to service-t/src/com/android/server/net/DelayedDiskWrite.java index 8f09eb7c19..35dc455725 100644 --- a/services/core/java/com/android/server/net/DelayedDiskWrite.java +++ b/service-t/src/com/android/server/net/DelayedDiskWrite.java @@ -26,21 +26,37 @@ import java.io.DataOutputStream; import java.io.FileOutputStream; import java.io.IOException; +/** + * This class provides APIs to do a delayed data write to a given {@link OutputStream}. + */ public class DelayedDiskWrite { + private static final String TAG = "DelayedDiskWrite"; + private HandlerThread mDiskWriteHandlerThread; private Handler mDiskWriteHandler; /* Tracks multiple writes on the same thread */ private int mWriteSequence = 0; - private final String TAG = "DelayedDiskWrite"; + /** + * Used to do a delayed data write to a given {@link OutputStream}. + */ public interface Writer { - public void onWriteCalled(DataOutputStream out) throws IOException; + /** + * write data to a given {@link OutputStream}. + */ + void onWriteCalled(DataOutputStream out) throws IOException; } + /** + * Do a delayed data write to a given output stream opened from filePath. + */ public void write(final String filePath, final Writer w) { write(filePath, w, true); } + /** + * Do a delayed data write to a given output stream opened from filePath. + */ public void write(final String filePath, final Writer w, final boolean open) { if (TextUtils.isEmpty(filePath)) { throw new IllegalArgumentException("empty file path"); @@ -77,7 +93,7 @@ public class DelayedDiskWrite { if (out != null) { try { out.close(); - } catch (Exception e) {} + } catch (Exception e) { } } // Quit if no more writes sent From 0bb493e12e863a423710ecaa336c2b376905398d Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Sun, 16 Jan 2022 16:29:17 +0000 Subject: [PATCH 1069/1150] [MS58] Expose Apis which will be used by data migration utility This includes: 1. NetworkIdentity 2. NetworkIdentitySet 3. NetworkStatsHistory NetworkStatsCollection Apis will be exposed in a separate CL. Test: TH Bug: 204830222 Change-Id: I47b2d3ac3b86cb4e6879afaae34326ca3c050ffa --- .../src/android/net/NetworkIdentity.java | 49 +++++++++++++------ .../src/android/net/NetworkIdentitySet.java | 26 +++++----- .../android/net/NetworkStatsCollection.java | 27 ++++++---- .../src/android/net/NetworkStatsHistory.java | 4 +- 4 files changed, 68 insertions(+), 38 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index ae0e8aa02e..d3d5a087cc 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -16,6 +16,7 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; @@ -24,6 +25,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.content.Context; import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; @@ -46,8 +48,8 @@ import java.util.Objects; * * @hide */ -// @SystemApi(client = MODULE_LIBRARIES) -public class NetworkIdentity implements Comparable { +@SystemApi(client = MODULE_LIBRARIES) +public class NetworkIdentity { private static final String TAG = "NetworkIdentity"; /** @hide */ @@ -299,30 +301,30 @@ public class NetworkIdentity implements Comparable { return oemManaged; } - @Override - public int compareTo(@NonNull NetworkIdentity another) { - Objects.requireNonNull(another); - int res = Integer.compare(mType, another.mType); + /** @hide */ + public static int compare(@NonNull NetworkIdentity left, @NonNull NetworkIdentity right) { + Objects.requireNonNull(right); + int res = Integer.compare(left.mType, right.mType); if (res == 0) { - res = Integer.compare(mRatType, another.mRatType); + res = Integer.compare(left.mRatType, right.mRatType); } - if (res == 0 && mSubscriberId != null && another.mSubscriberId != null) { - res = mSubscriberId.compareTo(another.mSubscriberId); + if (res == 0 && left.mSubscriberId != null && right.mSubscriberId != null) { + res = left.mSubscriberId.compareTo(right.mSubscriberId); } - if (res == 0 && mWifiNetworkKey != null && another.mWifiNetworkKey != null) { - res = mWifiNetworkKey.compareTo(another.mWifiNetworkKey); + if (res == 0 && left.mWifiNetworkKey != null && right.mWifiNetworkKey != null) { + res = left.mWifiNetworkKey.compareTo(right.mWifiNetworkKey); } if (res == 0) { - res = Boolean.compare(mRoaming, another.mRoaming); + res = Boolean.compare(left.mRoaming, right.mRoaming); } if (res == 0) { - res = Boolean.compare(mMetered, another.mMetered); + res = Boolean.compare(left.mMetered, right.mMetered); } if (res == 0) { - res = Boolean.compare(mDefaultNetwork, another.mDefaultNetwork); + res = Boolean.compare(left.mDefaultNetwork, right.mDefaultNetwork); } if (res == 0) { - res = Integer.compare(mOemManaged, another.mOemManaged); + res = Integer.compare(left.mOemManaged, right.mOemManaged); } return res; } @@ -362,7 +364,14 @@ public class NetworkIdentity implements Comparable { /** * Add an {@link NetworkStateSnapshot} into the {@link NetworkIdentity} instance. - * This is to read roaming, metered, wifikey... from the snapshot for convenience. + * This is a useful shorthand that will read from the snapshot and set the + * following fields, if they are set in the snapshot : + * - type + * - subscriberId + * - roaming + * - metered + * - oemManaged + * - wifiNetworkKey * * @param snapshot The target {@link NetworkStateSnapshot} object. * @return The builder object. @@ -415,6 +424,8 @@ public class NetworkIdentity implements Comparable { /** * Set the Radio Access Technology(RAT) type of the network. * + * No RAT type is specified by default. Call clearRatType to reset. + * * @param ratType the Radio Access Technology(RAT) type if applicable. See * {@code TelephonyManager.NETWORK_TYPE_*}. * @@ -470,6 +481,8 @@ public class NetworkIdentity implements Comparable { /** * Set whether this network is roaming. * + * This field is false by default. Call with false to reset. + * * @param roaming the roaming status of the network. * @return this builder. */ @@ -482,6 +495,8 @@ public class NetworkIdentity implements Comparable { /** * Set whether this network is metered. * + * This field is false by default. Call with false to reset. + * * @param metered the meteredness of the network. * @return this builder. */ @@ -494,6 +509,8 @@ public class NetworkIdentity implements Comparable { /** * Set whether this network is the default network. * + * This field is false by default. Call with false to reset. + * * @param defaultNetwork the default network status of the network. * @return this builder. */ diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index 041f070512..dfa347f6f1 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -27,6 +27,7 @@ import java.io.DataOutput; import java.io.IOException; import java.util.HashSet; import java.util.Objects; +import java.util.Set; /** * Identity of a {@code iface}, defined by the set of {@link NetworkIdentity} @@ -34,9 +35,7 @@ import java.util.Objects; * * @hide */ -// @SystemApi(client = MODULE_LIBRARIES) -public class NetworkIdentitySet extends HashSet implements - Comparable { +public class NetworkIdentitySet extends HashSet { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_ROAMING = 2; private static final int VERSION_ADD_NETWORK_ID = 3; @@ -51,6 +50,11 @@ public class NetworkIdentitySet extends HashSet implements super(); } + /** @hide */ + public NetworkIdentitySet(@NonNull Set ident) { + super(ident); + } + /** @hide */ public NetworkIdentitySet(DataInput in) throws IOException { final int version = in.readInt(); @@ -189,15 +193,15 @@ public class NetworkIdentitySet extends HashSet implements } } - @Override - public int compareTo(@NonNull NetworkIdentitySet another) { - Objects.requireNonNull(another); - if (isEmpty()) return -1; - if (another.isEmpty()) return 1; + public static int compare(@NonNull NetworkIdentitySet left, @NonNull NetworkIdentitySet right) { + Objects.requireNonNull(left); + Objects.requireNonNull(right); + if (left.isEmpty()) return -1; + if (right.isEmpty()) return 1; - final NetworkIdentity ident = iterator().next(); - final NetworkIdentity anotherIdent = another.iterator().next(); - return ident.compareTo(anotherIdent); + final NetworkIdentity leftIdent = left.iterator().next(); + final NetworkIdentity rightIdent = right.iterator().next(); + return NetworkIdentity.compare(leftIdent, rightIdent); } /** diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index f169fed6b9..58ca21fdfa 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -72,6 +72,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Objects; +import java.util.Set; /** * Collection of {@link NetworkStatsHistory}, stored based on combined key of @@ -702,7 +703,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private ArrayList getSortedKeys() { final ArrayList keys = new ArrayList<>(); keys.addAll(mStats.keySet()); - Collections.sort(keys); + Collections.sort(keys, (left, right) -> Key.compare(left, right)); return keys; } @@ -812,7 +813,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * the identifier that associate with the {@link NetworkStatsHistory} object to identify * a certain record in the {@link NetworkStatsCollection} object. */ - public static class Key implements Comparable { + public static class Key { /** @hide */ public final NetworkIdentitySet ident; /** @hide */ @@ -832,6 +833,11 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * @param set Set of the record, see {@code NetworkStats#SET_*}. * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}. */ + public Key(@NonNull Set ident, int uid, int set, int tag) { + this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag); + } + + /** @hide */ public Key(@NonNull NetworkIdentitySet ident, int uid, int set, int tag) { this.ident = Objects.requireNonNull(ident); this.uid = uid; @@ -855,21 +861,22 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W return false; } - @Override - public int compareTo(@NonNull Key another) { - Objects.requireNonNull(another); + /** @hide */ + public static int compare(@NonNull Key left, @NonNull Key right) { + Objects.requireNonNull(left); + Objects.requireNonNull(right); int res = 0; - if (ident != null && another.ident != null) { - res = ident.compareTo(another.ident); + if (left.ident != null && right.ident != null) { + res = NetworkIdentitySet.compare(left.ident, right.ident); } if (res == 0) { - res = Integer.compare(uid, another.uid); + res = Integer.compare(left.uid, right.uid); } if (res == 0) { - res = Integer.compare(set, another.set); + res = Integer.compare(left.set, right.set); } if (res == 0) { - res = Integer.compare(tag, another.tag); + res = Integer.compare(left.tag, right.tag); } return res; } diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index a09b3bb7db..78c137073a 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -16,6 +16,7 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.NetworkStats.IFACE_ALL; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_NONE; @@ -31,6 +32,7 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.compat.annotation.UnsupportedAppUsage; import android.os.Build; import android.os.Parcel; @@ -67,7 +69,7 @@ import java.util.Random; * * @hide */ -// @SystemApi(client = MODULE_LIBRARIES) +@SystemApi(client = MODULE_LIBRARIES) public final class NetworkStatsHistory implements Parcelable { private static final int VERSION_INIT = 1; private static final int VERSION_ADD_PACKETS = 2; From c28dd15332ec595b318a1eea15798db2b9814602 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sun, 23 Jan 2022 17:20:19 +0800 Subject: [PATCH 1070/1150] [MS38] Remove android.os.HandlerExecutor dependencies Mainline module can't use internal HandlerExecutor, so inline the implementation instead. Test: atest FrameworksNetTests NetworkPolicyManagerServiceTest Bug: 204830222 Change-Id: I54c2258cb3cee5fb862409441de293d6fed6b32c --- .../src/com/android/server/net/NetworkStatsService.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 9b90f3b545..1105de3dd9 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -106,7 +106,6 @@ import android.os.Binder; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; -import android.os.HandlerExecutor; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; @@ -450,7 +449,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { handlerThread.start(); mHandler = new NetworkStatsHandler(handlerThread.getLooper()); mNetworkStatsSubscriptionsMonitor = deps.makeSubscriptionsMonitor(mContext, - new HandlerExecutor(mHandler), this); + (command) -> mHandler.post(command) , this); mContentResolver = mContext.getContentResolver(); mContentObserver = mDeps.makeContentObserver(mHandler, mSettings, mNetworkStatsSubscriptionsMonitor); @@ -557,7 +556,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // watch for tethering changes final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class); tetheringManager.registerTetheringEventCallback( - new HandlerExecutor(mHandler), mTetherListener); + (command) -> mHandler.post(command), mTetherListener); // listen for periodic polling events final IntentFilter pollFilter = new IntentFilter(ACTION_NETWORK_STATS_POLL); From 18a2105afa1c1961951b2eaa68a2cf16fe7f4ad2 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sun, 23 Jan 2022 01:22:16 +0800 Subject: [PATCH 1071/1150] [MS67.1] Expose registerUsageCallback with template Test: atest FrameworksNetTests Bug: 204830222 Change-Id: I643e2d96144210852fc8916ec9c483f2b207a48b --- .../app/usage/NetworkStatsManager.java | 145 +++++++++++------- .../src/android/net/INetworkStatsService.aidl | 3 +- .../android/net/netstats/IUsageCallback.aidl | 29 ++++ .../server/net/NetworkStatsObservers.java | 56 ++++--- .../server/net/NetworkStatsService.java | 13 +- 5 files changed, 155 insertions(+), 91 deletions(-) create mode 100644 framework-t/src/android/net/netstats/IUsageCallback.aidl diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 8813f98451..453e8e61bf 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import android.Manifest; +import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -39,14 +40,11 @@ import android.net.NetworkStack; import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; import android.net.UnderlyingNetworkInfo; +import android.net.netstats.IUsageCallback; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; -import android.os.Binder; import android.os.Build; import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; import android.os.RemoteException; import android.telephony.TelephonyManager; import android.text.TextUtils; @@ -57,6 +55,7 @@ import com.android.net.module.util.NetworkIdentityUtils; import java.util.List; import java.util.Objects; +import java.util.concurrent.Executor; /** * Provides access to network usage history and statistics. Usage data is collected in @@ -723,26 +722,35 @@ public class NetworkStatsManager { } } - /** @hide */ - public void registerUsageCallback(NetworkTemplate template, int networkType, - long thresholdBytes, UsageCallback callback, @Nullable Handler handler) { + /** + * Registers to receive notifications about data usage on specified networks. + * + *

            The callbacks will continue to be called as long as the process is alive or + * {@link #unregisterUsageCallback} is called. + * + * @param template Template used to match networks. See {@link NetworkTemplate}. + * @param thresholdBytes Threshold in bytes to be notified on. + * @param executor The executor on which callback will be invoked. The provided {@link Executor} + * must run callback sequentially, otherwise the order of callbacks cannot be + * guaranteed. + * @param callback The {@link UsageCallback} that the system will call when data usage + * has exceeded the specified threshold. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, + @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { + Objects.requireNonNull(template, "NetworkTemplate cannot be null"); Objects.requireNonNull(callback, "UsageCallback cannot be null"); + Objects.requireNonNull(executor, "Executor cannot be null"); - final Looper looper; - if (handler == null) { - looper = Looper.myLooper(); - } else { - looper = handler.getLooper(); - } - - DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, + final DataUsageRequest request = new DataUsageRequest(DataUsageRequest.REQUEST_ID_UNSET, template, thresholdBytes); try { - CallbackHandler callbackHandler = new CallbackHandler(looper, networkType, - template.getSubscriberId(), callback); + final UsageCallbackWrapper callbackWrapper = + new UsageCallbackWrapper(executor, callback); callback.request = mService.registerUsageCallback( - mContext.getOpPackageName(), request, new Messenger(callbackHandler), - new Binder()); + mContext.getOpPackageName(), request, callbackWrapper); if (DBG) Log.d(TAG, "registerUsageCallback returned " + callback.request); if (callback.request == null) { @@ -795,12 +803,15 @@ public class NetworkStatsManager { NetworkTemplate template = createTemplate(networkType, subscriberId); if (DBG) { Log.d(TAG, "registerUsageCallback called with: {" - + " networkType=" + networkType - + " subscriberId=" + subscriberId - + " thresholdBytes=" + thresholdBytes - + " }"); + + " networkType=" + networkType + + " subscriberId=" + subscriberId + + " thresholdBytes=" + thresholdBytes + + " }"); } - registerUsageCallback(template, networkType, thresholdBytes, callback, handler); + + final Executor executor = handler == null ? r -> r.run() : r -> handler.post(r); + + registerUsageCallback(template, thresholdBytes, executor, callback); } /** @@ -825,6 +836,26 @@ public class NetworkStatsManager { * Base class for usage callbacks. Should be extended by applications wanting notifications. */ public static abstract class UsageCallback { + /** + * Called when data usage has reached the given threshold. + * + * Called by {@code NetworkStatsService} when the registered threshold is reached. + * If a caller implements {@link #onThresholdReached(NetworkTemplate)}, the system + * will not call {@link #onThresholdReached(int, String)}. + * + * @param template The {@link NetworkTemplate} that associated with this callback. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public void onThresholdReached(@NonNull NetworkTemplate template) { + // Backward compatibility for those who didn't override this function. + final int networkType = networkTypeForTemplate(template); + if (networkType != ConnectivityManager.TYPE_NONE) { + final String subscriberId = template.getSubscriberIds().isEmpty() ? null + : template.getSubscriberIds().iterator().next(); + onThresholdReached(networkType, subscriberId); + } + } /** * Called when data usage has reached the given threshold. @@ -835,6 +866,25 @@ public class NetworkStatsManager { * @hide used for internal bookkeeping */ private DataUsageRequest request; + + /** + * Get network type from a template if feasible. + * + * @param template the target {@link NetworkTemplate}. + * @return legacy network type, only supports for the types which is already supported in + * {@link #registerUsageCallback(int, String, long, UsageCallback, Handler)}. + * {@link ConnectivityManager#TYPE_NONE} for other types. + */ + private static int networkTypeForTemplate(@NonNull NetworkTemplate template) { + switch (template.getMatchRule()) { + case NetworkTemplate.MATCH_MOBILE: + return ConnectivityManager.TYPE_MOBILE; + case NetworkTemplate.MATCH_WIFI: + return ConnectivityManager.TYPE_WIFI; + default: + return ConnectivityManager.TYPE_NONE; + } + } } /** @@ -953,43 +1003,32 @@ public class NetworkStatsManager { } } - private static class CallbackHandler extends Handler { - private final int mNetworkType; - private final String mSubscriberId; - private UsageCallback mCallback; + private static class UsageCallbackWrapper extends IUsageCallback.Stub { + // Null if unregistered. + private volatile UsageCallback mCallback; - CallbackHandler(Looper looper, int networkType, String subscriberId, - UsageCallback callback) { - super(looper); - mNetworkType = networkType; - mSubscriberId = subscriberId; + private final Executor mExecutor; + + UsageCallbackWrapper(@NonNull Executor executor, @NonNull UsageCallback callback) { mCallback = callback; + mExecutor = executor; } @Override - public void handleMessage(Message message) { - DataUsageRequest request = - (DataUsageRequest) getObject(message, DataUsageRequest.PARCELABLE_KEY); - - switch (message.what) { - case CALLBACK_LIMIT_REACHED: { - if (mCallback != null) { - mCallback.onThresholdReached(mNetworkType, mSubscriberId); - } else { - Log.e(TAG, "limit reached with released callback for " + request); - } - break; - } - case CALLBACK_RELEASED: { - if (DBG) Log.d(TAG, "callback released for " + request); - mCallback = null; - break; - } + public void onThresholdReached(DataUsageRequest request) { + // Copy it to a local variable in case mCallback changed inside the if condition. + final UsageCallback callback = mCallback; + if (callback != null) { + mExecutor.execute(() -> callback.onThresholdReached(request.template)); + } else { + Log.e(TAG, "onThresholdReached with released callback for " + request); } } - private static Object getObject(Message msg, String key) { - return msg.getData().getParcelable(key); + @Override + public void onCallbackReleased(DataUsageRequest request) { + if (DBG) Log.d(TAG, "callback released for " + request); + mCallback = null; } } diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index da0aa99b93..efe626d3c9 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -24,6 +24,7 @@ import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.net.UnderlyingNetworkInfo; +import android.net.netstats.IUsageCallback; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.os.IBinder; @@ -71,7 +72,7 @@ interface INetworkStatsService { /** Registers a callback on data usage. */ DataUsageRequest registerUsageCallback(String callingPackage, - in DataUsageRequest request, in Messenger messenger, in IBinder binder); + in DataUsageRequest request, in IUsageCallback callback); /** Unregisters a callback on data usage. */ void unregisterUsageRequest(in DataUsageRequest request); diff --git a/framework-t/src/android/net/netstats/IUsageCallback.aidl b/framework-t/src/android/net/netstats/IUsageCallback.aidl new file mode 100644 index 0000000000..4e8a5b2309 --- /dev/null +++ b/framework-t/src/android/net/netstats/IUsageCallback.aidl @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.netstats; + +import android.net.DataUsageRequest; + +/** + * Interface for NetworkStatsService to notify events to the callers of registerUsageCallback. + * + * @hide + */ +oneway interface IUsageCallback { + void onThresholdReached(in DataUsageRequest request); + void onCallbackReleased(in DataUsageRequest request); +} diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index b57a4f920b..e85a59e8be 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -26,13 +26,12 @@ import android.net.NetworkStatsAccess; import android.net.NetworkStatsCollection; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; -import android.os.Bundle; +import android.net.netstats.IUsageCallback; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.Messenger; import android.os.Process; import android.os.RemoteException; import android.util.ArrayMap; @@ -75,10 +74,10 @@ class NetworkStatsObservers { * * @return the normalized request wrapped within {@link RequestInfo}. */ - public DataUsageRequest register(DataUsageRequest inputRequest, Messenger messenger, - IBinder binder, int callingUid, @NetworkStatsAccess.Level int accessLevel) { + public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback, + int callingUid, @NetworkStatsAccess.Level int accessLevel) { DataUsageRequest request = buildRequest(inputRequest); - RequestInfo requestInfo = buildRequestInfo(request, messenger, binder, callingUid, + RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, accessLevel); if (LOGV) Log.v(TAG, "Registering observer for " + request); @@ -206,11 +205,10 @@ class NetworkStatsObservers { request.template, thresholdInBytes); } - private RequestInfo buildRequestInfo(DataUsageRequest request, - Messenger messenger, IBinder binder, int callingUid, - @NetworkStatsAccess.Level int accessLevel) { + private RequestInfo buildRequestInfo(DataUsageRequest request, IUsageCallback callback, + int callingUid, @NetworkStatsAccess.Level int accessLevel) { if (accessLevel <= NetworkStatsAccess.Level.USER) { - return new UserUsageRequestInfo(this, request, messenger, binder, callingUid, + return new UserUsageRequestInfo(this, request, callback, callingUid, accessLevel); } else { // Safety check in case a new access level is added and we forgot to update this @@ -218,7 +216,7 @@ class NetworkStatsObservers { throw new IllegalArgumentException( "accessLevel " + accessLevel + " is less than DEVICESUMMARY."); } - return new NetworkUsageRequestInfo(this, request, messenger, binder, callingUid, + return new NetworkUsageRequestInfo(this, request, callback, callingUid, accessLevel); } } @@ -230,25 +228,23 @@ class NetworkStatsObservers { private abstract static class RequestInfo implements IBinder.DeathRecipient { private final NetworkStatsObservers mStatsObserver; protected final DataUsageRequest mRequest; - private final Messenger mMessenger; - private final IBinder mBinder; + private final IUsageCallback mCallback; protected final int mCallingUid; protected final @NetworkStatsAccess.Level int mAccessLevel; protected NetworkStatsRecorder mRecorder; protected NetworkStatsCollection mCollection; RequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - Messenger messenger, IBinder binder, int callingUid, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { mStatsObserver = statsObserver; mRequest = request; - mMessenger = messenger; - mBinder = binder; + mCallback = callback; mCallingUid = callingUid; mAccessLevel = accessLevel; try { - mBinder.linkToDeath(this, 0); + mCallback.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { binderDied(); } @@ -257,7 +253,7 @@ class NetworkStatsObservers { @Override public void binderDied() { if (LOGV) { - Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mBinder + ")"); + Log.v(TAG, "RequestInfo binderDied(" + mRequest + ", " + mCallback + ")"); } mStatsObserver.unregister(mRequest, Process.SYSTEM_UID); callCallback(NetworkStatsManager.CALLBACK_RELEASED); @@ -270,9 +266,7 @@ class NetworkStatsObservers { } private void unlinkDeathRecipient() { - if (mBinder != null) { - mBinder.unlinkToDeath(this, 0); - } + mCallback.asBinder().unlinkToDeath(this, 0); } /** @@ -294,17 +288,19 @@ class NetworkStatsObservers { } private void callCallback(int callbackType) { - Bundle bundle = new Bundle(); - bundle.putParcelable(DataUsageRequest.PARCELABLE_KEY, mRequest); - Message msg = Message.obtain(); - msg.what = callbackType; - msg.setData(bundle); try { if (LOGV) { Log.v(TAG, "sending notification " + callbackTypeToName(callbackType) + " for " + mRequest); } - mMessenger.send(msg); + switch (callbackType) { + case NetworkStatsManager.CALLBACK_LIMIT_REACHED: + mCallback.onThresholdReached(mRequest); + break; + case NetworkStatsManager.CALLBACK_RELEASED: + mCallback.onCallbackReleased(mRequest); + break; + } } catch (RemoteException e) { // May occur naturally in the race of binder death. Log.w(TAG, "RemoteException caught trying to send a callback msg for " + mRequest); @@ -334,9 +330,9 @@ class NetworkStatsObservers { private static class NetworkUsageRequestInfo extends RequestInfo { NetworkUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - Messenger messenger, IBinder binder, int callingUid, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, messenger, binder, callingUid, accessLevel); + super(statsObserver, request, callback, callingUid, accessLevel); } @Override @@ -376,9 +372,9 @@ class NetworkStatsObservers { private static class UserUsageRequestInfo extends RequestInfo { UserUsageRequestInfo(NetworkStatsObservers statsObserver, DataUsageRequest request, - Messenger messenger, IBinder binder, int callingUid, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - super(statsObserver, request, messenger, binder, callingUid, accessLevel); + super(statsObserver, request, callback, callingUid, accessLevel); } @Override diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1105de3dd9..1f87f7bf96 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -99,6 +99,7 @@ import android.net.TetheringManager; import android.net.TrafficStats; import android.net.UnderlyingNetworkInfo; import android.net.Uri; +import android.net.netstats.IUsageCallback; import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; @@ -110,7 +111,6 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; -import android.os.Messenger; import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceSpecificException; @@ -1136,21 +1136,20 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public DataUsageRequest registerUsageCallback(String callingPackage, - DataUsageRequest request, Messenger messenger, IBinder binder) { + public DataUsageRequest registerUsageCallback(@NonNull String callingPackage, + @NonNull DataUsageRequest request, @NonNull IUsageCallback callback) { Objects.requireNonNull(callingPackage, "calling package is null"); Objects.requireNonNull(request, "DataUsageRequest is null"); Objects.requireNonNull(request.template, "NetworkTemplate is null"); - Objects.requireNonNull(messenger, "messenger is null"); - Objects.requireNonNull(binder, "binder is null"); + Objects.requireNonNull(callback, "callback is null"); int callingUid = Binder.getCallingUid(); @NetworkStatsAccess.Level int accessLevel = checkAccessLevel(callingPackage); DataUsageRequest normalizedRequest; final long token = Binder.clearCallingIdentity(); try { - normalizedRequest = mStatsObservers.register(request, messenger, binder, - callingUid, accessLevel); + normalizedRequest = mStatsObservers.register( + request, callback, callingUid, accessLevel); } finally { Binder.restoreCallingIdentity(token); } From 9db383cf1d90aec2f2be7d40a3425fac38d3bad3 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Tue, 28 Dec 2021 03:23:02 +0800 Subject: [PATCH 1072/1150] Use public resouce in android.R package Use public resource since IpSec is planed to be moved into Connectivity mainline module. Bug: 204153604 Test: build Change-Id: I0aafef6b9b08307c3aebce597a2dd24925c6b09a Merged-In: I0aafef6b9b08307c3aebce597a2dd24925c6b09a --- framework-t/src/android/net/IpSecAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecAlgorithm.java b/framework-t/src/android/net/IpSecAlgorithm.java index a84e7a9c63..10a22ac360 100644 --- a/framework-t/src/android/net/IpSecAlgorithm.java +++ b/framework-t/src/android/net/IpSecAlgorithm.java @@ -343,7 +343,7 @@ public final class IpSecAlgorithm implements Parcelable { // Load and validate the optional algorithm resource. Undefined or duplicate algorithms in // the resource are not allowed. final String[] resourceAlgos = systemResources.getStringArray( - com.android.internal.R.array.config_optionalIpSecAlgorithms); + android.R.array.config_optionalIpSecAlgorithms); for (String str : resourceAlgos) { if (!ALGO_TO_REQUIRED_FIRST_SDK.containsKey(str) || !enabledAlgos.add(str)) { // This error should be caught by CTS and never be thrown to API callers From f6487fb3c1ea11d42eaa3864ba53454a0dd0c2b5 Mon Sep 17 00:00:00 2001 From: junyulai Date: Sun, 23 Jan 2022 03:22:13 +0800 Subject: [PATCH 1073/1150] [MS68.1] Register usage callback from NetworkPolicyManagerService Use usage callback to replace the need of intent receiver. Test: atest TrafficStatsTest NetworkUsageStatsTest FrameworksNetTests Bug: 204830222 Change-Id: I40967c2b6c86d25c7db93e6d3a4908b72ed76154 --- .../src/android/app/usage/NetworkStatsManager.java | 3 ++- .../android/server/net/NetworkStatsObservers.java | 12 +++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 453e8e61bf..28f930ff12 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -729,7 +729,8 @@ public class NetworkStatsManager { * {@link #unregisterUsageCallback} is called. * * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. + * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower + * than 2MiB will be clamped for non-privileged callers. * @param executor The executor on which callback will be invoked. The provided {@link Executor} * must run callback sequentially, otherwise the order of callbacks cannot be * guaranteed. diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index e85a59e8be..19536247b2 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -76,7 +76,7 @@ class NetworkStatsObservers { */ public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(inputRequest); + DataUsageRequest request = buildRequest(inputRequest, callingUid); RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, accessLevel); @@ -194,10 +194,12 @@ class NetworkStatsObservers { } } - private DataUsageRequest buildRequest(DataUsageRequest request) { - // Cap the minimum threshold to a safe default to avoid too many callbacks - long thresholdInBytes = Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes); - if (thresholdInBytes < request.thresholdInBytes) { + private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) { + // For non-system uid, cap the minimum threshold to a safe default to avoid too + // many callbacks. + long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes + : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); + if (thresholdInBytes > request.thresholdInBytes) { Log.w(TAG, "Threshold was too low for " + request + ". Overriding to a safer default of " + thresholdInBytes + " bytes"); } From 82a33b8e6463c68900f484e64062469a501a5cdc Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Tue, 25 Jan 2022 07:40:06 +0000 Subject: [PATCH 1074/1150] [MS69.1] Fix TrafficStats.init crashs for supplemental process Supplemental apps has limited capabilities and service discovery is restricted. Hence, calling TrafficStats.init would result in crash. This change includes: 1. Print log instead of crashing process when running into any unexpected cases. Test: atest SupplementalProcessManagerTests Bug: 216062904 Change-Id: I7f827ccc485c997745779053b5936a6cb30e8219 --- framework-t/src/android/net/TrafficStats.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index 77b7f16671..c2f0cdfb04 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -31,6 +31,7 @@ import android.media.MediaPlayer; import android.os.Binder; import android.os.Build; import android.os.RemoteException; +import android.util.Log; import com.android.server.NetworkManagementSocketTagger; @@ -212,6 +213,13 @@ public class TrafficStats { } final NetworkStatsManager statsManager = context.getSystemService(NetworkStatsManager.class); + if (statsManager == null) { + // TODO: Currently Process.isSupplemental is not working yet, because it depends on + // process to run in a certain UID range, which is not true for now. Change this + // to Log.wtf once Process.isSupplemental is ready. + Log.e(TAG, "TrafficStats not initialized, uid=" + Binder.getCallingUid()); + return; + } sStatsService = statsManager.getBinder(); } From 9d749d5128bea462bdd3001c5749fb8f1b95ee07 Mon Sep 17 00:00:00 2001 From: Frank Date: Sat, 22 Jan 2022 22:29:24 +0800 Subject: [PATCH 1075/1150] [DU09-0]Adding the NetworkStatsCollection Builder The purpose is provide NetworkStatsCollection.Builder as public API for adding the stats {@link NetworkStatsHistory} Bug: 215862801 Test: atest NetworkStatsCollectionTest Change-Id: I65ad589473cbb7785cbe8297f793ce9f18a55c35 --- .../android/net/NetworkStatsCollection.java | 72 ++++++++++++++++++- 1 file changed, 71 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 58ca21fdfa..735c44d5c8 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -16,6 +16,7 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.NetworkStats.DEFAULT_NETWORK_NO; import static android.net.NetworkStats.DEFAULT_NETWORK_YES; import static android.net.NetworkStats.IFACE_ALL; @@ -34,6 +35,8 @@ import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRation import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.net.NetworkStatsHistory.Entry; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; import android.service.NetworkStatsCollectionProto; @@ -71,6 +74,8 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; +import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; @@ -80,7 +85,7 @@ import java.util.Set; * * @hide */ -// @SystemApi(client = MODULE_LIBRARIES) +@SystemApi(client = MODULE_LIBRARIES) public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.Writer { private static final String TAG = NetworkStatsCollection.class.getSimpleName(); /** File header magic number: "ANET" */ @@ -809,6 +814,71 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W return false; } + /** + * Get the all historical stats of the collection {@link NetworkStatsCollection}. + * + * @return All {@link NetworkStatsHistory} in this collection. + */ + @NonNull + public Map getEntries() { + return new ArrayMap(mStats); + } + + /** + * Builder class for {@link NetworkStatsCollection}. + */ + public static final class Builder { + private final long mBucketDuration; + private final ArrayMap mEntries = new ArrayMap<>(); + + /** + * Creates a new Builder with given bucket duration. + * + * @param bucketDuration Duration of the buckets of the object, in milliseconds. + */ + public Builder(long bucketDuration) { + mBucketDuration = bucketDuration; + } + + /** + * Add association of the history with the specified key in this map. + * + * @param key The object used to identify a network, see {@link Key}. + * @param history {@link NetworkStatsHistory} instance associated to the given {@link Key}. + * @return The builder object. + */ + @NonNull + public NetworkStatsCollection.Builder addEntry(@NonNull Key key, + @NonNull NetworkStatsHistory history) { + Objects.requireNonNull(key); + Objects.requireNonNull(history); + final List historyEntries = history.getEntries(); + + final NetworkStatsHistory.Builder historyBuilder = + new NetworkStatsHistory.Builder(mBucketDuration, historyEntries.size()); + for (Entry entry : historyEntries) { + historyBuilder.addEntry(entry); + } + + mEntries.put(key, historyBuilder.build()); + return this; + } + + /** + * Builds the instance of the {@link NetworkStatsCollection}. + * + * @return the built instance of {@link NetworkStatsCollection}. + */ + @NonNull + public NetworkStatsCollection build() { + final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); + for (int i = 0; i < mEntries.size(); i++) { + collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i)); + } + return collection; + } + } + /** * the identifier that associate with the {@link NetworkStatsHistory} object to identify * a certain record in the {@link NetworkStatsCollection} object. From ad252f83473990880a6736e254ea5046ce843293 Mon Sep 17 00:00:00 2001 From: junyulai Date: Wed, 26 Jan 2022 01:11:08 +0800 Subject: [PATCH 1076/1150] [MS74] Expose NetworkTemplate#matches This is used by NetworkPolicyManagerService to find relevant networks of a given NetworkPolicy. Test: TH Bug: 204830222 Change-Id: I7176ab727bf208e0fd05ecb9c2bcb00cd3438031 --- framework-t/src/android/net/NetworkTemplate.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index cad80752b8..dba3991330 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -652,7 +652,9 @@ public final class NetworkTemplate implements Parcelable { * * @hide */ - public boolean matches(NetworkIdentity ident) { + @SystemApi(client = MODULE_LIBRARIES) + public boolean matches(@NonNull NetworkIdentity ident) { + Objects.requireNonNull(ident); if (!matchesMetered(ident)) return false; if (!matchesRoaming(ident)) return false; if (!matchesDefaultNetwork(ident)) return false; From ce3dbdb7418ade46f968fe685deab1f122761e5f Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 26 Jan 2022 07:33:13 +0000 Subject: [PATCH 1077/1150] [MS78.1] Fix NetworkIdentity#Builder crashing on 5G NSA networks Test: atest NetworkIdentityTest Fix: 216193400 Change-Id: Iaeae0c66f222ae8730439c5aedf5d5818855875d --- framework-t/src/android/net/NetworkIdentity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index d3d5a087cc..77fc17192c 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -434,7 +434,8 @@ public class NetworkIdentity { @NonNull public Builder setRatType(@Annotation.NetworkType int ratType) { if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) - && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN) { + && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN + && ratType != NetworkTemplate.NETWORK_TYPE_5G_NSA) { throw new IllegalArgumentException("Invalid ratType " + ratType); } mRatType = ratType; From ad9ee7d92668114e4becbc85e7800466d75d249a Mon Sep 17 00:00:00 2001 From: markchien Date: Wed, 26 Jan 2022 22:39:07 +0800 Subject: [PATCH 1078/1150] Update UidCounterSetMap directly from NetworkStatsService Currently NetworkStatsService call NetworkManagementSocketTagger#setKernelCounterSet which would call into netd to update UidCounterSet bpf map. This change let NetworkStatsService get UidCounterSetMap and update it directly. After this change, NetworkManagementSocketTagger#setKernelCounterSet could be removed because NetworkStatsService is the only caller. Test: dump UidCounterSetMap to ensure it still have value after removing netd code. Change-Id: I7ae14106ded4fa55122e93e76c3057052a2fa33e --- .../server/net/NetworkStatsService.java | 53 ++++++++++++++++++- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 243d621647..874b1a06a5 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -60,7 +60,6 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; -import static com.android.server.NetworkManagementSocketTagger.setKernelCounterSet; import android.annotation.NonNull; import android.annotation.Nullable; @@ -121,6 +120,7 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; +import android.system.ErrnoException; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; import android.text.TextUtils; @@ -139,10 +139,14 @@ import com.android.internal.util.FileRotator; import com.android.net.module.util.BaseNetdUnsolicitedEventListener; import com.android.net.module.util.BestClock; import com.android.net.module.util.BinderUtils; +import com.android.net.module.util.BpfMap; import com.android.net.module.util.CollectionUtils; +import com.android.net.module.util.IBpfMap; import com.android.net.module.util.LocationPermissionChecker; import com.android.net.module.util.NetworkStatsUtils; import com.android.net.module.util.PermissionUtils; +import com.android.net.module.util.Struct.U32; +import com.android.net.module.util.Struct.U8; import java.io.File; import java.io.FileDescriptor; @@ -207,6 +211,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static final String NETSTATS_COMBINE_SUBTYPE_ENABLED = "netstats_combine_subtype_enabled"; + // This is current path but may be changed soon. + private static final String UID_COUNTERSET_MAP_PATH = + "/sys/fs/bpf/map_netd_uid_counterset_map"; + private final Context mContext; private final NetworkStatsFactory mStatsFactory; private final AlarmManager mAlarmManager; @@ -325,8 +333,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private NetworkStatsCollection mXtStatsCached; - /** Current counter sets for each UID. */ + /** + * Current counter sets for each UID. + * TODO: maybe remove mActiveUidCounterSet and read UidCouneterSet value from mUidCounterSetMap + * directly ? But if mActiveUidCounterSet would be accessed very frequently, maybe keep + * mActiveUidCounterSet to avoid accessing kernel too frequently. + */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); + private final IBpfMap mUidCounterSetMap; /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); @@ -459,6 +473,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); mInterfaceMapUpdater.start(); + mUidCounterSetMap = mDeps.getUidCounterSetMap(); } /** @@ -520,6 +535,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @NonNull Context ctx, @NonNull Handler handler) { return new BpfInterfaceMapUpdater(ctx, handler); } + + /** Get counter sets map for each UID. */ + public IBpfMap getUidCounterSetMap() { + try { + return new BpfMap(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR, + U32.class, U8.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create uid counter set map: " + e); + return null; + } + } } /** @@ -1077,6 +1103,29 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } + private void setKernelCounterSet(int uid, int set) { + if (mUidCounterSetMap == null) { + Log.wtf(TAG, "Fail to set UidCounterSet: Null bpf map"); + return; + } + + if (set == SET_DEFAULT) { + try { + mUidCounterSetMap.deleteEntry(new U32(uid)); + } catch (ErrnoException e) { + Log.w(TAG, "UidCounterSetMap.deleteEntry(" + uid + ") failed with errno: " + e); + } + return; + } + + try { + mUidCounterSetMap.updateEntry(new U32(uid), new U8((short) set)); + } catch (ErrnoException e) { + Log.w(TAG, "UidCounterSetMap.updateEntry(" + uid + ", " + set + + ") failed with errno: " + e); + } + } + @VisibleForTesting public void setUidForeground(int uid, boolean uidForeground) { PermissionUtils.enforceNetworkStackPermission(mContext); From 0bfd365a4f5f3eed8e0279179a129939f3ed8b21 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 26 Jan 2022 23:27:19 +0800 Subject: [PATCH 1079/1150] Move NETWORK_TYPE_5G_NSA from NetworkTemplate to NetworkStatsManager Move NETWORK_TYPE_5G_NSA to NetworkStatsManager. Also expose it as module API so that it can be used out of module. Bug: 210073043 Test: builds, FrameworksNetTests Change-Id: I670c7e1405107bbe30b92fe1a8d81652c46de6d9 --- .../app/usage/NetworkStatsManager.java | 12 ++++++++++ .../src/android/net/NetworkIdentity.java | 3 ++- .../src/android/net/NetworkTemplate.java | 22 +++++++------------ .../net/NetworkStatsSubscriptionsMonitor.java | 2 +- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 28f930ff12..d7e513f121 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -145,6 +145,18 @@ public class NetworkStatsManager { /** @hide */ public static final int FLAG_AUGMENT_WITH_SUBSCRIPTION_PLAN = 1 << 2; + /** + * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is + * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along + * with NR state as connected. This is a concept added by NetworkStats on top of the telephony + * constants for backward compatibility of metrics so this should not be overlapped with any of + * the {@code TelephonyManager.NETWORK_TYPE_*} constants. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int NETWORK_TYPE_5G_NSA = -2; + private int mFlags; /** @hide */ diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 77fc17192c..73b9c72699 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -26,6 +26,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SuppressLint; import android.annotation.SystemApi; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; @@ -435,7 +436,7 @@ public class NetworkIdentity { public Builder setRatType(@Annotation.NetworkType int ratType) { if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN - && ratType != NetworkTemplate.NETWORK_TYPE_5G_NSA) { + && ratType != NetworkStatsManager.NETWORK_TYPE_5G_NSA) { throw new IllegalArgumentException("Invalid ratType " + ratType); } mRatType = ratType; diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index dba3991330..649f54b09e 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -41,6 +41,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.app.usage.NetworkStatsManager; import android.compat.annotation.UnsupportedAppUsage; import android.net.wifi.WifiInfo; import android.os.Build; @@ -136,15 +137,6 @@ public final class NetworkTemplate implements Parcelable { * {@code TelephonyManager.NETWORK_TYPE_*} constants, and thus needs to stay in sync. */ public static final int NETWORK_TYPE_ALL = -1; - /** - * Virtual RAT type to represent 5G NSA (Non Stand Alone) mode, where the primary cell is - * still LTE and network allocates a secondary 5G cell so telephony reports RAT = LTE along - * with NR state as connected. This should not be overlapped with any of the - * {@code TelephonyManager.NETWORK_TYPE_*} constants. - * - * @hide - */ - public static final int NETWORK_TYPE_5G_NSA = -2; /** @hide */ @Retention(RetentionPolicy.SOURCE) @@ -791,9 +783,10 @@ public final class NetworkTemplate implements Parcelable { return TelephonyManager.NETWORK_TYPE_LTE; case TelephonyManager.NETWORK_TYPE_NR: return TelephonyManager.NETWORK_TYPE_NR; - // Virtual RAT type for 5G NSA mode, see {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. - case NetworkTemplate.NETWORK_TYPE_5G_NSA: - return NetworkTemplate.NETWORK_TYPE_5G_NSA; + // Virtual RAT type for 5G NSA mode, see + // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. + case NetworkStatsManager.NETWORK_TYPE_5G_NSA: + return NetworkStatsManager.NETWORK_TYPE_5G_NSA; default: return TelephonyManager.NETWORK_TYPE_UNKNOWN; } @@ -815,8 +808,9 @@ public final class NetworkTemplate implements Parcelable { } // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and // it is not in TelephonyManager#NETWORK_TYPE_* constants. - // See {@link NetworkTemplate#NETWORK_TYPE_5G_NSA}. - collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(NETWORK_TYPE_5G_NSA)); + // See {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. + collapsedRatTypes.add( + NetworkTemplate.getCollapsedRatType(NetworkStatsManager.NETWORK_TYPE_5G_NSA)); // Ensure that unknown type is returned. collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); return toIntArray(collapsedRatTypes); diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 4875f1cf5a..b6c3af5a7b 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -16,7 +16,7 @@ package com.android.server.net; -import static android.net.NetworkTemplate.NETWORK_TYPE_5G_NSA; +import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA; import static android.net.NetworkTemplate.getCollapsedRatType; import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; From 1618171b38eff53ed568ef5164e1dbe683e6292f Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 27 Jan 2022 00:03:41 +0800 Subject: [PATCH 1080/1150] Move the implement of getAllCollapsedRatTypes to StatsPullAtomService To make data usage as a mainline module, move getAllCollapsedRatTypes to StatsPullAtomService since currently it is the only user. Also, the method needs to call getCollapsedRatType, thus move getCollapsedRatType to NetworkStatsManager and expose it as module API. Bug: 210073043 Test: builds, FrameworksNetTests Change-Id: Ibe41b50f173464694c21dd22841552bdb69a6a14 --- .../app/usage/NetworkStatsManager.java | 48 +++++++++++ .../src/android/net/NetworkTemplate.java | 86 +------------------ .../server/net/NetworkStatsService.java | 2 +- .../net/NetworkStatsSubscriptionsMonitor.java | 4 +- 4 files changed, 53 insertions(+), 87 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index d7e513f121..84adef53e4 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -1123,4 +1123,52 @@ public class NetworkStatsManager { throw e.rethrowFromSystemServer(); } } + + /** + * Get a RAT type representative of a group of RAT types for network statistics. + * + * Collapse the given Radio Access Technology (RAT) type into a bucket that + * is representative of the original RAT type for network statistics. The + * mapping mostly corresponds to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*} + * but with adaptations specific to the virtual types introduced by + * networks stats. + * + * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static int getCollapsedRatType(int ratType) { + switch (ratType) { + case TelephonyManager.NETWORK_TYPE_GPRS: + case TelephonyManager.NETWORK_TYPE_GSM: + case TelephonyManager.NETWORK_TYPE_EDGE: + case TelephonyManager.NETWORK_TYPE_IDEN: + case TelephonyManager.NETWORK_TYPE_CDMA: + case TelephonyManager.NETWORK_TYPE_1xRTT: + return TelephonyManager.NETWORK_TYPE_GSM; + case TelephonyManager.NETWORK_TYPE_EVDO_0: + case TelephonyManager.NETWORK_TYPE_EVDO_A: + case TelephonyManager.NETWORK_TYPE_EVDO_B: + case TelephonyManager.NETWORK_TYPE_EHRPD: + case TelephonyManager.NETWORK_TYPE_UMTS: + case TelephonyManager.NETWORK_TYPE_HSDPA: + case TelephonyManager.NETWORK_TYPE_HSUPA: + case TelephonyManager.NETWORK_TYPE_HSPA: + case TelephonyManager.NETWORK_TYPE_HSPAP: + case TelephonyManager.NETWORK_TYPE_TD_SCDMA: + return TelephonyManager.NETWORK_TYPE_UMTS; + case TelephonyManager.NETWORK_TYPE_LTE: + case TelephonyManager.NETWORK_TYPE_IWLAN: + return TelephonyManager.NETWORK_TYPE_LTE; + case TelephonyManager.NETWORK_TYPE_NR: + return TelephonyManager.NETWORK_TYPE_NR; + // Virtual RAT type for 5G NSA mode, see + // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. + case NetworkStatsManager.NETWORK_TYPE_5G_NSA: + return NetworkStatsManager.NETWORK_TYPE_5G_NSA; + default: + return TelephonyManager.NETWORK_TYPE_UNKNOWN; + } + } } diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 649f54b09e..27e717fb59 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -48,7 +48,6 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.telephony.Annotation.NetworkType; -import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.ArraySet; @@ -59,9 +58,7 @@ import com.android.net.module.util.NetworkStatsUtils; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Arrays; -import java.util.Collection; import java.util.Comparator; -import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.Set; @@ -703,7 +700,8 @@ public final class NetworkTemplate implements Parcelable { private boolean matchesCollapsedRatType(NetworkIdentity ident) { return mRatType == NETWORK_TYPE_ALL - || getCollapsedRatType(mRatType) == getCollapsedRatType(ident.mRatType); + || NetworkStatsManager.getCollapsedRatType(mRatType) + == NetworkStatsManager.getCollapsedRatType(ident.mRatType); } /** @@ -746,86 +744,6 @@ public final class NetworkTemplate implements Parcelable { } } - /** - * Get a Radio Access Technology(RAT) type that is representative of a group of RAT types. - * The mapping is corresponding to {@code TelephonyManager#NETWORK_CLASS_BIT_MASK_*}. - * - * @param ratType An integer defined in {@code TelephonyManager#NETWORK_TYPE_*}. - * - * @hide - */ - // TODO: 1. Consider move this to TelephonyManager if used by other modules. - // 2. Consider make this configurable. - // 3. Use TelephonyManager APIs when available. - // TODO: @SystemApi when ready. - public static int getCollapsedRatType(int ratType) { - switch (ratType) { - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_GSM: - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_IDEN: - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_1xRTT: - return TelephonyManager.NETWORK_TYPE_GSM; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - case TelephonyManager.NETWORK_TYPE_EHRPD: - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - case TelephonyManager.NETWORK_TYPE_TD_SCDMA: - return TelephonyManager.NETWORK_TYPE_UMTS; - case TelephonyManager.NETWORK_TYPE_LTE: - case TelephonyManager.NETWORK_TYPE_IWLAN: - return TelephonyManager.NETWORK_TYPE_LTE; - case TelephonyManager.NETWORK_TYPE_NR: - return TelephonyManager.NETWORK_TYPE_NR; - // Virtual RAT type for 5G NSA mode, see - // {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. - case NetworkStatsManager.NETWORK_TYPE_5G_NSA: - return NetworkStatsManager.NETWORK_TYPE_5G_NSA; - default: - return TelephonyManager.NETWORK_TYPE_UNKNOWN; - } - } - - /** - * Return all supported collapsed RAT types that could be returned by - * {@link #getCollapsedRatType(int)}. - * - * @hide - */ - // TODO: @SystemApi when ready. - @NonNull - public static final int[] getAllCollapsedRatTypes() { - final int[] ratTypes = TelephonyManager.getAllNetworkTypes(); - final HashSet collapsedRatTypes = new HashSet<>(); - for (final int ratType : ratTypes) { - collapsedRatTypes.add(NetworkTemplate.getCollapsedRatType(ratType)); - } - // Add NETWORK_TYPE_5G_NSA to the returned list since 5G NSA is a virtual RAT type and - // it is not in TelephonyManager#NETWORK_TYPE_* constants. - // See {@link NetworkStatsManager#NETWORK_TYPE_5G_NSA}. - collapsedRatTypes.add( - NetworkTemplate.getCollapsedRatType(NetworkStatsManager.NETWORK_TYPE_5G_NSA)); - // Ensure that unknown type is returned. - collapsedRatTypes.add(TelephonyManager.NETWORK_TYPE_UNKNOWN); - return toIntArray(collapsedRatTypes); - } - - @NonNull - private static int[] toIntArray(@NonNull Collection list) { - final int[] array = new int[list.size()]; - int i = 0; - for (final Integer item : list) { - array[i++] = item; - } - return array; - } - /** * Check if matches Wi-Fi network template. */ diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 243d621647..5c069e9d40 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -244,7 +244,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { /** * When enabled, all mobile data is reported under {@link NetworkTemplate#NETWORK_TYPE_ALL}. * When disabled, mobile data is broken down by a granular ratType representative of the - * actual ratType. {@see NetworkTemplate#getCollapsedRatType}. + * actual ratType. {@see android.app.usage.NetworkStatsManager#getCollapsedRatType}. * Enabling this decreases the level of detail but saves performance, disk space and * amount of data logged. */ diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index b6c3af5a7b..3e35e603e8 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -17,7 +17,7 @@ package com.android.server.net; import static android.app.usage.NetworkStatsManager.NETWORK_TYPE_5G_NSA; -import static android.net.NetworkTemplate.getCollapsedRatType; +import static android.app.usage.NetworkStatsManager.getCollapsedRatType; import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED; import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA; import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; @@ -57,7 +57,7 @@ public class NetworkStatsSubscriptionsMonitor extends * * @param subscriberId IMSI of the subscription. * @param collapsedRatType collapsed RAT type. - * @see android.net.NetworkTemplate#getCollapsedRatType(int). + * @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int). */ void onCollapsedRatTypeChanged(@NonNull String subscriberId, @Annotation.NetworkType int collapsedRatType); From de9b4def5feecba5d26fa899d97c8f62d2397ab9 Mon Sep 17 00:00:00 2001 From: Frank Date: Thu, 27 Jan 2022 22:15:46 +0800 Subject: [PATCH 1081/1150] [DU12]Remove NetworkType Annotation Bug: 216619447 Test: atest NetworkTemplateTest NetworkStatsCollectionTest NetworkStatsSubscriptionsMonitorTest Change-Id: I58689201a684f581a4b88df058a5e0683da61926 --- framework-t/src/android/net/NetworkIdentity.java | 6 ++---- framework-t/src/android/net/NetworkTemplate.java | 5 ++--- .../server/net/NetworkStatsSubscriptionsMonitor.java | 4 +--- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 73b9c72699..56faa52e82 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -30,7 +30,6 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.wifi.WifiInfo; import android.service.NetworkIdentityProto; -import android.telephony.Annotation; import android.telephony.TelephonyManager; import android.util.proto.ProtoOutputStream; @@ -275,8 +274,7 @@ public class NetworkIdentity { @Deprecated @NonNull public static NetworkIdentity buildNetworkIdentity(Context context, - @NonNull NetworkStateSnapshot snapshot, - boolean defaultNetwork, @Annotation.NetworkType int ratType) { + @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork); if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { @@ -433,7 +431,7 @@ public class NetworkIdentity { * @return this builder. */ @NonNull - public Builder setRatType(@Annotation.NetworkType int ratType) { + public Builder setRatType(int ratType) { if (!CollectionUtils.contains(TelephonyManager.getAllNetworkTypes(), ratType) && ratType != TelephonyManager.NETWORK_TYPE_UNKNOWN && ratType != NetworkStatsManager.NETWORK_TYPE_5G_NSA) { diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 27e717fb59..9b58b016bb 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -47,7 +47,6 @@ import android.net.wifi.WifiInfo; import android.os.Build; import android.os.Parcel; import android.os.Parcelable; -import android.telephony.Annotation.NetworkType; import android.text.TextUtils; import android.util.ArraySet; @@ -203,7 +202,7 @@ public final class NetworkTemplate implements Parcelable { * @hide */ public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId, - @NetworkType int ratType, int metered) { + int ratType, int metered) { if (TextUtils.isEmpty(subscriberId)) { return new NetworkTemplate(MATCH_MOBILE_WILDCARD, null /* subscriberId */, null /* matchSubscriberIds */, @@ -1039,7 +1038,7 @@ public final class NetworkTemplate implements Parcelable { * @return this builder. */ @NonNull - public Builder setRatType(@NetworkType int ratType) { + public Builder setRatType(int ratType) { // Input will be validated with the match rule when building the template. mRatType = ratType; return this; diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 3e35e603e8..5bba0b17aa 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -24,7 +24,6 @@ import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; import android.content.Context; -import android.telephony.Annotation; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; @@ -59,8 +58,7 @@ public class NetworkStatsSubscriptionsMonitor extends * @param collapsedRatType collapsed RAT type. * @see android.app.usage.NetworkStatsManager#getCollapsedRatType(int). */ - void onCollapsedRatTypeChanged(@NonNull String subscriberId, - @Annotation.NetworkType int collapsedRatType); + void onCollapsedRatTypeChanged(@NonNull String subscriberId, int collapsedRatType); } private final Delegate mDelegate; From bf254864a4269d8ab86a12830ea0871555f1fc08 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 27 Jan 2022 15:37:43 +0900 Subject: [PATCH 1082/1150] Clear counters and delete tag data from NetworkStatsService. Currently, NetworkStatsService deletes tag data by calling NetworkManagementSocketTagger, which then calls into libcutils "qtaguid" code. Instead, make NetworkStatsService call into libcutils directly and delete the NetworkManagementSocketTagger code. In the future, this will make it easier for NetworkStatsService to perform this operation by calling directly into BpfNetMaps. Because the unit test does not yet have working JNI code, provide an internal TagStatsDeleter interface that can be mocked out via the Dependencies class. This is a bit ugly but it will be deleted as soon as the code uses BpfNetMaps directly. Delete NetworkManagementSocketTagger#setKernelCounterSet since it was replaced in aosp/1958917. Also remove unused includes and make formatting changes suggested by clang-format. Test: m Test: atest NetworkStatsServiceTest Test: atest NetworkUsageStatsTest Test: atest TrafficStatsTest Test: stats deleted when CtsUsageStatsTestCases completes and test APK is uninstalled Change-Id: I62987000afc185199821580232bfb7668c8e301e --- .../server/net/NetworkStatsService.java | 19 +++++++++++++++++-- ...android_server_net_NetworkStatsService.cpp | 15 +++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 8e584d084f..748b0ae020 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -59,7 +59,6 @@ import static android.text.format.DateUtils.SECOND_IN_MILLIS; import static com.android.net.module.util.NetworkCapabilitiesUtils.getDisplayTransport; import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; -import static com.android.server.NetworkManagementSocketTagger.resetKernelUidStats; import android.annotation.NonNull; import android.annotation.Nullable; @@ -121,6 +120,7 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.system.ErrnoException; +import android.system.Os; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; import android.text.TextUtils; @@ -546,6 +546,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return null; } } + + public TagStatsDeleter getTagStatsDeleter() { + return NetworkStatsService::nativeDeleteTagData; + } } /** @@ -1801,7 +1805,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Clear kernel stats associated with UID for (int uid : uids) { - resetKernelUidStats(uid); + final int ret = mDeps.getTagStatsDeleter().deleteTagData(uid); + if (ret < 0) { + Log.w(TAG, "problem clearing counters for uid " + uid + ": " + Os.strerror(-ret)); + } } } @@ -2380,4 +2387,12 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); + + // TODO: use BpfNetMaps to delete tag data and remove this. + @VisibleForTesting + interface TagStatsDeleter { + int deleteTagData(int uid); + } + + private static native int nativeDeleteTagData(int uid); } diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index 5178132e4a..f8a81682bd 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -16,20 +16,18 @@ #define LOG_TAG "NetworkStatsNative" +#include #include #include #include #include -#include -#include - -#include "core_jni_helpers.h" #include #include -#include +#include +#include #include +#include -#include "android-base/unique_fd.h" #include "bpf/BpfUtils.h" #include "netdbpf/BpfNetworkStats.h" @@ -104,10 +102,15 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } +static int deleteTagData(JNIEnv* /* env */, jclass /* clazz */, jint uid) { + return qtaguid_deleteTagData(0, uid); +} + static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*)getUidStat}, + {"nativeDeleteTagData", "(I)I", (void*)deleteTagData}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { From aa6eed54a74396e0d53c4168aff67e02020c02db Mon Sep 17 00:00:00 2001 From: junyulai Date: Fri, 28 Jan 2022 09:53:45 +0800 Subject: [PATCH 1083/1150] [MS59.3] Expose NetworkStatsDataMigrationUtils Test: TH Bug: 204830222 Change-Id: I15a45fbadeb69b70a0e983b00de9e934d29749d6 --- .../src/android/app/usage/NetworkStatsManager.java | 12 ++++-------- .../com/android/server/net/NetworkStatsService.java | 6 +++--- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 84adef53e4..5ce7e59b38 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -41,6 +41,7 @@ import android.net.NetworkStateSnapshot; import android.net.NetworkTemplate; import android.net.UnderlyingNetworkInfo; import android.net.netstats.IUsageCallback; +import android.net.netstats.NetworkStatsDataMigrationUtils; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Build; @@ -126,17 +127,12 @@ public class NetworkStatsManager { private final INetworkStatsService mService; /** - * Type constants for reading different types of Data Usage. + * @deprecated Use {@link NetworkStatsDataMigrationUtils#PREFIX_XT} + * instead. * @hide */ - // @SystemApi(client = MODULE_LIBRARIES) + @Deprecated public static final String PREFIX_DEV = "dev"; - /** @hide */ - public static final String PREFIX_XT = "xt"; - /** @hide */ - public static final String PREFIX_UID = "uid"; - /** @hide */ - public static final String PREFIX_UID_TAG = "uid_tag"; /** @hide */ public static final int FLAG_POLL_ON_OPEN = 1 << 0; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 8e584d084f..3abb64fce1 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -20,9 +20,6 @@ import static android.Manifest.permission.NETWORK_STATS_PROVIDER; import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY; import static android.Manifest.permission.UPDATE_DEVICE_STATS; import static android.app.usage.NetworkStatsManager.PREFIX_DEV; -import static android.app.usage.NetworkStatsManager.PREFIX_UID; -import static android.app.usage.NetworkStatsManager.PREFIX_UID_TAG; -import static android.app.usage.NetworkStatsManager.PREFIX_XT; import static android.content.Intent.ACTION_SHUTDOWN; import static android.content.Intent.ACTION_UID_REMOVED; import static android.content.Intent.ACTION_USER_REMOVED; @@ -50,6 +47,9 @@ import static android.net.TrafficStats.KB_IN_BYTES; import static android.net.TrafficStats.MB_IN_BYTES; import static android.net.TrafficStats.UID_TETHERING; import static android.net.TrafficStats.UNSUPPORTED; +import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; +import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; +import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; import static android.os.Trace.TRACE_TAG_NETWORK; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; From adab7b1cc3ba4da747e37388f094a77214c31772 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 29 Jan 2022 21:37:59 +0900 Subject: [PATCH 1084/1150] Move kernelToTag to NetworkStatsFactory. ... to prepare for the deletion of NetworkManagementSocketTagger. Test: atest FrameworksNetTests Change-Id: Id3ad67fa640ddb9ab446e10dcf8e6a588d661dd9 --- .../android/server/net/NetworkStatsFactory.java | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index 17f3455d20..668d1cba92 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -22,8 +22,6 @@ import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; import static android.net.NetworkStats.UID_ALL; -import static com.android.server.NetworkManagementSocketTagger.kernelToTag; - import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -469,6 +467,19 @@ public class NetworkStatsFactory { } } + /** + * Convert {@code /proc/} tag format to {@link Integer}. Assumes incoming + * format like {@code 0x7fffffff00000000}. + */ + public static int kernelToTag(String string) { + int length = string.length(); + if (length > 10) { + return Long.decode(string.substring(0, length - 8)).intValue(); + } else { + return 0; + } + } + /** * Parse statistics from file into given {@link NetworkStats} object. Values * are expected to monotonically increase since device boot. From 81b707f491e12a89df456bf232ac3b3d6e35f83b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 29 Jan 2022 21:07:33 +0900 Subject: [PATCH 1085/1150] Move socket tagging implementation to mainline. Currently, socket tagging is implemented in the framework. The Java code is in NetworkManagmentSocketTagger.java and the JNI is in libandroid and loaded by the general framework JNI loader. - Move the Java implementation to TrafficStats, which is the only caller of NetworkManagmentSocketTagger. This simplifies the code a bit because a number of methods can be deleted. - Move the JNI code to a new JNI library in the APEX. The library depends only on the NDK and statically links the NDK-only version of libnativehelper. Its size is only 5k on ARM and 10k on ARM64. - Temporarily make the framework depend on this library until the rest of the T connectivity code moves to the APEX. Test: atest NetworkUsageStatsTest CtsNetTestCases:TrafficStatsTest Change-Id: I050c7c515237f68b78d08987bc443f50a7949c06 --- framework-t/Sources.bp | 32 ++++++- framework-t/jni/android_net_TrafficStats.cpp | 46 ++++++++++ framework-t/jni/onload.cpp | 39 +++++++++ framework-t/src/android/net/TrafficStats.java | 86 ++++++++++++++++--- 4 files changed, 190 insertions(+), 13 deletions(-) create mode 100644 framework-t/jni/android_net_TrafficStats.cpp create mode 100644 framework-t/jni/onload.cpp diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 223bdcdd9c..327b1fb2f5 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -39,7 +39,6 @@ filegroup { "src/android/net/TrafficStats.java", "src/android/net/UnderlyingNetworkInfo.*", "src/android/net/netstats/**/*.*", - "src/com/android/server/NetworkManagementSocketTagger.java", ], path: "src", visibility: [ @@ -176,3 +175,34 @@ filegroup { "//packages/modules/Connectivity:__subpackages__", ], } + +cc_library_shared { + name: "libframework-connectivity-tiramisu-jni", + min_sdk_version: "30", + cflags: [ + "-Wall", + "-Werror", + "-Wno-unused-parameter", + // Don't warn about S API usage even with + // min_sdk 30: the library is only loaded + // on S+ devices + "-Wno-unguarded-availability", + "-Wthread-safety", + ], + srcs: [ + "jni/android_net_TrafficStats.cpp", + "jni/onload.cpp", + ], + shared_libs: [ + "liblog", + ], + static_libs: [ + "libnativehelper_compat_libc++", + ], + stl: "none", + apex_available: [ + "com.android.tethering", + // TODO: remove when ConnectivityT moves to APEX. + "//apex_available:platform", + ], +} diff --git a/framework-t/jni/android_net_TrafficStats.cpp b/framework-t/jni/android_net_TrafficStats.cpp new file mode 100644 index 0000000000..f3c58b112f --- /dev/null +++ b/framework-t/jni/android_net_TrafficStats.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +namespace android { + +static jint tagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor, jint tag, jint uid) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_tag_socket_with_uid(fd, tag, uid); +} + +static jint untagSocketFd(JNIEnv* env, jclass, jobject fileDescriptor) { + int fd = AFileDescriptor_getFd(env, fileDescriptor); + if (fd == -1) return -EBADF; + return android_untag_socket(fd); +} + +static const JNINativeMethod gMethods[] = { + /* name, signature, funcPtr */ + { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*) tagSocketFd }, + { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*) untagSocketFd }, +}; + +int register_android_net_TrafficStats(JNIEnv* env) { + return jniRegisterNativeMethods(env, "android/net/TrafficStats", gMethods, NELEM(gMethods)); +} + +}; // namespace android + diff --git a/framework-t/jni/onload.cpp b/framework-t/jni/onload.cpp new file mode 100644 index 0000000000..1fb42c6347 --- /dev/null +++ b/framework-t/jni/onload.cpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "FrameworkConnectivityJNI" + +#include +#include + +namespace android { + +int register_android_net_TrafficStats(JNIEnv* env); + +extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { + JNIEnv *env; + if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { + __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed"); + return JNI_ERR; + } + + if (register_android_net_TrafficStats(env) < 0) return JNI_ERR; + + return JNI_VERSION_1_6; +} + +}; // namespace android + diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index c2f0cdfb04..bc836d857e 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -31,12 +31,9 @@ import android.media.MediaPlayer; import android.os.Binder; import android.os.Build; import android.os.RemoteException; +import android.os.StrictMode; import android.util.Log; -import com.android.server.NetworkManagementSocketTagger; - -import dalvik.system.SocketTagger; - import java.io.FileDescriptor; import java.io.IOException; import java.net.DatagramSocket; @@ -56,6 +53,10 @@ import java.net.SocketException; * use {@link NetworkStatsManager} instead. */ public class TrafficStats { + static { + System.loadLibrary("framework-connectivity-tiramisu-jni"); + } + private static final String TAG = TrafficStats.class.getSimpleName(); /** * The return value to indicate that the device does not support the statistic. @@ -232,9 +233,68 @@ public class TrafficStats { */ @SystemApi(client = MODULE_LIBRARIES) public static void attachSocketTagger() { - NetworkManagementSocketTagger.install(); + dalvik.system.SocketTagger.set(new SocketTagger()); } + private static class SocketTagger extends dalvik.system.SocketTagger { + + // TODO: set to false + private static final boolean LOGD = true; + + SocketTagger() { + } + + @Override + public void tag(FileDescriptor fd) throws SocketException { + final UidTag tagInfo = sThreadUidTag.get(); + if (LOGD) { + Log.d(TAG, "tagSocket(" + fd.getInt$() + ") with statsTag=0x" + + Integer.toHexString(tagInfo.tag) + ", statsUid=" + tagInfo.uid); + } + if (tagInfo.tag == -1) { + StrictMode.noteUntaggedSocket(); + } + + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + final int errno = native_tagSocketFd(fd, tagInfo.tag, tagInfo.uid); + if (errno < 0) { + Log.i(TAG, "tagSocketFd(" + fd.getInt$() + ", " + + tagInfo.tag + ", " + + tagInfo.uid + ") failed with errno" + errno); + } + } + + @Override + public void untag(FileDescriptor fd) throws SocketException { + if (LOGD) { + Log.i(TAG, "untagSocket(" + fd.getInt$() + ")"); + } + + final UidTag tagInfo = sThreadUidTag.get(); + if (tagInfo.tag == -1 && tagInfo.uid == -1) return; + + final int errno = native_untagSocketFd(fd); + if (errno < 0) { + Log.w(TAG, "untagSocket(" + fd.getInt$() + ") failed with errno " + errno); + } + } + } + + private static native int native_tagSocketFd(FileDescriptor fd, int tag, int uid); + private static native int native_untagSocketFd(FileDescriptor fd); + + private static class UidTag { + public int tag = -1; + public int uid = -1; + } + + private static ThreadLocal sThreadUidTag = new ThreadLocal() { + @Override + protected UidTag initialValue() { + return new UidTag(); + } + }; + /** * Set active tag to use when accounting {@link Socket} traffic originating * from the current thread. Only one active tag per thread is supported. @@ -249,7 +309,7 @@ public class TrafficStats { * @see #clearThreadStatsTag() */ public static void setThreadStatsTag(int tag) { - NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + getAndSetThreadStatsTag(tag); } /** @@ -267,7 +327,9 @@ public class TrafficStats { * restore any existing values after a nested operation is finished */ public static int getAndSetThreadStatsTag(int tag) { - return NetworkManagementSocketTagger.setThreadSocketStatsTag(tag); + final int old = sThreadUidTag.get().tag; + sThreadUidTag.get().tag = tag; + return old; } /** @@ -327,7 +389,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static int getThreadStatsTag() { - return NetworkManagementSocketTagger.getThreadSocketStatsTag(); + return sThreadUidTag.get().tag; } /** @@ -337,7 +399,7 @@ public class TrafficStats { * @see #setThreadStatsTag(int) */ public static void clearThreadStatsTag() { - NetworkManagementSocketTagger.setThreadSocketStatsTag(-1); + sThreadUidTag.get().tag = -1; } /** @@ -357,7 +419,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void setThreadStatsUid(int uid) { - NetworkManagementSocketTagger.setThreadSocketStatsUid(uid); + sThreadUidTag.get().uid = uid; } /** @@ -368,7 +430,7 @@ public class TrafficStats { * @see #setThreadStatsUid(int) */ public static int getThreadStatsUid() { - return NetworkManagementSocketTagger.getThreadSocketStatsUid(); + return sThreadUidTag.get().uid; } /** @@ -395,7 +457,7 @@ public class TrafficStats { */ @SuppressLint("RequiresPermission") public static void clearThreadStatsUid() { - NetworkManagementSocketTagger.setThreadSocketStatsUid(-1); + setThreadStatsUid(-1); } /** From aeb8a06c236e799a187d92e6f5270a1adec169f2 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Mon, 17 Jan 2022 15:43:10 -0800 Subject: [PATCH 1086/1150] InternalNetworkManagementException Changes Update to InternalNetworkManagementException in order to allow all members to be parcelable. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I17f119a66face8a927546657490969aa3073c54b --- .../InternalNetworkManagementException.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/framework-t/src/android/net/InternalNetworkManagementException.java b/framework-t/src/android/net/InternalNetworkManagementException.java index 7f4e403f22..798e9c3b52 100644 --- a/framework-t/src/android/net/InternalNetworkManagementException.java +++ b/framework-t/src/android/net/InternalNetworkManagementException.java @@ -20,22 +20,34 @@ import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; +import java.util.Objects; + /** @hide */ public final class InternalNetworkManagementException extends RuntimeException implements Parcelable { /* @hide */ - public InternalNetworkManagementException(@NonNull final Throwable t) { - super(t); + public InternalNetworkManagementException(@NonNull final String errorMessage) { + super(errorMessage); } - private InternalNetworkManagementException(@NonNull final Parcel source) { - super(source.readString()); + @Override + public int hashCode() { + return Objects.hash(getMessage()); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + final InternalNetworkManagementException that = (InternalNetworkManagementException) obj; + + return Objects.equals(getMessage(), that.getMessage()); } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(getCause().getMessage()); + dest.writeString(getMessage()); } @Override @@ -53,7 +65,7 @@ public final class InternalNetworkManagementException @Override public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new InternalNetworkManagementException(source); + return new InternalNetworkManagementException(source.readString()); } }; } From a46242b7ab47621f0d4100e591aab38c179195ed Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 28 Jan 2022 13:42:38 -0800 Subject: [PATCH 1087/1150] Renaming Ethernet Network Management Classes Renaming InternalNetwork* files and classes related to ethernet network management to EthernetNetwork* as ethernet is the only trasnport these particular files are used with. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Ieb3915c032ef5fcd6b36eb09878119de7668bb4b --- framework-t/Sources.bp | 10 ++++---- .../src/android/net/EthernetManager.java | 18 ++++++------- ...> EthernetNetworkManagementException.aidl} | 2 +- ...> EthernetNetworkManagementException.java} | 18 ++++++------- ...aidl => EthernetNetworkUpdateRequest.aidl} | 2 +- ...java => EthernetNetworkUpdateRequest.java} | 22 ++++++++-------- .../src/android/net/IEthernetManager.aidl | 12 ++++----- .../IEthernetNetworkManagementListener.aidl | 25 +++++++++++++++++++ 8 files changed, 67 insertions(+), 42 deletions(-) rename framework-t/src/android/net/{InternalNetworkManagementException.aidl => EthernetNetworkManagementException.aidl} (93%) rename framework-t/src/android/net/{InternalNetworkManagementException.java => EthernetNetworkManagementException.java} (73%) rename framework-t/src/android/net/{InternalNetworkUpdateRequest.aidl => EthernetNetworkUpdateRequest.aidl} (94%) rename framework-t/src/android/net/{InternalNetworkUpdateRequest.java => EthernetNetworkUpdateRequest.java} (80%) create mode 100644 framework-t/src/android/net/IEthernetNetworkManagementListener.aidl diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 327b1fb2f5..54538d91a5 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -125,14 +125,14 @@ filegroup { name: "framework-connectivity-ethernet-sources", srcs: [ "src/android/net/EthernetManager.java", + "src/android/net/EthernetNetworkManagementException.java", + "src/android/net/EthernetNetworkManagementException.aidl", "src/android/net/EthernetNetworkSpecifier.java", + "src/android/net/EthernetNetworkUpdateRequest.java", + "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/IInternalNetworkManagementListener.aidl", - "src/android/net/InternalNetworkUpdateRequest.java", - "src/android/net/InternalNetworkUpdateRequest.aidl", - "src/android/net/InternalNetworkManagementException.java", - "src/android/net/InternalNetworkManagementException.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index ece54df966..f472d563c4 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -320,15 +320,15 @@ public class EthernetManager { } private static final class InternalNetworkManagementListener - extends IInternalNetworkManagementListener.Stub { + extends IEthernetNetworkManagementListener.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer mListener; + private final BiConsumer mListener; InternalNetworkManagementListener( @NonNull final Executor executor, - @NonNull final BiConsumer listener) { + @NonNull final BiConsumer listener) { Objects.requireNonNull(executor, "Pass a non-null executor"); Objects.requireNonNull(listener, "Pass a non-null listener"); mExecutor = executor; @@ -338,14 +338,14 @@ public class EthernetManager { @Override public void onComplete( @Nullable final Network network, - @Nullable final InternalNetworkManagementException e) { + @Nullable final EthernetNetworkManagementException e) { mExecutor.execute(() -> mListener.accept(network, e)); } } private InternalNetworkManagementListener getInternalNetworkManagementListener( @Nullable final Executor executor, - @Nullable final BiConsumer listener) { + @Nullable final BiConsumer listener) { if (null != listener) { Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); } @@ -360,9 +360,9 @@ public class EthernetManager { private void updateConfiguration( @NonNull String iface, - @NonNull InternalNetworkUpdateRequest request, + @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable BiConsumer listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -375,7 +375,7 @@ public class EthernetManager { private void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable BiConsumer listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -388,7 +388,7 @@ public class EthernetManager { private void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable BiConsumer listener) { final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { diff --git a/framework-t/src/android/net/InternalNetworkManagementException.aidl b/framework-t/src/android/net/EthernetNetworkManagementException.aidl similarity index 93% rename from framework-t/src/android/net/InternalNetworkManagementException.aidl rename to framework-t/src/android/net/EthernetNetworkManagementException.aidl index dcce706989..adf9e5a4db 100644 --- a/framework-t/src/android/net/InternalNetworkManagementException.aidl +++ b/framework-t/src/android/net/EthernetNetworkManagementException.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkManagementException; \ No newline at end of file + parcelable EthernetNetworkManagementException; \ No newline at end of file diff --git a/framework-t/src/android/net/InternalNetworkManagementException.java b/framework-t/src/android/net/EthernetNetworkManagementException.java similarity index 73% rename from framework-t/src/android/net/InternalNetworkManagementException.java rename to framework-t/src/android/net/EthernetNetworkManagementException.java index 798e9c3b52..a35f28e172 100644 --- a/framework-t/src/android/net/InternalNetworkManagementException.java +++ b/framework-t/src/android/net/EthernetNetworkManagementException.java @@ -23,11 +23,11 @@ import android.os.Parcelable; import java.util.Objects; /** @hide */ -public final class InternalNetworkManagementException +public final class EthernetNetworkManagementException extends RuntimeException implements Parcelable { /* @hide */ - public InternalNetworkManagementException(@NonNull final String errorMessage) { + public EthernetNetworkManagementException(@NonNull final String errorMessage) { super(errorMessage); } @@ -40,7 +40,7 @@ public final class InternalNetworkManagementException public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; - final InternalNetworkManagementException that = (InternalNetworkManagementException) obj; + final EthernetNetworkManagementException that = (EthernetNetworkManagementException) obj; return Objects.equals(getMessage(), that.getMessage()); } @@ -56,16 +56,16 @@ public final class InternalNetworkManagementException } @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { @Override - public InternalNetworkManagementException[] newArray(int size) { - return new InternalNetworkManagementException[size]; + public EthernetNetworkManagementException[] newArray(int size) { + return new EthernetNetworkManagementException[size]; } @Override - public InternalNetworkManagementException createFromParcel(@NonNull Parcel source) { - return new InternalNetworkManagementException(source.readString()); + public EthernetNetworkManagementException createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkManagementException(source.readString()); } }; } diff --git a/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl b/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl similarity index 94% rename from framework-t/src/android/net/InternalNetworkUpdateRequest.aidl rename to framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl index da00cb97af..debc348ea3 100644 --- a/framework-t/src/android/net/InternalNetworkUpdateRequest.aidl +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.aidl @@ -16,4 +16,4 @@ package android.net; - parcelable InternalNetworkUpdateRequest; \ No newline at end of file + parcelable EthernetNetworkUpdateRequest; \ No newline at end of file diff --git a/framework-t/src/android/net/InternalNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java similarity index 80% rename from framework-t/src/android/net/InternalNetworkUpdateRequest.java rename to framework-t/src/android/net/EthernetNetworkUpdateRequest.java index f42c4b7c42..4d229d23b1 100644 --- a/framework-t/src/android/net/InternalNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -23,7 +23,7 @@ import android.os.Parcelable; import java.util.Objects; /** @hide */ -public final class InternalNetworkUpdateRequest implements Parcelable { +public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull private final StaticIpConfiguration mIpConfig; @NonNull @@ -40,7 +40,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { } /** @hide */ - public InternalNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); Objects.requireNonNull(networkCapabilities); @@ -48,7 +48,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } - private InternalNetworkUpdateRequest(@NonNull final Parcel source) { + private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); @@ -56,7 +56,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { @Override public String toString() { - return "InternalNetworkUpdateRequest{" + return "EthernetNetworkUpdateRequest{" + "mIpConfig=" + mIpConfig + ", mNetworkCapabilities=" + mNetworkCapabilities + '}'; } @@ -65,7 +65,7 @@ public final class InternalNetworkUpdateRequest implements Parcelable { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - InternalNetworkUpdateRequest that = (InternalNetworkUpdateRequest) o; + EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; return Objects.equals(that.getIpConfig(), mIpConfig) && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); @@ -88,16 +88,16 @@ public final class InternalNetworkUpdateRequest implements Parcelable { } @NonNull - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { @Override - public InternalNetworkUpdateRequest[] newArray(int size) { - return new InternalNetworkUpdateRequest[size]; + public EthernetNetworkUpdateRequest[] newArray(int size) { + return new EthernetNetworkUpdateRequest[size]; } @Override - public InternalNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { - return new InternalNetworkUpdateRequest(source); + public EthernetNetworkUpdateRequest createFromParcel(@NonNull Parcel source) { + return new EthernetNetworkUpdateRequest(source); } }; } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index e688bea1cf..544d02ba76 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,8 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IInternalNetworkManagementListener; -import android.net.InternalNetworkUpdateRequest; +import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkUpdateRequest; import android.net.ITetheredInterfaceCallback; /** @@ -38,8 +38,8 @@ interface IEthernetManager void setIncludeTestInterfaces(boolean include); void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); - void updateConfiguration(String iface, in InternalNetworkUpdateRequest request, - in IInternalNetworkManagementListener listener); - void connectNetwork(String iface, in IInternalNetworkManagementListener listener); - void disconnectNetwork(String iface, in IInternalNetworkManagementListener listener); + void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, + in IEthernetNetworkManagementListener listener); + void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); + void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); } diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl new file mode 100644 index 0000000000..93edccfdaf --- /dev/null +++ b/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2021, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net; + +import android.net.EthernetNetworkManagementException; +import android.net.Network; + +/** @hide */ +oneway interface IEthernetNetworkManagementListener { + void onComplete(in Network network, in EthernetNetworkManagementException exception); +} \ No newline at end of file From 271548c96d50944cc93405e6b30605bbef1dece9 Mon Sep 17 00:00:00 2001 From: hepengtao Date: Tue, 19 Oct 2021 17:25:50 +0800 Subject: [PATCH 1088/1150] NSD: Specify on what interface to getAddrInfo When discover two different host with same host name from different network interface, specify on what interface to getAddrInfo. Bug: 203453164 Test: build & manual Signed-off-by: hepengtao Change-Id: Ifaccb7f3fac6b1dd789cc9ce7c8d964102754508 --- service-t/src/com/android/server/NsdService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java index 497107dbf9..eca4ccf680 100644 --- a/service-t/src/com/android/server/NsdService.java +++ b/service-t/src/com/android/server/NsdService.java @@ -488,7 +488,7 @@ public class NsdService extends INsdManager.Stub { removeRequestMap(clientId, id, clientInfo); int id2 = getUniqueId(); - if (getAddrInfo(id2, cooked[3])) { + if (getAddrInfo(id2, cooked[3], cooked[7])) { storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.onResolveServiceFailed( @@ -833,8 +833,8 @@ public class NsdService extends INsdManager.Stub { return mDaemon.execute("stop-resolve", resolveId); } - private boolean getAddrInfo(int resolveId, String hostname) { - return mDaemon.execute("getaddrinfo", resolveId, hostname); + private boolean getAddrInfo(int resolveId, String hostname, String interfaceName) { + return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceName); } private boolean stopGetAddrInfo(int resolveId) { From 74a5a70b6f4c068400c6ac25babfc354c5e61a08 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 28 Jan 2022 19:43:48 -0800 Subject: [PATCH 1089/1150] Adding permission for Ethernet Network Management Adding MANAGE_ETHERNET_NETWORKS as a signature level permission to allow an application to dynamically change ethernet network values. Bug: 210485380 Test: atest EthernetServiceTests Change-Id: Icf9c2accc86735cc981adc0d5a24802e0616ffaf Merged-In: Icf9c2accc86735cc981adc0d5a24802e0616ffaf --- framework-t/src/android/net/EthernetManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index f472d563c4..e0ce081c02 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -358,6 +358,7 @@ public class EthernetManager { return proxy; } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void updateConfiguration( @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @@ -372,6 +373,7 @@ public class EthernetManager { } } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @@ -385,6 +387,7 @@ public class EthernetManager { } } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, From 131a8663843fced7b44234bddc93759e56c29344 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 12 Jan 2022 15:11:01 +0800 Subject: [PATCH 1090/1150] Split out the ipsec API surface and use framework-connectivity-tiramisu Bug: 204153604 Test: TH Change-Id: I6cc8aef6a0ab9ce4bcef2797196b1d1b3687acca --- framework-t/Sources.bp | 2 +- ...nectivityFrameworkInitializerTiramisu.java | 9 ++++++ service-t/Sources.bp | 2 +- .../src/com/android/server/IpSecService.java | 29 +------------------ 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 54538d91a5..6329565ca5 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -158,7 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], @@ -167,6 +166,7 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ipsec-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 630f902ecf..577ac54666 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -48,5 +48,14 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NsdManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.IPSEC_SERVICE, + IpSecManager.class, + (context, serviceBinder) -> { + IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder); + return new IpSecManager(context, service); + } + ); } } diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 24bc91d91e..d2d6ef0cbb 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -83,7 +83,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ], path: "src", @@ -93,6 +92,7 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ipsec-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index 179d9459fd..4bc40eae44 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -1008,16 +1008,10 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { + public IpSecService(Context context) { this(context, new Dependencies()); } - static IpSecService create(Context context) - throws InterruptedException { - final IpSecService service = new IpSecService(context); - return service; - } - @NonNull private AppOpsManager getAppOpsManager() { AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); @@ -1054,26 +1048,6 @@ public class IpSecService extends IIpSecService.Stub { } } - /** Called by system server when system is ready. */ - public void systemReady() { - if (isNetdAlive()) { - Log.d(TAG, "IpSecService is ready"); - } else { - Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); - } - } - - synchronized boolean isNetdAlive() { - try { - if (mNetd == null) { - return false; - } - return mNetd.isAlive(); - } catch (RemoteException re) { - return false; - } - } - /** * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. @@ -1896,7 +1870,6 @@ public class IpSecService extends IIpSecService.Stub { mContext.enforceCallingOrSelfPermission(DUMP, TAG); pw.println("IpSecService dump:"); - pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); pw.println("mUserResourceTracker:"); From 8def1329832cb7ea921f8d276d40c72f2b8b1de0 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Fri, 28 Jan 2022 19:43:48 -0800 Subject: [PATCH 1091/1150] Adding permission for Ethernet Network Management Adding MANAGE_ETHERNET_NETWORKS as a signature level permission to allow an application to dynamically change ethernet network values. Bug: 210485380 Test: atest EthernetServiceTests cherry pick of aosp/1964543 Change-Id: Icf9c2accc86735cc981adc0d5a24802e0616ffaf --- framework-t/src/android/net/EthernetManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index ece54df966..77f18e3242 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -358,6 +358,7 @@ public class EthernetManager { return proxy; } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void updateConfiguration( @NonNull String iface, @NonNull InternalNetworkUpdateRequest request, @@ -372,6 +373,7 @@ public class EthernetManager { } } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @@ -385,6 +387,7 @@ public class EthernetManager { } } + @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) private void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, From bca7618ded9d6b97fd04011ff59220c065584859 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 16 Dec 2021 15:31:16 +0900 Subject: [PATCH 1092/1150] Support discover/resolve on specific networks This adds a Network member to NsdServiceInfo, allowing discovered services to report which network they were discovered on, and clients to specify which network to resolve the service on. If clients use the discovered NsdServiceInfo to resolve a service, it will be resolved on the network where it was discovered instead of an unspecified network. Also add a network parameter to a new overload of NsdManager#discoverServices, so that clients can discover on specific networks. Bug: 190249673 Test: atest NsdManagerTest Change-Id: Idc4bf9fde0f4b0328204a8cd2eedc12fffbbbdba --- .../src/android/net/nsd/NsdManager.java | 16 ++- .../src/android/net/nsd/NsdServiceInfo.java | 39 ++++- .../src/com/android/server/NsdService.java | 134 ++++++++++++++++-- 3 files changed, 167 insertions(+), 22 deletions(-) diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index 0f21e55b9f..ea69e092c4 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java @@ -16,6 +16,8 @@ package android.net.nsd; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -23,6 +25,7 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; +import android.net.Network; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; @@ -633,6 +636,14 @@ public final class NsdManager { } } + /** + * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null + * {@link Network}. + */ + public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { + discoverServices(serviceType, protocolType, null, listener); + } + /** * Initiate service discovery to browse for instances of a service type. Service discovery * consumes network bandwidth and will continue until the application calls @@ -657,11 +668,13 @@ public final class NsdManager { * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers * @param protocolType The service discovery protocol + * @param network Network to discover services on, or null to discover on all available networks * @param listener The listener notifies of a successful discovery and is used * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. * Cannot be null. Cannot be in use for an active service discovery. */ - public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { + public void discoverServices(@NonNull String serviceType, int protocolType, + @Nullable Network network, @NonNull DiscoveryListener listener) { if (TextUtils.isEmpty(serviceType)) { throw new IllegalArgumentException("Service type cannot be empty"); } @@ -669,6 +682,7 @@ public final class NsdManager { NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); + s.setNetwork(network); int key = putListener(listener, s); try { diff --git a/framework-t/src/android/net/nsd/NsdServiceInfo.java b/framework-t/src/android/net/nsd/NsdServiceInfo.java index 0946499f16..8506db1fbe 100644 --- a/framework-t/src/android/net/nsd/NsdServiceInfo.java +++ b/framework-t/src/android/net/nsd/NsdServiceInfo.java @@ -17,7 +17,9 @@ package android.net.nsd; import android.annotation.NonNull; +import android.annotation.Nullable; import android.compat.annotation.UnsupportedAppUsage; +import android.net.Network; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -49,6 +51,9 @@ public final class NsdServiceInfo implements Parcelable { private int mPort; + @Nullable + private Network mNetwork; + public NsdServiceInfo() { } @@ -307,18 +312,37 @@ public final class NsdServiceInfo implements Parcelable { return txtRecord; } - public String toString() { - StringBuffer sb = new StringBuffer(); + /** + * Get the network where the service can be found. + * + * This is never null if this {@link NsdServiceInfo} was obtained from + * {@link NsdManager#discoverServices} or {@link NsdManager#resolveService}. + */ + @Nullable + public Network getNetwork() { + return mNetwork; + } + /** + * Set the network where the service can be found. + * @param network The network, or null to search for, or to announce, the service on all + * connected networks. + */ + public void setNetwork(@Nullable Network network) { + mNetwork = network; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); sb.append("name: ").append(mServiceName) .append(", type: ").append(mServiceType) .append(", host: ").append(mHost) - .append(", port: ").append(mPort); + .append(", port: ").append(mPort) + .append(", network: ").append(mNetwork); byte[] txtRecord = getTxtRecord(); - if (txtRecord != null) { - sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); - } + sb.append(", txtRecord: ").append(new String(txtRecord, StandardCharsets.UTF_8)); return sb.toString(); } @@ -352,6 +376,8 @@ public final class NsdServiceInfo implements Parcelable { } dest.writeString(key); } + + dest.writeParcelable(mNetwork, 0); } /** Implement the Parcelable interface */ @@ -381,6 +407,7 @@ public final class NsdServiceInfo implements Parcelable { } info.mTxtRecord.put(in.readString(), valueArray); } + info.mNetwork = in.readParcelable(null, Network.class); return info; } diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java index eca4ccf680..ddf6d2c4ab 100644 --- a/service-t/src/com/android/server/NsdService.java +++ b/service-t/src/com/android/server/NsdService.java @@ -19,6 +19,9 @@ package com.android.server; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.net.ConnectivityManager; +import android.net.LinkProperties; +import android.net.Network; import android.net.nsd.INsdManager; import android.net.nsd.INsdManagerCallback; import android.net.nsd.INsdServiceConnector; @@ -44,6 +47,9 @@ import com.android.net.module.util.DnsSdTxtRecord; import java.io.FileDescriptor; import java.io.PrintWriter; import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; import java.util.Arrays; import java.util.HashMap; import java.util.concurrent.CountDownLatch; @@ -60,6 +66,7 @@ public class NsdService extends INsdManager.Stub { private static final boolean DBG = true; private static final long CLEANUP_DELAY_MS = 10000; + private static final int IFACE_IDX_ANY = 0; private final Context mContext; private final NsdStateMachine mNsdStateMachine; @@ -297,7 +304,7 @@ public class NsdService extends INsdManager.Stub { maybeStartDaemon(); id = getUniqueId(); - if (discoverServices(id, args.serviceInfo.getServiceType())) { + if (discoverServices(id, args.serviceInfo)) { if (DBG) { Log.d(TAG, "Discover " + msg.arg2 + " " + id + args.serviceInfo.getServiceType()); @@ -430,13 +437,38 @@ public class NsdService extends INsdManager.Stub { } switch (code) { case NativeResponseCode.SERVICE_FOUND: - /* NNN uniqueId serviceName regType domain */ + /* NNN uniqueId serviceName regType domain interfaceIdx netId */ servInfo = new NsdServiceInfo(cooked[2], cooked[3]); + final int foundNetId; + try { + foundNetId = Integer.parseInt(cooked[6]); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); + break; + } + if (foundNetId == 0L) { + // Ignore services that do not have a Network: they are not usable + // by apps, as they would need privileged permissions to use + // interfaces that do not have an associated Network. + break; + } + servInfo.setNetwork(new Network(foundNetId)); clientInfo.onServiceFound(clientId, servInfo); break; case NativeResponseCode.SERVICE_LOST: - /* NNN uniqueId serviceName regType domain */ + /* NNN uniqueId serviceName regType domain interfaceIdx netId */ + final int lostNetId; + try { + lostNetId = Integer.parseInt(cooked[6]); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network received from mdnsd: " + cooked[6]); + break; + } servInfo = new NsdServiceInfo(cooked[2], cooked[3]); + // The network could be null if it was torn down when the service is lost + // TODO: avoid returning null in that case, possibly by remembering found + // services on the same interface index and their network at the time + servInfo.setNetwork(lostNetId == 0 ? null : new Network(lostNetId)); clientInfo.onServiceLost(clientId, servInfo); break; case NativeResponseCode.SERVICE_DISCOVERY_FAILED: @@ -461,7 +493,7 @@ public class NsdService extends INsdManager.Stub { /* NNN regId errorCode */ break; case NativeResponseCode.SERVICE_RESOLVED: - /* NNN resolveId fullName hostName port txtlen txtdata */ + /* NNN resolveId fullName hostName port txtlen txtdata interfaceIdx */ int index = 0; while (index < cooked[2].length() && cooked[2].charAt(index) != '.') { if (cooked[2].charAt(index) == '\\') { @@ -473,6 +505,7 @@ public class NsdService extends INsdManager.Stub { Log.e(TAG, "Invalid service found " + raw); break; } + String name = cooked[2].substring(0, index); String rest = cooked[2].substring(index); String type = rest.replace(".local.", ""); @@ -483,12 +516,13 @@ public class NsdService extends INsdManager.Stub { clientInfo.mResolvedService.setServiceType(type); clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4])); clientInfo.mResolvedService.setTxtRecords(cooked[6]); + // Network will be added after SERVICE_GET_ADDR_SUCCESS stopResolveService(id); removeRequestMap(clientId, id, clientInfo); int id2 = getUniqueId(); - if (getAddrInfo(id2, cooked[3], cooked[7])) { + if (getAddrInfo(id2, cooked[3], cooked[7] /* interfaceIdx */)) { storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE); } else { clientInfo.onResolveServiceFailed( @@ -513,12 +547,31 @@ public class NsdService extends INsdManager.Stub { clientId, NsdManager.FAILURE_INTERNAL_ERROR); break; case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS: - /* NNN resolveId hostname ttl addr */ + /* NNN resolveId hostname ttl addr interfaceIdx netId */ + Network network = null; try { - clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4])); + final int netId = Integer.parseInt(cooked[6]); + network = netId == 0L ? null : new Network(netId); + } catch (NumberFormatException e) { + Log.wtf(TAG, "Invalid network in GET_ADDR_SUCCESS: " + cooked[6], e); + } + + InetAddress serviceHost = null; + try { + serviceHost = InetAddress.getByName(cooked[4]); + } catch (UnknownHostException e) { + Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e); + } + + // If the resolved service is on an interface without a network, consider it + // as a failure: it would not be usable by apps as they would need + // privileged permissions. + if (network != null && serviceHost != null) { + clientInfo.mResolvedService.setHost(serviceHost); + clientInfo.mResolvedService.setNetwork(network); clientInfo.onResolveServiceSucceeded( clientId, clientInfo.mResolvedService); - } catch (java.net.UnknownHostException e) { + } else { clientInfo.onResolveServiceFailed( clientId, NsdManager.FAILURE_INTERNAL_ERROR); } @@ -815,8 +868,15 @@ public class NsdService extends INsdManager.Stub { return mDaemon.execute("update", regId, t.size(), t.getRawData()); } - private boolean discoverServices(int discoveryId, String serviceType) { - return mDaemon.execute("discover", discoveryId, serviceType); + private boolean discoverServices(int discoveryId, NsdServiceInfo serviceInfo) { + final Network network = serviceInfo.getNetwork(); + final int discoverInterface = getNetworkInterfaceIndex(network); + if (network != null && discoverInterface == IFACE_IDX_ANY) { + Log.e(TAG, "Interface to discover service on not found"); + return false; + } + return mDaemon.execute("discover", discoveryId, serviceInfo.getServiceType(), + discoverInterface); } private boolean stopServiceDiscovery(int discoveryId) { @@ -824,17 +884,61 @@ public class NsdService extends INsdManager.Stub { } private boolean resolveService(int resolveId, NsdServiceInfo service) { - String name = service.getServiceName(); - String type = service.getServiceType(); - return mDaemon.execute("resolve", resolveId, name, type, "local."); + final String name = service.getServiceName(); + final String type = service.getServiceType(); + final Network network = service.getNetwork(); + final int resolveInterface = getNetworkInterfaceIndex(network); + if (network != null && resolveInterface == IFACE_IDX_ANY) { + Log.e(TAG, "Interface to resolve service on not found"); + return false; + } + return mDaemon.execute("resolve", resolveId, name, type, "local.", resolveInterface); + } + + /** + * Guess the interface to use to resolve or discover a service on a specific network. + * + * This is an imperfect guess, as for example the network may be gone or not yet fully + * registered. This is fine as failing is correct if the network is gone, and a client + * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also + * this is to support the legacy mdnsresponder implementation, which historically resolved + * services on an unspecified network. + */ + private int getNetworkInterfaceIndex(Network network) { + if (network == null) return IFACE_IDX_ANY; + + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + if (cm == null) { + Log.wtf(TAG, "No ConnectivityManager for resolveService"); + return IFACE_IDX_ANY; + } + final LinkProperties lp = cm.getLinkProperties(network); + if (lp == null) return IFACE_IDX_ANY; + + // Only resolve on non-stacked interfaces + final NetworkInterface iface; + try { + iface = NetworkInterface.getByName(lp.getInterfaceName()); + } catch (SocketException e) { + Log.e(TAG, "Error querying interface", e); + return IFACE_IDX_ANY; + } + + if (iface == null) { + Log.e(TAG, "Interface not found: " + lp.getInterfaceName()); + return IFACE_IDX_ANY; + } + + return iface.getIndex(); } private boolean stopResolveService(int resolveId) { return mDaemon.execute("stop-resolve", resolveId); } - private boolean getAddrInfo(int resolveId, String hostname, String interfaceName) { - return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceName); + private boolean getAddrInfo(int resolveId, String hostname, String interfaceIdx) { + // interfaceIdx is always obtained (as string) from the service resolved callback + return mDaemon.execute("getaddrinfo", resolveId, hostname, interfaceIdx); } private boolean stopGetAddrInfo(int resolveId) { From 1ddba4c56af65ce30315c27e760334789bfd4548 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 18 Jan 2022 19:44:57 +0900 Subject: [PATCH 1093/1150] Support discovering services with a NetworkRequest A common mistake when using service discovery is to mismanage networks, expecting to find or be able to access services on networks that may not be available yet, or may be stale/lost. This new API allows clients to start service discovery with just a NetworkRequest, letting NsdManager track networks and notify when services are found/lost for each network. Bug: 190249673 Test: atest NsdManagerTest Change-Id: I12e799aa48fce2d1a35f708c5617386b1cc70f21 --- .../src/android/net/nsd/NsdManager.java | 249 +++++++++++++++++- 1 file changed, 248 insertions(+), 1 deletion(-) diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index ea69e092c4..512fbcee93 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java @@ -18,6 +18,7 @@ package android.net.nsd; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemService; @@ -25,16 +26,22 @@ import android.app.compat.CompatChanges; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledSince; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.ConnectivityManager.NetworkCallback; import android.net.Network; +import android.net.NetworkRequest; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; @@ -281,9 +288,180 @@ public final class NsdManager { private final SparseArray mListenerMap = new SparseArray(); private final SparseArray mServiceMap = new SparseArray<>(); private final Object mMapLock = new Object(); + // Map of listener key sent by client -> per-network discovery tracker + @GuardedBy("mPerNetworkDiscoveryMap") + private final ArrayMap + mPerNetworkDiscoveryMap = new ArrayMap<>(); private final ServiceHandler mHandler; + private class PerNetworkDiscoveryTracker { + final String mServiceType; + final int mProtocolType; + final DiscoveryListener mBaseListener; + final ArrayMap mPerNetworkListeners = + new ArrayMap<>(); + + final NetworkCallback mNetworkCb = new NetworkCallback() { + @Override + public void onAvailable(@NonNull Network network) { + final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener( + network, mBaseListener); + mPerNetworkListeners.put(network, wrappedListener); + discoverServices(mServiceType, mProtocolType, network, wrappedListener); + } + + @Override + public void onLost(@NonNull Network network) { + final DelegatingDiscoveryListener listener = mPerNetworkListeners.get(network); + if (listener == null) return; + listener.notifyAllServicesLost(); + // Listener will be removed from map in discovery stopped callback + stopServiceDiscovery(listener); + } + }; + + // Accessed from mHandler + private boolean mStopRequested; + + public void start(@NonNull NetworkRequest request) { + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.registerNetworkCallback(request, mNetworkCb, mHandler); + mHandler.post(() -> mBaseListener.onDiscoveryStarted(mServiceType)); + } + + /** + * Stop discovery on all networks tracked by this class. + * + * This will request all underlying listeners to stop, and the last one to stop will call + * onDiscoveryStopped or onStopDiscoveryFailed. + * + * Must be called on the handler thread. + */ + public void requestStop() { + mHandler.post(() -> { + mStopRequested = true; + final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); + cm.unregisterNetworkCallback(mNetworkCb); + if (mPerNetworkListeners.size() == 0) { + mBaseListener.onDiscoveryStopped(mServiceType); + return; + } + for (int i = 0; i < mPerNetworkListeners.size(); i++) { + final DelegatingDiscoveryListener listener = mPerNetworkListeners.valueAt(i); + stopServiceDiscovery(listener); + } + }); + } + + private PerNetworkDiscoveryTracker(String serviceType, int protocolType, + DiscoveryListener baseListener) { + mServiceType = serviceType; + mProtocolType = protocolType; + mBaseListener = baseListener; + } + + /** + * Subset of NsdServiceInfo that is tracked to generate service lost notifications when a + * network is lost. + * + * Service lost notifications only contain service name, type and network, so only track + * that information (Network is known from the listener). This also implements + * equals/hashCode for usage in maps. + */ + private class TrackedNsdInfo { + private final String mServiceName; + private final String mServiceType; + TrackedNsdInfo(NsdServiceInfo info) { + mServiceName = info.getServiceName(); + mServiceType = info.getServiceType(); + } + + @Override + public int hashCode() { + return Objects.hash(mServiceName, mServiceType); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TrackedNsdInfo)) return false; + final TrackedNsdInfo other = (TrackedNsdInfo) obj; + return Objects.equals(mServiceName, other.mServiceName) + && Objects.equals(mServiceType, other.mServiceType); + } + } + + private class DelegatingDiscoveryListener implements DiscoveryListener { + private final Network mNetwork; + private final DiscoveryListener mWrapped; + private final ArraySet mFoundInfo = new ArraySet<>(); + + private DelegatingDiscoveryListener(Network network, DiscoveryListener listener) { + mNetwork = network; + mWrapped = listener; + } + + void notifyAllServicesLost() { + for (int i = 0; i < mFoundInfo.size(); i++) { + final TrackedNsdInfo trackedInfo = mFoundInfo.valueAt(i); + final NsdServiceInfo serviceInfo = new NsdServiceInfo( + trackedInfo.mServiceName, trackedInfo.mServiceType); + serviceInfo.setNetwork(mNetwork); + mWrapped.onServiceLost(serviceInfo); + } + } + + @Override + public void onStartDiscoveryFailed(String serviceType, int errorCode) { + // The delegated listener is used when NsdManager takes care of starting/stopping + // discovery on multiple networks. Failure to start on one network is not a global + // failure to be reported up, as other networks may succeed: just log. + Log.e(TAG, "Failed to start discovery for " + serviceType + " on " + mNetwork + + " with code " + errorCode); + mPerNetworkListeners.remove(mNetwork); + } + + @Override + public void onDiscoveryStarted(String serviceType) { + // Wrapped listener was called upon registration, it is not called for discovery + // on each network + } + + @Override + public void onStopDiscoveryFailed(String serviceType, int errorCode) { + Log.e(TAG, "Failed to stop discovery for " + serviceType + " on " + mNetwork + + " with code " + errorCode); + mPerNetworkListeners.remove(mNetwork); + if (mStopRequested && mPerNetworkListeners.size() == 0) { + // Do not report onStopDiscoveryFailed when some underlying listeners failed: + // this does not mean that all listeners did, and onStopDiscoveryFailed is not + // actionable anyway. Just report that discovery stopped. + mWrapped.onDiscoveryStopped(serviceType); + } + } + + @Override + public void onDiscoveryStopped(String serviceType) { + mPerNetworkListeners.remove(mNetwork); + if (mStopRequested && mPerNetworkListeners.size() == 0) { + mWrapped.onDiscoveryStopped(serviceType); + } + } + + @Override + public void onServiceFound(NsdServiceInfo serviceInfo) { + mFoundInfo.add(new TrackedNsdInfo(serviceInfo)); + mWrapped.onServiceFound(serviceInfo); + } + + @Override + public void onServiceLost(NsdServiceInfo serviceInfo) { + mFoundInfo.remove(new TrackedNsdInfo(serviceInfo)); + mWrapped.onServiceLost(serviceInfo); + } + } + } + /** * Create a new Nsd instance. Applications use * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve @@ -641,7 +819,7 @@ public final class NsdManager { * {@link Network}. */ public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - discoverServices(serviceType, protocolType, null, listener); + discoverServices(serviceType, protocolType, (Network) null, listener); } /** @@ -692,6 +870,67 @@ public final class NsdManager { } } + /** + * Initiate service discovery to browse for instances of a service type. Service discovery + * consumes network bandwidth and will continue until the application calls + * {@link #stopServiceDiscovery}. + * + *

            The function call immediately returns after sending a request to start service + * discovery to the framework. The application is notified of a success to initiate + * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure + * through {@link DiscoveryListener#onStartDiscoveryFailed}. + * + *

            Upon successful start, application is notified when a service is found with + * {@link DiscoveryListener#onServiceFound} or when a service is lost with + * {@link DiscoveryListener#onServiceLost}. + * + *

            Upon failure to start, service discovery is not active and application does + * not need to invoke {@link #stopServiceDiscovery} + * + *

            The application should call {@link #stopServiceDiscovery} when discovery of this + * service type is no longer required, and/or whenever the application is paused or + * stopped. + * + *

            During discovery, new networks may connect or existing networks may disconnect - for + * example if wifi is reconnected. When a service was found on a network that disconnects, + * {@link DiscoveryListener#onServiceLost} will be called. If a new network connects that + * matches the {@link NetworkRequest}, {@link DiscoveryListener#onServiceFound} will be called + * for services found on that network. Applications that do not want to track networks + * themselves are encouraged to use this method instead of other overloads of + * {@code discoverServices}, as they will receive proper notifications when a service becomes + * available or unavailable due to network changes. + * + * @param serviceType The service type being discovered. Examples include "_http._tcp" for + * http services or "_ipp._tcp" for printers + * @param protocolType The service discovery protocol + * @param networkRequest Request specifying networks that should be considered when discovering + * @param listener The listener notifies of a successful discovery and is used + * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. + * Cannot be null. Cannot be in use for an active service discovery. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + public void discoverServices(@NonNull String serviceType, int protocolType, + @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) { + if (TextUtils.isEmpty(serviceType)) { + throw new IllegalArgumentException("Service type cannot be empty"); + } + Objects.requireNonNull(networkRequest, "NetworkRequest cannot be null"); + checkProtocol(protocolType); + + NsdServiceInfo s = new NsdServiceInfo(); + s.setServiceType(serviceType); + + final int baseListenerKey = putListener(listener, s); + + final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker( + serviceType, protocolType, listener); + + synchronized (mPerNetworkDiscoveryMap) { + mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo); + discoveryInfo.start(networkRequest); + } + } + /** * Stop service discovery initiated with {@link #discoverServices}. An active service * discovery is notified to the application with {@link DiscoveryListener#onDiscoveryStarted} @@ -710,6 +949,14 @@ public final class NsdManager { */ public void stopServiceDiscovery(DiscoveryListener listener) { int id = getListenerKey(listener); + // If this is a PerNetworkDiscovery request, handle it as such + synchronized (mPerNetworkDiscoveryMap) { + final PerNetworkDiscoveryTracker info = mPerNetworkDiscoveryMap.get(id); + if (info != null) { + info.requestStop(); + return; + } + } try { mService.stopDiscovery(id); } catch (RemoteException e) { From fc3b420236653939a09a9fd5ce3bf9785e1300a9 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 2 Feb 2022 22:28:28 +0100 Subject: [PATCH 1094/1150] Add key / value data structures for IBpfMaps Add key / value structures for CookieTagMap, StatsMap, and UidStatsMap. This will be used for deleteTagData. Test: m Change-Id: I955ae7f7745d4c5f37eccbad80cdb841ef55ff56 --- service-t/Sources.bp | 5 ++ .../android/server/net/CookieTagMapKey.java | 33 +++++++++++++ .../android/server/net/CookieTagMapValue.java | 37 +++++++++++++++ .../com/android/server/net/StatsMapKey.java | 46 +++++++++++++++++++ .../com/android/server/net/StatsMapValue.java | 46 +++++++++++++++++++ .../android/server/net/UidStatsMapKey.java | 33 +++++++++++++ 6 files changed, 200 insertions(+) create mode 100644 service-t/src/com/android/server/net/CookieTagMapKey.java create mode 100644 service-t/src/com/android/server/net/CookieTagMapValue.java create mode 100644 service-t/src/com/android/server/net/StatsMapKey.java create mode 100644 service-t/src/com/android/server/net/StatsMapValue.java create mode 100644 service-t/src/com/android/server/net/UidStatsMapKey.java diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 24bc91d91e..d05370f9ba 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -28,6 +28,11 @@ filegroup { "src/com/android/server/net/NetworkStats*.java", "src/com/android/server/net/BpfInterfaceMapUpdater.java", "src/com/android/server/net/InterfaceMapValue.java", + "src/com/android/server/net/CookieTagMapKey.java", + "src/com/android/server/net/CookieTagMapValue.java", + "src/com/android/server/net/StatsMapKey.java", + "src/com/android/server/net/StatsMapValue.java", + "src/com/android/server/net/UidStatsMapKey.java", ], path: "src", visibility: [ diff --git a/service-t/src/com/android/server/net/CookieTagMapKey.java b/service-t/src/com/android/server/net/CookieTagMapKey.java new file mode 100644 index 0000000000..443e5b3847 --- /dev/null +++ b/service-t/src/com/android/server/net/CookieTagMapKey.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for cookie tag map. + */ +public class CookieTagMapKey extends Struct { + @Field(order = 0, type = Type.S64) + public final long socketCookie; + + public CookieTagMapKey(final long socketCookie) { + this.socketCookie = socketCookie; + } +} diff --git a/service-t/src/com/android/server/net/CookieTagMapValue.java b/service-t/src/com/android/server/net/CookieTagMapValue.java new file mode 100644 index 0000000000..93b9195f92 --- /dev/null +++ b/service-t/src/com/android/server/net/CookieTagMapValue.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Value for cookie tag map. + */ +public class CookieTagMapValue extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + public CookieTagMapValue(final long uid, final long tag) { + this.uid = uid; + this.tag = tag; + } +} diff --git a/service-t/src/com/android/server/net/StatsMapKey.java b/service-t/src/com/android/server/net/StatsMapKey.java new file mode 100644 index 0000000000..ea8d836383 --- /dev/null +++ b/service-t/src/com/android/server/net/StatsMapKey.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for both stats maps. + */ +public class StatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + @Field(order = 1, type = Type.U32) + public final long tag; + + @Field(order = 2, type = Type.U32) + public final long counterSet; + + @Field(order = 3, type = Type.U32) + public final long ifaceIndex; + + public StatsMapKey(final long uid, final long tag, final long counterSet, + final long ifaceIndex) { + this.uid = uid; + this.tag = tag; + this.counterSet = counterSet; + this.ifaceIndex = ifaceIndex; + } +} diff --git a/service-t/src/com/android/server/net/StatsMapValue.java b/service-t/src/com/android/server/net/StatsMapValue.java new file mode 100644 index 0000000000..48f26ce686 --- /dev/null +++ b/service-t/src/com/android/server/net/StatsMapValue.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Value used for both stats maps and uid stats map. + */ +public class StatsMapValue extends Struct { + @Field(order = 0, type = Type.U63) + public final long rxPackets; + + @Field(order = 1, type = Type.U63) + public final long rxBytes; + + @Field(order = 2, type = Type.U63) + public final long txPackets; + + @Field(order = 3, type = Type.U63) + public final long txBytes; + + public StatsMapValue(final long rxPackets, final long rxBytes, final long txPackets, + final long txBytes) { + this.rxPackets = rxPackets; + this.rxBytes = rxBytes; + this.txPackets = txPackets; + this.txBytes = txBytes; + } +} diff --git a/service-t/src/com/android/server/net/UidStatsMapKey.java b/service-t/src/com/android/server/net/UidStatsMapKey.java new file mode 100644 index 0000000000..2849f94c93 --- /dev/null +++ b/service-t/src/com/android/server/net/UidStatsMapKey.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.net; + +import com.android.net.module.util.Struct; +import com.android.net.module.util.Struct.Field; +import com.android.net.module.util.Struct.Type; + +/** + * Key for uid stats map. + */ +public class UidStatsMapKey extends Struct { + @Field(order = 0, type = Type.U32) + public final long uid; + + public UidStatsMapKey(final long uid) { + this.uid = uid; + } +} From d8d9fb13a81b641a26ae63e407dbfb03512c5f27 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Wed, 2 Feb 2022 14:32:40 -0800 Subject: [PATCH 1095/1150] Marking eth network management APIs @SystemApi Annotating ethernet network management APIs in EthernetManager with @SystemApi. Bug: 210485380 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk cherry pick of aosp/1969839 Change-Id: I10429441fd4d7b9bcaa7437b844420a43a415d72 --- .../src/android/net/EthernetManager.java | 90 +++++++++++++++++-- .../EthernetNetworkManagementException.java | 2 + .../net/EthernetNetworkUpdateRequest.java | 3 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index e0ce081c02..1f67f6d654 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -19,12 +19,14 @@ package android.net; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.RemoteException; @@ -358,12 +360,43 @@ public class EthernetManager { return proxy; } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void updateConfiguration( + /** + * Updates the configuration of an automotive device's ethernet network. + * + * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the + * configuration for this network. + * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for + * this network to put inside the {@code request}. + * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} + * object for this network to put inside the {@code request}. + * + * If non-null, the listener will be called exactly once after this is called, unless + * a synchronous exception was thrown. + * + * @param iface the name of the interface to act upon. + * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's + * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device or on an + * unsupported interface. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void updateConfiguration( @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); + Objects.requireNonNull(request, "request must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -373,11 +406,34 @@ public class EthernetManager { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void connectNetwork( + /** + * Set an ethernet network's link state up. + * + * When the link is successfully turned up, the listener will be called with the resulting + * network. If any error or unexpected condition happens while the system tries to turn the + * interface up, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method, but this + * may take an unbounded amount of time depending on the actual network conditions. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -387,11 +443,33 @@ public class EthernetManager { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void disconnectNetwork( + /** + * Set an ethernet network's link state down. + * + * When the link is successfully turned down, the listener will be called with the network that + * was torn down, if any. If any error or unexpected condition happens while the system tries to + * turn the interface down, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { diff --git a/framework-t/src/android/net/EthernetNetworkManagementException.java b/framework-t/src/android/net/EthernetNetworkManagementException.java index a35f28e172..a69cc55363 100644 --- a/framework-t/src/android/net/EthernetNetworkManagementException.java +++ b/framework-t/src/android/net/EthernetNetworkManagementException.java @@ -17,12 +17,14 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** @hide */ +@SystemApi public final class EthernetNetworkManagementException extends RuntimeException implements Parcelable { diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index 4d229d23b1..e879e40247 100644 --- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -17,12 +17,14 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** @hide */ +@SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull private final StaticIpConfiguration mIpConfig; @@ -39,7 +41,6 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return new NetworkCapabilities(mNetworkCapabilities); } - /** @hide */ public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); From 5e1593f3a6f3196ac13c420d1c7453d437646b28 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Wed, 2 Feb 2022 14:32:40 -0800 Subject: [PATCH 1096/1150] Marking eth network management APIs @SystemApi Annotating ethernet network management APIs in EthernetManager with @SystemApi. Bug: 210485380 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk Change-Id: I10429441fd4d7b9bcaa7437b844420a43a415d72 Merged-In: I10429441fd4d7b9bcaa7437b844420a43a415d72 --- .../src/android/net/EthernetManager.java | 90 +++++++++++++++++-- .../EthernetNetworkManagementException.java | 2 + .../net/EthernetNetworkUpdateRequest.java | 3 +- 3 files changed, 88 insertions(+), 7 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index e0ce081c02..1f67f6d654 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -19,12 +19,14 @@ package android.net; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; +import android.content.pm.PackageManager; import android.os.Build; import android.os.RemoteException; @@ -358,12 +360,43 @@ public class EthernetManager { return proxy; } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void updateConfiguration( + /** + * Updates the configuration of an automotive device's ethernet network. + * + * The {@link EthernetNetworkUpdateRequest} {@code request} argument describes how to update the + * configuration for this network. + * Use {@link StaticIpConfiguration.Builder} to build a {@code StaticIpConfiguration} object for + * this network to put inside the {@code request}. + * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} + * object for this network to put inside the {@code request}. + * + * If non-null, the listener will be called exactly once after this is called, unless + * a synchronous exception was thrown. + * + * @param iface the name of the interface to act upon. + * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's + * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device or on an + * unsupported interface. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void updateConfiguration( @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); + Objects.requireNonNull(request, "request must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -373,11 +406,34 @@ public class EthernetManager { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void connectNetwork( + /** + * Set an ethernet network's link state up. + * + * When the link is successfully turned up, the listener will be called with the resulting + * network. If any error or unexpected condition happens while the system tries to turn the + * interface up, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method, but this + * may take an unbounded amount of time depending on the actual network conditions. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { @@ -387,11 +443,33 @@ public class EthernetManager { } } - @RequiresPermission(android.Manifest.permission.MANAGE_ETHERNET_NETWORKS) - private void disconnectNetwork( + /** + * Set an ethernet network's link state down. + * + * When the link is successfully turned down, the listener will be called with the network that + * was torn down, if any. If any error or unexpected condition happens while the system tries to + * turn the interface down, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method. + * + * @param iface the name of the interface to act upon. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @throws SecurityException if the process doesn't hold + * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. + * @throws UnsupportedOperationException if called on a non-automotive device. + * @hide + */ + @SystemApi + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) + @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) + public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable BiConsumer listener) { + Objects.requireNonNull(iface, "iface must be non-null"); final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( executor, listener); try { diff --git a/framework-t/src/android/net/EthernetNetworkManagementException.java b/framework-t/src/android/net/EthernetNetworkManagementException.java index a35f28e172..a69cc55363 100644 --- a/framework-t/src/android/net/EthernetNetworkManagementException.java +++ b/framework-t/src/android/net/EthernetNetworkManagementException.java @@ -17,12 +17,14 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** @hide */ +@SystemApi public final class EthernetNetworkManagementException extends RuntimeException implements Parcelable { diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index 4d229d23b1..e879e40247 100644 --- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -17,12 +17,14 @@ package android.net; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import java.util.Objects; /** @hide */ +@SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull private final StaticIpConfiguration mIpConfig; @@ -39,7 +41,6 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return new NetworkCapabilities(mNetworkCapabilities); } - /** @hide */ public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); From 2b01633f812028c99a765d4382dc32f118178db1 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 17 Jan 2022 17:37:19 +0000 Subject: [PATCH 1097/1150] [MS62.1] Start NetworkStatsService from the module NetworkStatsService is going to be moved into Connectivity mainlne module and it will be not visible to SystemServiceResistry after migration done. Thus: 1. Register service in NetworkStatsServiceInitialalizer, a separate initializer is needed because the service needs to be created before NetworkPolicyManagerService's initialization. 2. Call SystemReady at PHASE_ACTIVITY_MANAGER_READY phase where it needs to be ready before StatsPullAtomService pulls at PHASE_THIRD_PARTY_APPS_CAN_START. 3. Register manager in ConnectivityFrameworkInitializerTiramisu instead of SystemServiceRegistery. Test: atest FrameworksNetTests CtsNetTestCases NetworkUsageStatsTest Bug: 204830222 Change-Id: I95020d816ed613ce3480a0720a5b71dcdc7fab72 --- .../net/ConnectivityFrameworkInitializerTiramisu.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 577ac54666..9bffbfb27a 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SystemApi; import android.app.SystemServiceRegistry; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -57,5 +58,15 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new IpSecManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.NETWORK_STATS_SERVICE, + NetworkStatsManager.class, + (context, serviceBinder) -> { + INetworkStatsService service = + INetworkStatsService.Stub.asInterface(serviceBinder); + return new NetworkStatsManager(context, service); + } + ); } } From 0bac7dddd7c41df4ad03adb305678ea405faaeab Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 26 Jan 2022 09:00:41 +0000 Subject: [PATCH 1098/1150] [MS54.1] Move NetworkStats to updatable sources This CL builds NetworkStats related code with the connectivity module instead of platform. This includes: 1. Add netstats.proto to the module. 2. Add lib dependencies for all callers. 3. Include several source files in platform and add jarjar rule to it. Modify callers accordingly. Test: TH Bug: 197717846 Change-Id: I244693aebe1782d9e67502638ff8145c51462e1e --- framework-t/Sources.bp | 4 +--- .../src/android/net/NetworkIdentity.java | 10 ++++----- .../src/android/net/NetworkIdentitySet.java | 2 +- .../android/net/NetworkStatsCollection.java | 14 ++++++------ .../src/android/net/NetworkStatsHistory.java | 17 +++++++------- service-t/Sources.bp | 2 +- .../server/net/NetworkStatsRecorder.java | 6 +++-- .../server/net/NetworkStatsService.java | 22 ++++++++++++------- .../net/NetworkStatsSubscriptionsMonitor.java | 3 +++ 9 files changed, 45 insertions(+), 35 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 6329565ca5..b30e54d20b 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -158,7 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], } @@ -167,6 +166,7 @@ filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ ":framework-connectivity-ipsec-sources", + ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], @@ -202,7 +202,5 @@ cc_library_shared { stl: "none", apex_available: [ "com.android.tethering", - // TODO: remove when ConnectivityT moves to APEX. - "//apex_available:platform", ], } diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 56faa52e82..4ebaf2b8cd 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -184,14 +184,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE, mType); + proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); + proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); proto.end(start); } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index dfa347f6f1..2236d70c35 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -212,7 +212,7 @@ public class NetworkIdentitySet extends HashSet { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); } proto.end(start); diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 735c44d5c8..67d48f0000 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); + proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); proto.end(startStats); } diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 78c137073a..822a16e0bb 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,17 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + bucketStart[i]); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); proto.end(startBucket); } diff --git a/service-t/Sources.bp b/service-t/Sources.bp index c3049dabef..502c56a7fb 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -88,7 +88,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-netstats-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], @@ -98,6 +97,7 @@ filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ ":services.connectivity-ipsec-sources", + ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index c371f0859a..a006cd5975 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,9 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + mPending.getTotalBytes()); } - getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + getOrLoadCompleteLocked().dumpDebug(proto, + NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 9f3371b724..1ff4fd285a 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -62,6 +62,7 @@ import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -102,6 +103,7 @@ import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -169,6 +171,7 @@ import java.util.concurrent.TimeUnit; * Collect and persist detailed network statistics, and provide this data to * other system services. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); @@ -2004,12 +2007,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + mActiveUidIfaces); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mUidTagRecorder.dumpDebugLocked(proto, + NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); proto.flush(); } @@ -2019,8 +2025,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); + proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 5bba0b17aa..65ccd20072 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -23,7 +23,9 @@ import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NS import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; @@ -43,6 +45,7 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { From 1e63b0bce2f6b76d60b9536a944b34bea3651f0b Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 2 Feb 2022 13:22:57 +0900 Subject: [PATCH 1099/1150] Move networkstats JNI to connectivity module Reorganize networkstats JNI so it can be included in the connectivity module. Bug: 197717846 Test: m Change-Id: I815ea379f3d9915041c80ac5e743ce62e05f4cf8 --- framework-t/Sources.bp | 5 ++-- service-t/Sources.bp | 24 +++++++++++++++++++ ...android_server_net_NetworkStatsFactory.cpp | 0 ...android_server_net_NetworkStatsService.cpp | 0 .../server/net/NetworkStatsFactory.java | 4 ++++ .../server/net/NetworkStatsService.java | 4 ++++ 6 files changed, 34 insertions(+), 3 deletions(-) rename {services/core => service-t}/jni/com_android_server_net_NetworkStatsFactory.cpp (100%) rename {services/core => service-t}/jni/com_android_server_net_NetworkStatsService.cpp (100%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index b30e54d20b..66527802a0 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -194,10 +194,9 @@ cc_library_shared { "jni/onload.cpp", ], shared_libs: [ + "libandroid", "liblog", - ], - static_libs: [ - "libnativehelper_compat_libc++", + "libnativehelper", ], stl: "none", apex_available: [ diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 502c56a7fb..5100e7c5b9 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -40,6 +40,30 @@ filegroup { ], } +// For test code only. +filegroup { + name: "lib_networkStatsFactory_native", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + +filegroup { + name: "services.connectivity-netstats-jni-sources", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + "jni/com_android_server_net_NetworkStatsService.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + // Nsd related libraries. filegroup { diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp similarity index 100% rename from services/core/jni/com_android_server_net_NetworkStatsFactory.cpp rename to service-t/jni/com_android_server_net_NetworkStatsFactory.cpp diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp similarity index 100% rename from services/core/jni/com_android_server_net_NetworkStatsService.cpp rename to service-t/jni/com_android_server_net_NetworkStatsService.cpp diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index 668d1cba92..151c90dd41 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -54,6 +54,10 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ public class NetworkStatsFactory { + static { + System.loadLibrary("service-connectivity"); + } + private static final String TAG = "NetworkStatsFactory"; private static final boolean USE_NATIVE_PARSING = true; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1ff4fd285a..7a5ba09f27 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -173,6 +173,10 @@ import java.util.concurrent.TimeUnit; */ @TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { + static { + System.loadLibrary("service-connectivity"); + } + static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); From 7ede3024bcdde33ddf4abe8cd3058c9d938ecfbe Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 3 Feb 2022 11:34:52 +0900 Subject: [PATCH 1100/1150] Add setPollForce to module API The API was test API in S, but this is not supported in module API surfaces. Make it module API instead. Bug: 197717846 Test: Tests already using this API Change-Id: I9d44b761572f94b08b269478c4a0c20c1171343c --- .../src/android/app/usage/NetworkStatsManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 5ce7e59b38..0414bb79f8 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; @@ -192,9 +191,13 @@ public class NetworkStatsManager { } } - /** @hide */ + /** + * Set poll force flag to indicate that calling any subsequent query method will force a stats + * poll. + * @hide + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setPollForce(boolean pollForce) { if (pollForce) { mFlags |= FLAG_POLL_FORCE; From 889703ce18f16e8fb462a8f36e9d9a41e6132c9d Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 4 Feb 2022 03:05:59 +0900 Subject: [PATCH 1101/1150] Expose MATCH_PROXY as a module-lib API. It is used by clockwork. Test: m update-api Change-Id: I5676f883141afca1511c425b7c36683a6c6bfb9f --- framework-t/src/android/net/NetworkTemplate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 9b58b016bb..7b5afd7200 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -79,7 +79,8 @@ public final class NetworkTemplate implements Parcelable { MATCH_WIFI, MATCH_ETHERNET, MATCH_BLUETOOTH, - MATCH_CARRIER + MATCH_PROXY, + MATCH_CARRIER, }) public @interface TemplateMatchRule{} @@ -104,9 +105,8 @@ public final class NetworkTemplate implements Parcelable { /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; /** - * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. - * - * @hide + * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy + * network type. */ public static final int MATCH_PROXY = 9; /** From 250b1e31d6b9c38a7c048dce1fa49ca726f5e30f Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 28 Jan 2022 22:02:06 +0800 Subject: [PATCH 1102/1150] [MS68.3] Address comments at aosp/1958144 Test: atest TrafficStatsTest NetworkUsageStatsTest FrameworksNetTests Bug: 204830222 Change-Id: I5a54b44294021d64d8506eeb570db0db8544472a --- .../app/usage/NetworkStatsManager.java | 8 ++++++-- .../server/net/NetworkStatsObservers.java | 20 ++++++++++++------- .../server/net/NetworkStatsService.java | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 0414bb79f8..221a848a59 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -740,8 +740,9 @@ public class NetworkStatsManager { * {@link #unregisterUsageCallback} is called. * * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower - * than 2MiB will be clamped for non-privileged callers. + * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB + * will be clamped for callers except callers with the NETWORK_STACK + * permission. * @param executor The executor on which callback will be invoked. The provided {@link Executor} * must run callback sequentially, otherwise the order of callbacks cannot be * guaranteed. @@ -750,6 +751,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}, conditional = true) public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { Objects.requireNonNull(template, "NetworkTemplate cannot be null"); diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index 19536247b2..fdfc893f57 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -19,8 +19,11 @@ package com.android.server.net; import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.content.pm.PackageManager; import android.net.DataUsageRequest; import android.net.NetworkIdentitySet; +import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkStatsAccess; import android.net.NetworkStatsCollection; @@ -74,9 +77,9 @@ class NetworkStatsObservers { * * @return the normalized request wrapped within {@link RequestInfo}. */ - public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback, - int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(inputRequest, callingUid); + public DataUsageRequest register(Context context, DataUsageRequest inputRequest, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { + DataUsageRequest request = buildRequest(context, inputRequest, callingUid); RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, accessLevel); @@ -194,10 +197,13 @@ class NetworkStatsObservers { } } - private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) { - // For non-system uid, cap the minimum threshold to a safe default to avoid too - // many callbacks. - long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes + private DataUsageRequest buildRequest(Context context, DataUsageRequest request, + int callingUid) { + // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to + // avoid too many callbacks. + final long thresholdInBytes = (context.checkPermission( + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid) + == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); if (thresholdInBytes > request.thresholdInBytes) { Log.w(TAG, "Threshold was too low for " + request diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 7a5ba09f27..e366ca13df 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1229,7 +1229,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { DataUsageRequest normalizedRequest; final long token = Binder.clearCallingIdentity(); try { - normalizedRequest = mStatsObservers.register( + normalizedRequest = mStatsObservers.register(mContext, request, callback, callingUid, accessLevel); } finally { Binder.restoreCallingIdentity(token); From fea7a4f5fd9965a6d10e7f55f9a81f749dd65619 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 3 Feb 2022 19:09:36 -0800 Subject: [PATCH 1103/1150] Making EthernetNetworkSpecifier public Bug: 210485380 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk cherry pick of aosp/1971181 Change-Id: Ic0b7a3360745632eb024a97692e49f6c8dafa3ee --- framework-t/src/android/net/EthernetNetworkSpecifier.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkSpecifier.java b/framework-t/src/android/net/EthernetNetworkSpecifier.java index 925d12b574..e4d6e248d4 100644 --- a/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ b/framework-t/src/android/net/EthernetNetworkSpecifier.java @@ -18,7 +18,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -29,9 +28,7 @@ import java.util.Objects; * A {@link NetworkSpecifier} used to identify ethernet interfaces. * * @see EthernetManager - * @hide */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { /** @@ -61,6 +58,7 @@ public final class EthernetNetworkSpecifier extends NetworkSpecifier implements return mInterfaceName; } + /** @hide */ @Override public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { return equals(other); From 34f91fc7b893228cf37395f8766f4b4d1fb7309a Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 2 Feb 2022 16:39:45 -0800 Subject: [PATCH 1104/1150] Un-finalize IpSecManager Allows VCN and IKE unit tests to mock IpSecManager and thus stop depending on the hidden APIs in the Connectivity module (e.g. IpSecService binder interface). Otherwise, any changes on these related hidden APIs will require topic changes across multiple projects. Bug: 217572993 Test: make update-api Test: atest IpSecManagerTest, IpSecManagerTunnelTest Change-Id: I29f3ac96f83b4271f29a7051d33ccf47a0dd6c57 --- framework-t/src/android/net/IpSecManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index a423783bc1..9cb0947b23 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -61,7 +61,7 @@ import java.util.Objects; * Internet Protocol */ @SystemService(Context.IPSEC_SERVICE) -public final class IpSecManager { +public class IpSecManager { private static final String TAG = "IpSecManager"; /** From 7b04f8f339d63019cbf8999e55498dfe7b6437a1 Mon Sep 17 00:00:00 2001 From: Yan Yan Date: Wed, 2 Feb 2022 16:39:45 -0800 Subject: [PATCH 1105/1150] Un-finalize IpSecManager Allows VCN and IKE unit tests to mock IpSecManager and thus stop depending on the hidden APIs in the Connectivity module (e.g. IpSecService binder interface). Otherwise, any changes on these related hidden APIs will require topic changes across multiple projects. Bug: 217572993 Test: make update-api Test: atest IpSecManagerTest, IpSecManagerTunnelTest Change-Id: I29f3ac96f83b4271f29a7051d33ccf47a0dd6c57 Merged-In: I29f3ac96f83b4271f29a7051d33ccf47a0dd6c57 --- framework-t/src/android/net/IpSecManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java index a423783bc1..9cb0947b23 100644 --- a/framework-t/src/android/net/IpSecManager.java +++ b/framework-t/src/android/net/IpSecManager.java @@ -61,7 +61,7 @@ import java.util.Objects; * Internet Protocol */ @SystemService(Context.IPSEC_SERVICE) -public final class IpSecManager { +public class IpSecManager { private static final String TAG = "IpSecManager"; /** From 531889a99304f7e2f48df7fd9f042a0608c3b643 Mon Sep 17 00:00:00 2001 From: Chiachang Wang Date: Wed, 9 Feb 2022 14:30:57 +0800 Subject: [PATCH 1106/1150] Correct typo in the year of copyright Test: m Change-Id: I68e9925b5b6deb7c5c9d57aa4a397c80f8b8d869 --- service-t/src/com/android/server/net/InterfaceMapValue.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/net/InterfaceMapValue.java b/service-t/src/com/android/server/net/InterfaceMapValue.java index 061f323447..42c0044e66 100644 --- a/service-t/src/com/android/server/net/InterfaceMapValue.java +++ b/service-t/src/com/android/server/net/InterfaceMapValue.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2020 The Android Open Source Project + * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From c3c367e4819bdc7e00641c8175ccf64ce996115d Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 9 Feb 2022 20:37:26 +0800 Subject: [PATCH 1107/1150] [DU03-4]Add NETWORK_STACK Permission check for NetworkStatsService API 1. getUidStatsForTransport API Bug: 210066922 Test: atest BatteryStatsImplTest WifiPowerCalculatorTest MobileRadioPowerCalculatorTest NetworkStatsServiceTest Change-Id: I022c34b5af87fe3ff6857ea264bac2f7098eaed4 --- .../src/android/app/usage/NetworkStatsManager.java | 8 ++++++-- .../src/com/android/server/net/NetworkStatsService.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 0414bb79f8..a8baa8e488 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -699,7 +699,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getMobileUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); @@ -723,7 +725,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getWifiUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_WIFI); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 7a5ba09f27..35dfefe752 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1067,7 +1067,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getUidStatsForTransport(int transport) { - enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + PermissionUtils.enforceNetworkStackPermission(mContext); try { final String[] relevantIfaces = transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; From 83400b6b3b393f811d1fe269f346603e08c21002 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Wed, 12 Jan 2022 15:11:01 +0800 Subject: [PATCH 1108/1150] Split out the ipsec API surface and use framework-connectivity-tiramisu (cherry picked from commit 131a8663843fced7b44234bddc93759e56c29344) Bug: 204153604 Test: TH Change-Id: I6cc8aef6a0ab9ce4bcef2797196b1d1b3687acca Merged-In: I6cc8aef6a0ab9ce4bcef2797196b1d1b3687acca --- framework-t/Sources.bp | 2 +- ...nectivityFrameworkInitializerTiramisu.java | 9 ++++++ service-t/Sources.bp | 2 +- .../src/com/android/server/IpSecService.java | 29 +------------------ 4 files changed, 12 insertions(+), 30 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 54538d91a5..6329565ca5 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -158,7 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], @@ -167,6 +166,7 @@ filegroup { filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ipsec-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 630f902ecf..577ac54666 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -48,5 +48,14 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NsdManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.IPSEC_SERVICE, + IpSecManager.class, + (context, serviceBinder) -> { + IIpSecService service = IIpSecService.Stub.asInterface(serviceBinder); + return new IpSecManager(context, service); + } + ); } } diff --git a/service-t/Sources.bp b/service-t/Sources.bp index d05370f9ba..c3049dabef 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -88,7 +88,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ], path: "src", @@ -98,6 +97,7 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ipsec-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/service-t/src/com/android/server/IpSecService.java b/service-t/src/com/android/server/IpSecService.java index 179d9459fd..4bc40eae44 100644 --- a/service-t/src/com/android/server/IpSecService.java +++ b/service-t/src/com/android/server/IpSecService.java @@ -1008,16 +1008,10 @@ public class IpSecService extends IIpSecService.Stub { * * @param context Binder context for this service */ - private IpSecService(Context context) { + public IpSecService(Context context) { this(context, new Dependencies()); } - static IpSecService create(Context context) - throws InterruptedException { - final IpSecService service = new IpSecService(context); - return service; - } - @NonNull private AppOpsManager getAppOpsManager() { AppOpsManager appOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); @@ -1054,26 +1048,6 @@ public class IpSecService extends IIpSecService.Stub { } } - /** Called by system server when system is ready. */ - public void systemReady() { - if (isNetdAlive()) { - Log.d(TAG, "IpSecService is ready"); - } else { - Log.wtf(TAG, "IpSecService not ready: failed to connect to NetD Native Service!"); - } - } - - synchronized boolean isNetdAlive() { - try { - if (mNetd == null) { - return false; - } - return mNetd.isAlive(); - } catch (RemoteException re) { - return false; - } - } - /** * Checks that the provided InetAddress is valid for use in an IPsec SA. The address must not be * a wildcard address and must be in a numeric form such as 1.2.3.4 or 2001::1. @@ -1896,7 +1870,6 @@ public class IpSecService extends IIpSecService.Stub { mContext.enforceCallingOrSelfPermission(DUMP, TAG); pw.println("IpSecService dump:"); - pw.println("NetdNativeService Connection: " + (isNetdAlive() ? "alive" : "dead")); pw.println(); pw.println("mUserResourceTracker:"); From 29cf58992de9ec4fdabc3dfc79be040ef519eff2 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sun, 30 Jan 2022 11:27:16 +0000 Subject: [PATCH 1109/1150] Expose EthernetManager state and control APIs. This CL exposes EthernetManager APIs that settings and other system components can use to modify and monitor Ethernet state. The new APIs are similar to the existing @hide methods but pass on more information and meet API guidelines: 1. Add an InterfaceStateListener interface, and addInterfaceStateListener and removeInterfaceStateListener methods that meet API guidelines (e.g., take Executor, take SAM parameter last, etc.) This new listener passes interface state (absent, up, down), role (client or server) and IP configuration. 2. Implement the legacy Listener type as a subinterface of the new interface. Hopefully existing callers should be able to use it unchanged. 3. Expose setIncludeTestInterfaces as module-lib api instead of TestApi, since modules cannot expose TestApi methods. Bug: 210586283 Test: m Test: atest EthernetServiceTests Test: atest EthernetTetheringTest Change-Id: I88240a546ab51d128ed83775499f2bcabab74db0 --- .../src/android/net/EthernetManager.java | 158 ++++++++++++++++-- .../android/net/IEthernetServiceListener.aidl | 5 +- 2 files changed, 144 insertions(+), 19 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 1f67f6d654..1a955c4c57 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -16,14 +16,16 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; @@ -33,13 +35,15 @@ import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.BiConsumer; /** - * A class representing the IP configuration of the Ethernet network. + * A class that manages and configures Ethernet interfaces. * * @hide */ @@ -54,11 +58,13 @@ public class EthernetManager { private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override - public void onAvailabilityChanged(String iface, boolean isAvailable) { + public void onInterfaceStateChanged(String iface, int state, int role, + IpConfiguration configuration) { synchronized (mListeners) { for (ListenerInfo li : mListeners) { li.executor.execute(() -> - li.listener.onAvailabilityChanged(iface, isAvailable)); + li.listener.onInterfaceStateChanged(iface, state, role, + configuration)); } } } @@ -68,19 +74,93 @@ public class EthernetManager { @NonNull public final Executor executor; @NonNull - public final Listener listener; + public final InterfaceStateListener listener; - private ListenerInfo(@NonNull Executor executor, @NonNull Listener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { this.executor = executor; this.listener = listener; } } /** - * A listener interface to receive notification on changes in Ethernet. + * The interface is absent. * @hide */ - public interface Listener { + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_ABSENT = 0; + + /** + * The interface is present but link is down. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_DOWN = 1; + + /** + * The interface is present and link is up. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_UP = 2; + + /** @hide */ + @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP}) + @Retention(RetentionPolicy.SOURCE) + public @interface InterfaceState {} + + /** + * The interface currently does not have any specific role. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_NONE = 0; + + /** + * The interface is in client mode (e.g., connected to the Internet). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_CLIENT = 1; + + /** + * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_SERVER = 2; + + /** @hide */ + @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER}) + @Retention(RetentionPolicy.SOURCE) + public @interface Role {} + + /** + * A listener that receives notifications about the state of Ethernet interfaces on the system. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public interface InterfaceStateListener { + /** + * Called when an Ethernet interface changes state. + * + * @param iface the name of the interface. + * @param state the current state of the interface, or {@link #STATE_ABSENT} if the + * interface was removed. + * @param role whether the interface is in the client mode or server mode. + * @param configuration the current IP configuration of the interface. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration); + } + + /** + * A listener interface to receive notification on changes in Ethernet. + * This has never been a supported API. Use {@link InterfaceStateListener} instead. + * @hide + */ + public interface Listener extends InterfaceStateListener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name @@ -89,6 +169,13 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); + + /** Default implementation for backwards compatibility. Only calls the legacy listener. */ + default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration) { + onAvailabilityChanged(iface, (state >= STATE_LINK_UP)); + } + } /** @@ -121,7 +208,7 @@ public class EthernetManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setConfiguration(String iface, IpConfiguration config) { + public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) { try { mService.setConfiguration(iface, config); } catch (RemoteException e) { @@ -155,9 +242,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. * - * Consider using {@link #addListener(Listener, Executor)} instead: this method uses a default - * executor that may have higher latency than a provided executor. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. * @hide @@ -169,6 +255,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. + * * @param listener A {@link Listener} to add. * @param executor Executor to run callbacks on. * @throws IllegalArgumentException If the listener or executor is null. @@ -176,6 +264,28 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(@NonNull Listener listener, @NonNull Executor executor) { + addInterfaceStateListener(executor, listener); + } + + /** + * Listen to changes in the state of Ethernet interfaces. + * + * Adds a listener to receive notification for any state change of all existing Ethernet + * interfaces. + *

            {@link Listener#onInterfaceStateChanged} will be triggered immediately for all + * existing interfaces upon adding a listener. The same method will be called on the + * listener every time any of the interface changes state. In particular, if an + * interface is removed, it will be called with state {@link #STATE_ABSENT}. + *

            Use {@link #removeInterfaceStateListener} with the same object to stop listening. + * + * @param executor Executor to run callbacks on. + * @param listener A {@link Listener} to add. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addInterfaceStateListener(@NonNull Executor executor, + @NonNull InterfaceStateListener listener) { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } @@ -206,15 +316,13 @@ public class EthernetManager { /** * Removes a listener. + * * @param listener A {@link Listener} to remove. - * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(@NonNull Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + @SystemApi(client = MODULE_LIBRARIES) + public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { + Objects.requireNonNull(listener); synchronized (mListeners) { mListeners.removeIf(l -> l.listener == listener); if (mListeners.isEmpty()) { @@ -227,13 +335,27 @@ public class EthernetManager { } } + /** + * Removes a listener. + * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead. + * @param listener A {@link Listener} to remove. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void removeListener(@NonNull Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + removeInterfaceStateListener(listener); + } + /** * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} * as Ethernet interfaces. The effects of this method apply to any test interfaces that are * already present on the system. * @hide */ - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setIncludeTestInterfaces(boolean include) { try { mService.setIncludeTestInterfaces(include); diff --git a/framework-t/src/android/net/IEthernetServiceListener.aidl b/framework-t/src/android/net/IEthernetServiceListener.aidl index 782fa19d9d..6d2ba03f78 100644 --- a/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -16,8 +16,11 @@ package android.net; +import android.net.IpConfiguration; + /** @hide */ oneway interface IEthernetServiceListener { - void onAvailabilityChanged(String iface, boolean isAvailable); + void onInterfaceStateChanged(String iface, int state, int role, + in IpConfiguration configuration); } From 2c266fbc3b1507029aec8003d9ddd8e9ef16b028 Mon Sep 17 00:00:00 2001 From: lifr Date: Mon, 1 Nov 2021 18:50:54 +0800 Subject: [PATCH 1110/1150] [SUBID01-0]Grow NetworkIdentity to include a new mSubId field In the previous design of NSS and NPMS, those only had IMSI to identify the cell network. Now the telephony has created the "subId" handle, which is the preferred mechanism for identifying subscribers. This commit adds NetworkStats support for subscriberId as a part of the network identity key Bug: 80526261 Test: atest NetworkTemplateTest NetworkStatsCollectionTest NetworkStatsServiceTest NetworkIdentityTest NetworkStatsDataMigrationUtilsTest Change-Id: Ie1fe81006555dbcca4b62457fa6c319f04b4576d --- .../src/android/net/NetworkIdentity.java | 39 ++++++++++++++++--- .../src/android/net/NetworkIdentitySet.java | 14 ++++++- .../src/android/net/NetworkStateSnapshot.java | 21 +++++++++- .../server/net/NetworkStatsService.java | 13 +++++-- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 4ebaf2b8cd..a48f94b66d 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -20,6 +20,7 @@ import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.IntDef; import android.annotation.NonNull; @@ -86,6 +87,7 @@ public class NetworkIdentity { final int mType; final int mRatType; + final int mSubId; final String mSubscriberId; final String mWifiNetworkKey; final boolean mRoaming; @@ -96,7 +98,7 @@ public class NetworkIdentity { /** @hide */ public NetworkIdentity( int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, - boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged) { + boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) { mType = type; mRatType = ratType; mSubscriberId = subscriberId; @@ -105,12 +107,13 @@ public class NetworkIdentity { mMetered = metered; mDefaultNetwork = defaultNetwork; mOemManaged = oemManaged; + mSubId = subId; } @Override public int hashCode() { return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, - mDefaultNetwork, mOemManaged); + mDefaultNetwork, mOemManaged, mSubId); } @Override @@ -122,7 +125,8 @@ public class NetworkIdentity { && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) && mMetered == ident.mMetered && mDefaultNetwork == ident.mDefaultNetwork - && mOemManaged == ident.mOemManaged; + && mOemManaged == ident.mOemManaged + && mSubId == ident.mSubId; } return false; } @@ -150,6 +154,7 @@ public class NetworkIdentity { builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); + builder.append(", subId=").append(mSubId); return builder.append("}").toString(); } @@ -256,6 +261,11 @@ public class NetworkIdentity { return mOemManaged; } + /** Get the SubId of this instance. */ + public int getSubId() { + return mSubId; + } + /** * Assemble a {@link NetworkIdentity} from the passed arguments. * @@ -276,7 +286,8 @@ public class NetworkIdentity { public static NetworkIdentity buildNetworkIdentity(Context context, @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() - .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork); + .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork) + .setSubId(snapshot.getSubId()); if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { builder.setRatType(ratType); } @@ -325,6 +336,9 @@ public class NetworkIdentity { if (res == 0) { res = Integer.compare(left.mOemManaged, right.mOemManaged); } + if (res == 0) { + res = Integer.compare(left.mSubId, right.mSubId); + } return res; } @@ -345,6 +359,7 @@ public class NetworkIdentity { private boolean mMetered; private boolean mDefaultNetwork; private int mOemManaged; + private int mSubId; /** * Creates a new Builder. @@ -359,6 +374,7 @@ public class NetworkIdentity { mMetered = false; mDefaultNetwork = false; mOemManaged = NetworkTemplate.OEM_MANAGED_NO; + mSubId = INVALID_SUBSCRIPTION_ID; } /** @@ -537,6 +553,19 @@ public class NetworkIdentity { return this; } + /** + * Set the Subscription Id. + * + * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not + * applicable. + * @return this builder. + */ + @NonNull + public Builder setSubId(int subId) { + mSubId = subId; + return this; + } + private void ensureValidParameters() { // Assert non-mobile network cannot have a ratType. if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { @@ -559,7 +588,7 @@ public class NetworkIdentity { public NetworkIdentity build() { ensureValidParameters(); return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, - mRoaming, mMetered, mDefaultNetwork, mOemManaged); + mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId); } } } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index 2236d70c35..56461babfe 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -17,6 +17,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.service.NetworkIdentitySetProto; @@ -42,6 +43,7 @@ public class NetworkIdentitySet extends HashSet { private static final int VERSION_ADD_METERED = 4; private static final int VERSION_ADD_DEFAULT_NETWORK = 5; private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; + private static final int VERSION_ADD_SUB_ID = 7; /** * Construct a {@link NetworkIdentitySet} object. @@ -103,8 +105,15 @@ public class NetworkIdentitySet extends HashSet { oemNetCapabilities = NetworkIdentity.OEM_NONE; } + final int subId; + if (version >= VERSION_ADD_SUB_ID) { + subId = in.readInt(); + } else { + subId = INVALID_SUBSCRIPTION_ID; + } + add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemNetCapabilities)); + defaultNetwork, oemNetCapabilities, subId)); } } @@ -113,7 +122,7 @@ public class NetworkIdentitySet extends HashSet { * @hide */ public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); + out.writeInt(VERSION_ADD_SUB_ID); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -124,6 +133,7 @@ public class NetworkIdentitySet extends HashSet { out.writeBoolean(ident.isMetered()); out.writeBoolean(ident.isDefaultNetwork()); out.writeInt(ident.getOemManaged()); + out.writeInt(ident.getSubId()); } } diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java index d577aa8fba..c018e91655 100644 --- a/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/framework-t/src/android/net/NetworkStateSnapshot.java @@ -17,6 +17,8 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.annotation.Nullable; @@ -98,12 +100,29 @@ public final class NetworkStateSnapshot implements Parcelable { return mLinkProperties; } - /** Get the Subscriber Id of the network associated with this snapshot. */ + /** + * Get the Subscriber Id of the network associated with this snapshot. + * @deprecated Please use #getSubId, which doesn't return personally identifiable + * information. + */ + @Deprecated @Nullable public String getSubscriberId() { return mSubscriberId; } + /** Get the subId of the network associated with this snapshot. */ + public int getSubId() { + if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier(); + if (spec instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); + } + } + return INVALID_SUBSCRIPTION_ID; + } + + /** * Get the legacy type of the network associated with this snapshot. * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 7a5ba09f27..c35bd2da42 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1484,10 +1484,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), - ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(), - ident.isRoaming(), true /* metered */, - true /* onDefaultNetwork */, ident.getOemManaged()); + NetworkIdentity vtIdent = new NetworkIdentity.Builder() + .setType(ident.getType()) + .setRatType(ident.getRatType()) + .setSubscriberId(ident.getSubscriberId()) + .setWifiNetworkKey(ident.getWifiNetworkKey()) + .setRoaming(ident.isRoaming()).setMetered(true) + .setDefaultNetwork(true) + .setOemManaged(ident.getOemManaged()) + .setSubId(ident.getSubId()).build(); final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); From ca0be94009194dbcae8023d7ac738501aedd5037 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 3 Feb 2022 19:09:36 -0800 Subject: [PATCH 1111/1150] Making EthernetNetworkSpecifier public Bug: 210485380 Test: atest EthernetServiceTests atest CtsNetTestCasesLatestSdk Change-Id: Ic0b7a3360745632eb024a97692e49f6c8dafa3ee Merged-In: Ic0b7a3360745632eb024a97692e49f6c8dafa3ee --- framework-t/src/android/net/EthernetNetworkSpecifier.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkSpecifier.java b/framework-t/src/android/net/EthernetNetworkSpecifier.java index 925d12b574..e4d6e248d4 100644 --- a/framework-t/src/android/net/EthernetNetworkSpecifier.java +++ b/framework-t/src/android/net/EthernetNetworkSpecifier.java @@ -18,7 +18,6 @@ package android.net; import android.annotation.NonNull; import android.annotation.Nullable; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; @@ -29,9 +28,7 @@ import java.util.Objects; * A {@link NetworkSpecifier} used to identify ethernet interfaces. * * @see EthernetManager - * @hide */ -@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) public final class EthernetNetworkSpecifier extends NetworkSpecifier implements Parcelable { /** @@ -61,6 +58,7 @@ public final class EthernetNetworkSpecifier extends NetworkSpecifier implements return mInterfaceName; } + /** @hide */ @Override public boolean canBeSatisfiedBy(@Nullable NetworkSpecifier other) { return equals(other); From 336d3c71b398b27267c2ce41ea952b9f04efc7dc Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 11 Feb 2022 14:08:02 +0800 Subject: [PATCH 1112/1150] Replace qtaguid_deleteTagData with java implementation Copies the behavior of TrafficController::deleteTagData. Test: atest NetworkStatsServiceTest Change-Id: I436ce514108486db712b455f1b5fd8dca345c65c --- .../server/net/NetworkStatsService.java | 132 ++++++++++++++++-- ...android_server_net_NetworkStatsService.cpp | 5 - 2 files changed, 117 insertions(+), 20 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 9f3371b724..eeb56d05e7 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -51,6 +51,7 @@ import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_UID_TAG; import static android.net.netstats.NetworkStatsDataMigrationUtils.PREFIX_XT; import static android.os.Trace.TRACE_TAG_NETWORK; +import static android.system.OsConstants.ENOENT; import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import static android.text.format.DateUtils.DAY_IN_MILLIS; import static android.text.format.DateUtils.HOUR_IN_MILLIS; @@ -120,7 +121,6 @@ import android.provider.Settings.Global; import android.service.NetworkInterfaceProto; import android.service.NetworkStatsServiceDumpProto; import android.system.ErrnoException; -import android.system.Os; import android.telephony.PhoneStateListener; import android.telephony.SubscriptionPlan; import android.text.TextUtils; @@ -214,6 +214,14 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // This is current path but may be changed soon. private static final String UID_COUNTERSET_MAP_PATH = "/sys/fs/bpf/map_netd_uid_counterset_map"; + private static final String COOKIE_TAG_MAP_PATH = + "/sys/fs/bpf/map_netd_cookie_tag_map"; + private static final String APP_UID_STATS_MAP_PATH = + "/sys/fs/bpf/map_netd_app_uid_stats_map"; + private static final String STATS_MAP_A_PATH = + "/sys/fs/bpf/map_netd_stats_map_A"; + private static final String STATS_MAP_B_PATH = + "/sys/fs/bpf/map_netd_stats_map_B"; private final Context mContext; private final NetworkStatsFactory mStatsFactory; @@ -341,6 +349,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { */ private SparseIntArray mActiveUidCounterSet = new SparseIntArray(); private final IBpfMap mUidCounterSetMap; + private final IBpfMap mCookieTagMap; + private final IBpfMap mStatsMapA; + private final IBpfMap mStatsMapB; + private final IBpfMap mAppUidStatsMap; /** Data layer operation counters for splicing into other structures. */ private NetworkStats mUidOperations = new NetworkStats(0L, 10); @@ -474,6 +486,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mInterfaceMapUpdater = mDeps.makeBpfInterfaceMapUpdater(mContext, mHandler); mInterfaceMapUpdater.start(); mUidCounterSetMap = mDeps.getUidCounterSetMap(); + mCookieTagMap = mDeps.getCookieTagMap(); + mStatsMapA = mDeps.getStatsMapA(); + mStatsMapB = mDeps.getStatsMapB(); + mAppUidStatsMap = mDeps.getAppUidStatsMap(); } /** @@ -547,8 +563,48 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } } - public TagStatsDeleter getTagStatsDeleter() { - return NetworkStatsService::nativeDeleteTagData; + /** Gets the cookie tag map */ + public IBpfMap getCookieTagMap() { + try { + return new BpfMap(COOKIE_TAG_MAP_PATH, + BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create cookie tag map: " + e); + return null; + } + } + + /** Gets stats map A */ + public IBpfMap getStatsMapA() { + try { + return new BpfMap(STATS_MAP_A_PATH, + BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create stats map A: " + e); + return null; + } + } + + /** Gets stats map B */ + public IBpfMap getStatsMapB() { + try { + return new BpfMap(STATS_MAP_B_PATH, + BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create stats map B: " + e); + return null; + } + } + + /** Gets the uid stats map */ + public IBpfMap getAppUidStatsMap() { + try { + return new BpfMap(APP_UID_STATS_MAP_PATH, + BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class); + } catch (ErrnoException e) { + Log.wtf(TAG, "Cannot create app uid stats map: " + e); + return null; + } } } @@ -1790,6 +1846,63 @@ public class NetworkStatsService extends INetworkStatsService.Stub { currentTime); } + // deleteKernelTagData can ignore ENOENT; otherwise we should log an error + private void logErrorIfNotErrNoent(final ErrnoException e, final String msg) { + if (e.errno != ENOENT) Log.e(TAG, msg, e); + } + + private void deleteStatsMapTagData( + IBpfMap statsMap, int uid) { + try { + statsMap.forEach((key, value) -> { + if (key.uid == uid) { + try { + statsMap.deleteEntry(key); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete data(uid = " + key.uid + ")"); + } + } + }); + } catch (ErrnoException e) { + Log.e(TAG, "FAILED to delete tag data from stats map", e); + } + } + + /** + * Deletes uid tag data from CookieTagMap, StatsMapA, StatsMapB, and UidStatsMap + * @param uid + */ + private void deleteKernelTagData(int uid) { + try { + mCookieTagMap.forEach((key, value) -> { + if (value.uid == uid) { + try { + mCookieTagMap.deleteEntry(key); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete data(cookie = " + key + ")"); + } + } + }); + } catch (ErrnoException e) { + Log.e(TAG, "Failed to delete tag data from cookie tag map", e); + } + + deleteStatsMapTagData(mStatsMapA, uid); + deleteStatsMapTagData(mStatsMapB, uid); + + try { + mUidCounterSetMap.deleteEntry(new U32(uid)); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete tag data from uid counter set map"); + } + + try { + mAppUidStatsMap.deleteEntry(new UidStatsMapKey(uid)); + } catch (ErrnoException e) { + logErrorIfNotErrNoent(e, "Failed to delete tag data from app uid stats map"); + } + } + /** * Clean up {@link #mUidRecorder} after UID is removed. */ @@ -1805,10 +1918,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Clear kernel stats associated with UID for (int uid : uids) { - final int ret = mDeps.getTagStatsDeleter().deleteTagData(uid); - if (ret < 0) { - Log.w(TAG, "problem clearing counters for uid " + uid + ": " + Os.strerror(-ret)); - } + deleteKernelTagData(uid); } } @@ -2387,12 +2497,4 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private static native long nativeGetTotalStat(int type); private static native long nativeGetIfaceStat(String iface, int type); private static native long nativeGetUidStat(int uid, int type); - - // TODO: use BpfNetMaps to delete tag data and remove this. - @VisibleForTesting - interface TagStatsDeleter { - int deleteTagData(int uid); - } - - private static native int nativeDeleteTagData(int uid); } diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/services/core/jni/com_android_server_net_NetworkStatsService.cpp index f8a81682bd..39cbaf716f 100644 --- a/services/core/jni/com_android_server_net_NetworkStatsService.cpp +++ b/services/core/jni/com_android_server_net_NetworkStatsService.cpp @@ -102,15 +102,10 @@ static jlong getUidStat(JNIEnv* env, jclass clazz, jint uid, jint type) { } } -static int deleteTagData(JNIEnv* /* env */, jclass /* clazz */, jint uid) { - return qtaguid_deleteTagData(0, uid); -} - static const JNINativeMethod gMethods[] = { {"nativeGetTotalStat", "(I)J", (void*)getTotalStat}, {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*)getIfaceStat}, {"nativeGetUidStat", "(II)J", (void*)getUidStat}, - {"nativeDeleteTagData", "(I)I", (void*)deleteTagData}, }; int register_android_server_net_NetworkStatsService(JNIEnv* env) { From 11170dd9ef00ec57b85772494be1dd1c75b24f1a Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Sun, 30 Jan 2022 11:27:16 +0000 Subject: [PATCH 1113/1150] Expose EthernetManager state and control APIs. This CL exposes EthernetManager APIs that settings and other system components can use to modify and monitor Ethernet state. The new APIs are similar to the existing @hide methods but pass on more information and meet API guidelines: 1. Add an InterfaceStateListener interface, and addInterfaceStateListener and removeInterfaceStateListener methods that meet API guidelines (e.g., take Executor, take SAM parameter last, etc.) This new listener passes interface state (absent, up, down), role (client or server) and IP configuration. 2. Implement the legacy Listener type as a subinterface of the new interface. Hopefully existing callers should be able to use it unchanged. 3. Expose setIncludeTestInterfaces as module-lib api instead of TestApi, since modules cannot expose TestApi methods. Bug: 210586283 Test: m Test: atest EthernetServiceTests Test: atest EthernetTetheringTest Change-Id: I88240a546ab51d128ed83775499f2bcabab74db0 Merged-In: I88240a546ab51d128ed83775499f2bcabab74db0 --- .../src/android/net/EthernetManager.java | 158 ++++++++++++++++-- .../android/net/IEthernetServiceListener.aidl | 5 +- 2 files changed, 144 insertions(+), 19 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 1f67f6d654..1a955c4c57 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -16,14 +16,16 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import android.annotation.CallbackExecutor; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresFeature; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; @@ -33,13 +35,15 @@ import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.BiConsumer; /** - * A class representing the IP configuration of the Ethernet network. + * A class that manages and configures Ethernet interfaces. * * @hide */ @@ -54,11 +58,13 @@ public class EthernetManager { private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { @Override - public void onAvailabilityChanged(String iface, boolean isAvailable) { + public void onInterfaceStateChanged(String iface, int state, int role, + IpConfiguration configuration) { synchronized (mListeners) { for (ListenerInfo li : mListeners) { li.executor.execute(() -> - li.listener.onAvailabilityChanged(iface, isAvailable)); + li.listener.onInterfaceStateChanged(iface, state, role, + configuration)); } } } @@ -68,19 +74,93 @@ public class EthernetManager { @NonNull public final Executor executor; @NonNull - public final Listener listener; + public final InterfaceStateListener listener; - private ListenerInfo(@NonNull Executor executor, @NonNull Listener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { this.executor = executor; this.listener = listener; } } /** - * A listener interface to receive notification on changes in Ethernet. + * The interface is absent. * @hide */ - public interface Listener { + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_ABSENT = 0; + + /** + * The interface is present but link is down. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_DOWN = 1; + + /** + * The interface is present and link is up. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int STATE_LINK_UP = 2; + + /** @hide */ + @IntDef(prefix = "STATE_", value = {STATE_ABSENT, STATE_LINK_DOWN, STATE_LINK_UP}) + @Retention(RetentionPolicy.SOURCE) + public @interface InterfaceState {} + + /** + * The interface currently does not have any specific role. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_NONE = 0; + + /** + * The interface is in client mode (e.g., connected to the Internet). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_CLIENT = 1; + + /** + * Ethernet interface is in server mode (e.g., providing Internet access to tethered devices). + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ROLE_SERVER = 2; + + /** @hide */ + @IntDef(prefix = "ROLE_", value = {ROLE_NONE, ROLE_CLIENT, ROLE_SERVER}) + @Retention(RetentionPolicy.SOURCE) + public @interface Role {} + + /** + * A listener that receives notifications about the state of Ethernet interfaces on the system. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public interface InterfaceStateListener { + /** + * Called when an Ethernet interface changes state. + * + * @param iface the name of the interface. + * @param state the current state of the interface, or {@link #STATE_ABSENT} if the + * interface was removed. + * @param role whether the interface is in the client mode or server mode. + * @param configuration the current IP configuration of the interface. + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration); + } + + /** + * A listener interface to receive notification on changes in Ethernet. + * This has never been a supported API. Use {@link InterfaceStateListener} instead. + * @hide + */ + public interface Listener extends InterfaceStateListener { /** * Called when Ethernet port's availability is changed. * @param iface Ethernet interface name @@ -89,6 +169,13 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) void onAvailabilityChanged(String iface, boolean isAvailable); + + /** Default implementation for backwards compatibility. Only calls the legacy listener. */ + default void onInterfaceStateChanged(@NonNull String iface, @InterfaceState int state, + @Role int role, @Nullable IpConfiguration configuration) { + onAvailabilityChanged(iface, (state >= STATE_LINK_UP)); + } + } /** @@ -121,7 +208,7 @@ public class EthernetManager { * @hide */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void setConfiguration(String iface, IpConfiguration config) { + public void setConfiguration(@NonNull String iface, @NonNull IpConfiguration config) { try { mService.setConfiguration(iface, config); } catch (RemoteException e) { @@ -155,9 +242,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. * - * Consider using {@link #addListener(Listener, Executor)} instead: this method uses a default - * executor that may have higher latency than a provided executor. * @param listener A {@link Listener} to add. * @throws IllegalArgumentException If the listener is null. * @hide @@ -169,6 +255,8 @@ public class EthernetManager { /** * Adds a listener. + * This has never been a supported API. Use {@link #addInterfaceStateListener} instead. + * * @param listener A {@link Listener} to add. * @param executor Executor to run callbacks on. * @throws IllegalArgumentException If the listener or executor is null. @@ -176,6 +264,28 @@ public class EthernetManager { */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) public void addListener(@NonNull Listener listener, @NonNull Executor executor) { + addInterfaceStateListener(executor, listener); + } + + /** + * Listen to changes in the state of Ethernet interfaces. + * + * Adds a listener to receive notification for any state change of all existing Ethernet + * interfaces. + *

            {@link Listener#onInterfaceStateChanged} will be triggered immediately for all + * existing interfaces upon adding a listener. The same method will be called on the + * listener every time any of the interface changes state. In particular, if an + * interface is removed, it will be called with state {@link #STATE_ABSENT}. + *

            Use {@link #removeInterfaceStateListener} with the same object to stop listening. + * + * @param executor Executor to run callbacks on. + * @param listener A {@link Listener} to add. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addInterfaceStateListener(@NonNull Executor executor, + @NonNull InterfaceStateListener listener) { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } @@ -206,15 +316,13 @@ public class EthernetManager { /** * Removes a listener. + * * @param listener A {@link Listener} to remove. - * @throws IllegalArgumentException If the listener is null. * @hide */ - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - public void removeListener(@NonNull Listener listener) { - if (listener == null) { - throw new IllegalArgumentException("listener must not be null"); - } + @SystemApi(client = MODULE_LIBRARIES) + public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { + Objects.requireNonNull(listener); synchronized (mListeners) { mListeners.removeIf(l -> l.listener == listener); if (mListeners.isEmpty()) { @@ -227,13 +335,27 @@ public class EthernetManager { } } + /** + * Removes a listener. + * This has never been a supported API. Use {@link #removeInterfaceStateListener} instead. + * @param listener A {@link Listener} to remove. + * @hide + */ + @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) + public void removeListener(@NonNull Listener listener) { + if (listener == null) { + throw new IllegalArgumentException("listener must not be null"); + } + removeInterfaceStateListener(listener); + } + /** * Whether to treat interfaces created by {@link TestNetworkManager#createTapInterface} * as Ethernet interfaces. The effects of this method apply to any test interfaces that are * already present on the system. * @hide */ - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setIncludeTestInterfaces(boolean include) { try { mService.setIncludeTestInterfaces(include); diff --git a/framework-t/src/android/net/IEthernetServiceListener.aidl b/framework-t/src/android/net/IEthernetServiceListener.aidl index 782fa19d9d..6d2ba03f78 100644 --- a/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -16,8 +16,11 @@ package android.net; +import android.net.IpConfiguration; + /** @hide */ oneway interface IEthernetServiceListener { - void onAvailabilityChanged(String iface, boolean isAvailable); + void onInterfaceStateChanged(String iface, int state, int role, + in IpConfiguration configuration); } From c54e4f397bef2adcd7e71d91760cb558d4bbd27b Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 11 Feb 2022 12:18:59 +0900 Subject: [PATCH 1114/1150] Fix grammar nit in comment. Test: None Change-Id: I60cb2478615efce13f1904092abe5c21bdf0dc9a --- framework-t/src/android/net/EthernetManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 1a955c4c57..72243f9e87 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -146,7 +146,7 @@ public class EthernetManager { * @param iface the name of the interface. * @param state the current state of the interface, or {@link #STATE_ABSENT} if the * interface was removed. - * @param role whether the interface is in the client mode or server mode. + * @param role whether the interface is in client mode or server mode. * @param configuration the current IP configuration of the interface. * @hide */ From 01a87ca336f5a47c462fdbba696106c9e8d5a97e Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Mon, 17 Jan 2022 17:37:19 +0000 Subject: [PATCH 1115/1150] [MS62.1] Start NetworkStatsService from the module NetworkStatsService is going to be moved into Connectivity mainlne module and it will be not visible to SystemServiceResistry after migration done. Thus: 1. Register service in NetworkStatsServiceInitialalizer, a separate initializer is needed because the service needs to be created before NetworkPolicyManagerService's initialization. 2. Call SystemReady at PHASE_ACTIVITY_MANAGER_READY phase where it needs to be ready before StatsPullAtomService pulls at PHASE_THIRD_PARTY_APPS_CAN_START. 3. Register manager in ConnectivityFrameworkInitializerTiramisu instead of SystemServiceRegistery. Test: atest FrameworksNetTests CtsNetTestCases NetworkUsageStatsTest Bug: 204830222 (cherry-picked from ag/16688794) Change-Id: I95020d816ed613ce3480a0720a5b71dcdc7fab72 Merged-In: I95020d816ed613ce3480a0720a5b71dcdc7fab72 --- .../net/ConnectivityFrameworkInitializerTiramisu.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 577ac54666..9bffbfb27a 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SystemApi; import android.app.SystemServiceRegistry; +import android.app.usage.NetworkStatsManager; import android.content.Context; import android.net.nsd.INsdManager; import android.net.nsd.NsdManager; @@ -57,5 +58,15 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new IpSecManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.NETWORK_STATS_SERVICE, + NetworkStatsManager.class, + (context, serviceBinder) -> { + INetworkStatsService service = + INetworkStatsService.Stub.asInterface(serviceBinder); + return new NetworkStatsManager(context, service); + } + ); } } From 63627bce56e929cd515714741622a30c1a94ba71 Mon Sep 17 00:00:00 2001 From: Junyu Lai Date: Wed, 26 Jan 2022 09:00:41 +0000 Subject: [PATCH 1116/1150] [MS54.1] Move NetworkStats to updatable sources This CL builds NetworkStats related code with the connectivity module instead of platform. This includes: 1. Add netstats.proto to the module. 2. Add lib dependencies for all callers. 3. Include several source files in platform and add jarjar rule to it. Modify callers accordingly. Test: TH Bug: 197717846 Change-Id: I244693aebe1782d9e67502638ff8145c51462e1e Merged-In: I244693aebe1782d9e67502638ff8145c51462e1e --- framework-t/Sources.bp | 4 +--- .../src/android/net/NetworkIdentity.java | 10 ++++----- .../src/android/net/NetworkIdentitySet.java | 2 +- .../android/net/NetworkStatsCollection.java | 14 ++++++------ .../src/android/net/NetworkStatsHistory.java | 17 +++++++------- service-t/Sources.bp | 2 +- .../server/net/NetworkStatsRecorder.java | 6 +++-- .../server/net/NetworkStatsService.java | 22 ++++++++++++------- .../net/NetworkStatsSubscriptionsMonitor.java | 3 +++ 9 files changed, 45 insertions(+), 35 deletions(-) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 6329565ca5..b30e54d20b 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -158,7 +158,6 @@ filegroup { name: "framework-connectivity-tiramisu-sources", srcs: [ ":framework-connectivity-ethernet-sources", - ":framework-connectivity-netstats-sources", ], visibility: ["//frameworks/base"], } @@ -167,6 +166,7 @@ filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ ":framework-connectivity-ipsec-sources", + ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", ":framework-connectivity-tiramisu-internal-sources", ], @@ -202,7 +202,5 @@ cc_library_shared { stl: "none", apex_available: [ "com.android.tethering", - // TODO: remove when ConnectivityT moves to APEX. - "//apex_available:platform", ], } diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 56faa52e82..4ebaf2b8cd 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -184,14 +184,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE, mType); + proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING, mRoaming); - proto.write(NetworkIdentityProto.METERED, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); + proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); proto.end(start); } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index dfa347f6f1..2236d70c35 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -212,7 +212,7 @@ public class NetworkIdentitySet extends HashSet { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); } proto.end(start); diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 735c44d5c8..67d48f0000 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); - proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); + proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); proto.end(startStats); } diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 78c137073a..822a16e0bb 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,17 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + bucketStart[i]); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); proto.end(startBucket); } diff --git a/service-t/Sources.bp b/service-t/Sources.bp index c3049dabef..502c56a7fb 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -88,7 +88,6 @@ filegroup { name: "services.connectivity-tiramisu-sources", srcs: [ ":services.connectivity-ethernet-sources", - ":services.connectivity-netstats-sources", ], path: "src", visibility: ["//frameworks/base/services/core"], @@ -98,6 +97,7 @@ filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ ":services.connectivity-ipsec-sources", + ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", ], path: "src", diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index c371f0859a..a006cd5975 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,9 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + mPending.getTotalBytes()); } - getOrLoadCompleteLocked().dumpDebug(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY); + getOrLoadCompleteLocked().dumpDebug(proto, + NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index eeb56d05e7..c441c81602 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -63,6 +63,7 @@ import static com.android.net.module.util.NetworkStatsUtils.LIMIT_GLOBAL_ALERT; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.TargetApi; import android.app.AlarmManager; import android.app.PendingIntent; import android.app.usage.NetworkStatsManager; @@ -103,6 +104,7 @@ import android.net.netstats.provider.INetworkStatsProvider; import android.net.netstats.provider.INetworkStatsProviderCallback; import android.net.netstats.provider.NetworkStatsProvider; import android.os.Binder; +import android.os.Build; import android.os.DropBoxManager; import android.os.Environment; import android.os.Handler; @@ -169,6 +171,7 @@ import java.util.concurrent.TimeUnit; * Collect and persist detailed network statistics, and provide this data to * other system services. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); @@ -2114,12 +2117,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); - mUidTagRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + mActiveIfaces); + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + mActiveUidIfaces); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mUidTagRecorder.dumpDebugLocked(proto, + NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); proto.flush(); } @@ -2129,8 +2135,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); + proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java index 5bba0b17aa..65ccd20072 100644 --- a/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java +++ b/service-t/src/com/android/server/net/NetworkStatsSubscriptionsMonitor.java @@ -23,7 +23,9 @@ import static android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NS import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE; import android.annotation.NonNull; +import android.annotation.TargetApi; import android.content.Context; +import android.os.Build; import android.telephony.SubscriptionManager; import android.telephony.TelephonyCallback; import android.telephony.TelephonyDisplayInfo; @@ -43,6 +45,7 @@ import java.util.concurrent.Executor; /** * Helper class that watches for events that are triggered per subscription. */ +@TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsSubscriptionsMonitor extends SubscriptionManager.OnSubscriptionsChangedListener { From 63d42a25bb0f234afe8d596170cbf7eda601e1bc Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Wed, 2 Feb 2022 13:22:57 +0900 Subject: [PATCH 1117/1150] Move networkstats JNI to connectivity module Reorganize networkstats JNI so it can be included in the connectivity module. Bug: 197717846 Test: m Change-Id: I815ea379f3d9915041c80ac5e743ce62e05f4cf8 Merged-In: I815ea379f3d9915041c80ac5e743ce62e05f4cf8 --- framework-t/Sources.bp | 5 ++-- service-t/Sources.bp | 24 +++++++++++++++++++ ...android_server_net_NetworkStatsFactory.cpp | 0 ...android_server_net_NetworkStatsService.cpp | 0 .../server/net/NetworkStatsFactory.java | 4 ++++ .../server/net/NetworkStatsService.java | 4 ++++ 6 files changed, 34 insertions(+), 3 deletions(-) rename {services/core => service-t}/jni/com_android_server_net_NetworkStatsFactory.cpp (100%) rename {services/core => service-t}/jni/com_android_server_net_NetworkStatsService.cpp (100%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index b30e54d20b..66527802a0 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -194,10 +194,9 @@ cc_library_shared { "jni/onload.cpp", ], shared_libs: [ + "libandroid", "liblog", - ], - static_libs: [ - "libnativehelper_compat_libc++", + "libnativehelper", ], stl: "none", apex_available: [ diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 502c56a7fb..5100e7c5b9 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -40,6 +40,30 @@ filegroup { ], } +// For test code only. +filegroup { + name: "lib_networkStatsFactory_native", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + +filegroup { + name: "services.connectivity-netstats-jni-sources", + srcs: [ + "jni/com_android_server_net_NetworkStatsFactory.cpp", + "jni/com_android_server_net_NetworkStatsService.cpp", + ], + path: "jni", + visibility: [ + "//packages/modules/Connectivity:__subpackages__", + ], +} + // Nsd related libraries. filegroup { diff --git a/services/core/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp similarity index 100% rename from services/core/jni/com_android_server_net_NetworkStatsFactory.cpp rename to service-t/jni/com_android_server_net_NetworkStatsFactory.cpp diff --git a/services/core/jni/com_android_server_net_NetworkStatsService.cpp b/service-t/jni/com_android_server_net_NetworkStatsService.cpp similarity index 100% rename from services/core/jni/com_android_server_net_NetworkStatsService.cpp rename to service-t/jni/com_android_server_net_NetworkStatsService.cpp diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index 668d1cba92..151c90dd41 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -54,6 +54,10 @@ import java.util.concurrent.ConcurrentHashMap; * @hide */ public class NetworkStatsFactory { + static { + System.loadLibrary("service-connectivity"); + } + private static final String TAG = "NetworkStatsFactory"; private static final boolean USE_NATIVE_PARSING = true; diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index c441c81602..3e4687f9d2 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -173,6 +173,10 @@ import java.util.concurrent.TimeUnit; */ @TargetApi(Build.VERSION_CODES.TIRAMISU) public class NetworkStatsService extends INetworkStatsService.Stub { + static { + System.loadLibrary("service-connectivity"); + } + static final String TAG = "NetworkStats"; static final boolean LOGD = Log.isLoggable(TAG, Log.DEBUG); static final boolean LOGV = Log.isLoggable(TAG, Log.VERBOSE); From c99a128f510cdbb2ccf44187313f356bfef5a476 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 3 Feb 2022 11:34:52 +0900 Subject: [PATCH 1118/1150] Add setPollForce to module API The API was test API in S, but this is not supported in module API surfaces. Make it module API instead. Bug: 197717846 Test: Tests already using this API (cherry-picked from ag/16780943) Change-Id: I9d44b761572f94b08b269478c4a0c20c1171343c Merged-In: I9d44b761572f94b08b269478c4a0c20c1171343c --- .../src/android/app/usage/NetworkStatsManager.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 5ce7e59b38..0414bb79f8 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -27,7 +27,6 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; -import android.annotation.TestApi; import android.annotation.WorkerThread; import android.app.usage.NetworkStats.Bucket; import android.compat.annotation.UnsupportedAppUsage; @@ -192,9 +191,13 @@ public class NetworkStatsManager { } } - /** @hide */ + /** + * Set poll force flag to indicate that calling any subsequent query method will force a stats + * poll. + * @hide + */ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) - @TestApi + @SystemApi(client = MODULE_LIBRARIES) public void setPollForce(boolean pollForce) { if (pollForce) { mFlags |= FLAG_POLL_FORCE; From fe5ed721bea0543525742b66f4d29f0d2d01d7f5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 4 Feb 2022 03:05:59 +0900 Subject: [PATCH 1119/1150] Expose MATCH_PROXY as a module-lib API. It is used by clockwork. Test: m update-api (cherry-picked from ag/16786203) Change-Id: I5676f883141afca1511c425b7c36683a6c6bfb9f Merged-In: I5676f883141afca1511c425b7c36683a6c6bfb9f --- framework-t/src/android/net/NetworkTemplate.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java index 9b58b016bb..7b5afd7200 100644 --- a/framework-t/src/android/net/NetworkTemplate.java +++ b/framework-t/src/android/net/NetworkTemplate.java @@ -79,7 +79,8 @@ public final class NetworkTemplate implements Parcelable { MATCH_WIFI, MATCH_ETHERNET, MATCH_BLUETOOTH, - MATCH_CARRIER + MATCH_PROXY, + MATCH_CARRIER, }) public @interface TemplateMatchRule{} @@ -104,9 +105,8 @@ public final class NetworkTemplate implements Parcelable { /** Match rule to match bluetooth networks. */ public static final int MATCH_BLUETOOTH = 8; /** - * Match rule to match networks with {@link Connectivity#TYPE_PROXY} as the legacy network type. - * - * @hide + * Match rule to match networks with {@link ConnectivityManager#TYPE_PROXY} as the legacy + * network type. */ public static final int MATCH_PROXY = 9; /** From 2616b49c709b2e4aca5b20fb59f571b6fd987d03 Mon Sep 17 00:00:00 2001 From: markchien Date: Fri, 18 Feb 2022 12:48:02 +0800 Subject: [PATCH 1120/1150] Fix system_server crash while iterating CookieTagMap When uid is removed, NetworkStatsService will iterate CookieTagMap and delete the corresponded uid socketTag value. But not only NetworkStatsService would detete CookieTagMap entries. There are other threads may also delete CookieTagMap entries such as #unTagSocket in bpfHandler and desctroy socket listener in TrafficController. System server crash as NPE because the CookieTagMap entry it iterate just be removed by other threads at the same time. This is just a simple fix to prevent the crash. Will have follow up CL for formal fix. Bug: 220084230 Test: m Change-Id: I08cad87f537fb09499faf1ff5cfd443fcb8ce436 --- .../src/com/android/server/net/NetworkStatsService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index eeb56d05e7..b193623114 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1875,7 +1875,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private void deleteKernelTagData(int uid) { try { mCookieTagMap.forEach((key, value) -> { - if (value.uid == uid) { + // If SkDestroyListener deletes the socket tag while this code is running, + // forEach will either restart iteration from the beginning or return null, + // depending on when the deletion happens. + // If it returns null, continue iteration to delete the data and in fact it would + // just iterate from first key because BpfMap#getNextKey would return first key + // if the current key is not exist. + if (value != null && value.uid == uid) { try { mCookieTagMap.deleteEntry(key); } catch (ErrnoException e) { From 420d6e09c9e9e95cdb931e3e7d9c3fbcd72e82dc Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 17 Feb 2022 13:06:45 -0800 Subject: [PATCH 1121/1150] Updating Eth Update Request to use Builder Updating EthernetNetworkUpdateRequest to use a builder for creation and also changing to use IpConfiguration instead of StaticIpConfiguration. Bug: 220017952 Bug: 210487893 Bug: 210485380 Test: atest EthernetServiceTests Change-Id: I78b002c12cf927c075671b75f0fe0d7878443b56 --- .../net/EthernetNetworkUpdateRequest.java | 70 +++++++++++++++++-- 1 file changed, 63 insertions(+), 7 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index e879e40247..a626971105 100644 --- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -17,6 +17,7 @@ package android.net; import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -27,13 +28,13 @@ import java.util.Objects; @SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull - private final StaticIpConfiguration mIpConfig; + private final IpConfiguration mIpConfig; @NonNull private final NetworkCapabilities mNetworkCapabilities; @NonNull - public StaticIpConfiguration getIpConfig() { - return new StaticIpConfiguration(mIpConfig); + public IpConfiguration getIpConfiguration() { + return new IpConfiguration(mIpConfig); } @NonNull @@ -41,20 +42,75 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return new NetworkCapabilities(mNetworkCapabilities); } - public EthernetNetworkUpdateRequest(@NonNull final StaticIpConfiguration ipConfig, + private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, @NonNull final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); Objects.requireNonNull(networkCapabilities); - mIpConfig = new StaticIpConfiguration(ipConfig); + mIpConfig = new IpConfiguration(ipConfig); mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); } private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); - mIpConfig = StaticIpConfiguration.CREATOR.createFromParcel(source); + mIpConfig = IpConfiguration.CREATOR.createFromParcel(source); mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); } + /** + * Builder used to create {@link EthernetNetworkUpdateRequest} objects. + */ + public static final class Builder { + @Nullable + private IpConfiguration mBuilderIpConfig; + @Nullable + private NetworkCapabilities mBuilderNetworkCapabilities; + + public Builder(){} + + /** + * Constructor to populate the builder's values with an already built + * {@link EthernetNetworkUpdateRequest}. + * @param request the {@link EthernetNetworkUpdateRequest} to populate with. + */ + public Builder(@NonNull final EthernetNetworkUpdateRequest request) { + Objects.requireNonNull(request); + mBuilderIpConfig = new IpConfiguration(request.mIpConfig); + mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities); + } + + /** + * Set the {@link IpConfiguration} to be used with the {@code Builder}. + * @param ipConfig the {@link IpConfiguration} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { + Objects.requireNonNull(ipConfig); + mBuilderIpConfig = new IpConfiguration(ipConfig); + return this; + } + + /** + * Set the {@link NetworkCapabilities} to be used with the {@code Builder}. + * @param nc the {@link NetworkCapabilities} to set. + * @return The builder to facilitate chaining. + */ + @NonNull + public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) { + Objects.requireNonNull(nc); + mBuilderNetworkCapabilities = new NetworkCapabilities(nc); + return this; + } + + /** + * Build {@link EthernetNetworkUpdateRequest} return the current update request. + */ + @NonNull + public EthernetNetworkUpdateRequest build() { + return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); + } + } + @Override public String toString() { return "EthernetNetworkUpdateRequest{" @@ -68,7 +124,7 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { if (o == null || getClass() != o.getClass()) return false; EthernetNetworkUpdateRequest that = (EthernetNetworkUpdateRequest) o; - return Objects.equals(that.getIpConfig(), mIpConfig) + return Objects.equals(that.getIpConfiguration(), mIpConfig) && Objects.equals(that.getNetworkCapabilities(), mNetworkCapabilities); } From 5c3fa07cc137845d26753635c208422663ff651e Mon Sep 17 00:00:00 2001 From: Frank Date: Wed, 9 Feb 2022 20:37:26 +0800 Subject: [PATCH 1122/1150] [DU03-4]Add NETWORK_STACK Permission check for NetworkStatsService API 1. getUidStatsForTransport API Bug: 210066922 Test: atest BatteryStatsImplTest WifiPowerCalculatorTest MobileRadioPowerCalculatorTest NetworkStatsServiceTest (cherry-picked from ag/16816095) Change-Id: I022c34b5af87fe3ff6857ea264bac2f7098eaed4 Merged-In: I022c34b5af87fe3ff6857ea264bac2f7098eaed4 --- .../src/android/app/usage/NetworkStatsManager.java | 8 ++++++-- .../src/com/android/server/net/NetworkStatsService.java | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 0414bb79f8..a8baa8e488 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -699,7 +699,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getMobileUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_CELLULAR); @@ -723,7 +725,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi - @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}) @NonNull public android.net.NetworkStats getWifiUidStats() { try { return mService.getUidStatsForTransport(TRANSPORT_WIFI); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1579f1e171..0b5a85fa4b 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1123,7 +1123,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @Override public NetworkStats getUidStatsForTransport(int transport) { - enforceAnyPermissionOf(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK); + PermissionUtils.enforceNetworkStackPermission(mContext); try { final String[] relevantIfaces = transport == TRANSPORT_WIFI ? mWifiIfaces : mMobileIfaces; From 5f93cdff5a97cc1a14fde6a4e2542a5b6f4b025d Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 28 Jan 2022 22:02:06 +0800 Subject: [PATCH 1123/1150] [MS68.3] Address comments at aosp/1958144 Test: atest TrafficStatsTest NetworkUsageStatsTest FrameworksNetTests Bug: 204830222 (cherry-picked from ag/16813003) Change-Id: I5a54b44294021d64d8506eeb570db0db8544472a Merged-In: I5a54b44294021d64d8506eeb570db0db8544472a --- .../app/usage/NetworkStatsManager.java | 8 ++++++-- .../server/net/NetworkStatsObservers.java | 20 ++++++++++++------- .../server/net/NetworkStatsService.java | 2 +- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index 0414bb79f8..221a848a59 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -740,8 +740,9 @@ public class NetworkStatsManager { * {@link #unregisterUsageCallback} is called. * * @param template Template used to match networks. See {@link NetworkTemplate}. - * @param thresholdBytes Threshold in bytes to be notified on. The provided value that lower - * than 2MiB will be clamped for non-privileged callers. + * @param thresholdBytes Threshold in bytes to be notified on. Provided values lower than 2MiB + * will be clamped for callers except callers with the NETWORK_STACK + * permission. * @param executor The executor on which callback will be invoked. The provided {@link Executor} * must run callback sequentially, otherwise the order of callbacks cannot be * guaranteed. @@ -750,6 +751,9 @@ public class NetworkStatsManager { * @hide */ @SystemApi(client = MODULE_LIBRARIES) + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK}, conditional = true) public void registerUsageCallback(@NonNull NetworkTemplate template, long thresholdBytes, @NonNull @CallbackExecutor Executor executor, @NonNull UsageCallback callback) { Objects.requireNonNull(template, "NetworkTemplate cannot be null"); diff --git a/service-t/src/com/android/server/net/NetworkStatsObservers.java b/service-t/src/com/android/server/net/NetworkStatsObservers.java index 19536247b2..fdfc893f57 100644 --- a/service-t/src/com/android/server/net/NetworkStatsObservers.java +++ b/service-t/src/com/android/server/net/NetworkStatsObservers.java @@ -19,8 +19,11 @@ package com.android.server.net; import static android.app.usage.NetworkStatsManager.MIN_THRESHOLD_BYTES; import android.app.usage.NetworkStatsManager; +import android.content.Context; +import android.content.pm.PackageManager; import android.net.DataUsageRequest; import android.net.NetworkIdentitySet; +import android.net.NetworkStack; import android.net.NetworkStats; import android.net.NetworkStatsAccess; import android.net.NetworkStatsCollection; @@ -74,9 +77,9 @@ class NetworkStatsObservers { * * @return the normalized request wrapped within {@link RequestInfo}. */ - public DataUsageRequest register(DataUsageRequest inputRequest, IUsageCallback callback, - int callingUid, @NetworkStatsAccess.Level int accessLevel) { - DataUsageRequest request = buildRequest(inputRequest, callingUid); + public DataUsageRequest register(Context context, DataUsageRequest inputRequest, + IUsageCallback callback, int callingUid, @NetworkStatsAccess.Level int accessLevel) { + DataUsageRequest request = buildRequest(context, inputRequest, callingUid); RequestInfo requestInfo = buildRequestInfo(request, callback, callingUid, accessLevel); @@ -194,10 +197,13 @@ class NetworkStatsObservers { } } - private DataUsageRequest buildRequest(DataUsageRequest request, int callingUid) { - // For non-system uid, cap the minimum threshold to a safe default to avoid too - // many callbacks. - long thresholdInBytes = (callingUid == Process.SYSTEM_UID ? request.thresholdInBytes + private DataUsageRequest buildRequest(Context context, DataUsageRequest request, + int callingUid) { + // For non-NETWORK_STACK permission uid, cap the minimum threshold to a safe default to + // avoid too many callbacks. + final long thresholdInBytes = (context.checkPermission( + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, Process.myPid(), callingUid) + == PackageManager.PERMISSION_GRANTED ? request.thresholdInBytes : Math.max(MIN_THRESHOLD_BYTES, request.thresholdInBytes)); if (thresholdInBytes > request.thresholdInBytes) { Log.w(TAG, "Threshold was too low for " + request diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1579f1e171..775a47d2e0 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1285,7 +1285,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { DataUsageRequest normalizedRequest; final long token = Binder.clearCallingIdentity(); try { - normalizedRequest = mStatsObservers.register( + normalizedRequest = mStatsObservers.register(mContext, request, callback, callingUid, accessLevel); } finally { Binder.restoreCallingIdentity(token); From 2bdae7d6e462d3026defeb7fd6f9c6eac96d6473 Mon Sep 17 00:00:00 2001 From: lifr Date: Mon, 1 Nov 2021 18:50:54 +0800 Subject: [PATCH 1124/1150] [SUBID01-0]Grow NetworkIdentity to include a new mSubId field In the previous design of NSS and NPMS, those only had IMSI to identify the cell network. Now the telephony has created the "subId" handle, which is the preferred mechanism for identifying subscribers. This commit adds NetworkStats support for subscriberId as a part of the network identity key Bug: 80526261 Test: atest NetworkTemplateTest NetworkStatsCollectionTest NetworkStatsServiceTest NetworkIdentityTest NetworkStatsDataMigrationUtilsTest (cherry-picked from ag/16825721) Change-Id: Ie1fe81006555dbcca4b62457fa6c319f04b4576d Merged-In: Ie1fe81006555dbcca4b62457fa6c319f04b4576d --- .../src/android/net/NetworkIdentity.java | 39 ++++++++++++++++--- .../src/android/net/NetworkIdentitySet.java | 14 ++++++- .../src/android/net/NetworkStateSnapshot.java | 21 +++++++++- .../server/net/NetworkStatsService.java | 13 +++++-- 4 files changed, 75 insertions(+), 12 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 4ebaf2b8cd..a48f94b66d 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -20,6 +20,7 @@ import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.NetworkTemplate.NETWORK_TYPE_ALL; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.IntDef; import android.annotation.NonNull; @@ -86,6 +87,7 @@ public class NetworkIdentity { final int mType; final int mRatType; + final int mSubId; final String mSubscriberId; final String mWifiNetworkKey; final boolean mRoaming; @@ -96,7 +98,7 @@ public class NetworkIdentity { /** @hide */ public NetworkIdentity( int type, int ratType, @Nullable String subscriberId, @Nullable String wifiNetworkKey, - boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged) { + boolean roaming, boolean metered, boolean defaultNetwork, int oemManaged, int subId) { mType = type; mRatType = ratType; mSubscriberId = subscriberId; @@ -105,12 +107,13 @@ public class NetworkIdentity { mMetered = metered; mDefaultNetwork = defaultNetwork; mOemManaged = oemManaged; + mSubId = subId; } @Override public int hashCode() { return Objects.hash(mType, mRatType, mSubscriberId, mWifiNetworkKey, mRoaming, mMetered, - mDefaultNetwork, mOemManaged); + mDefaultNetwork, mOemManaged, mSubId); } @Override @@ -122,7 +125,8 @@ public class NetworkIdentity { && Objects.equals(mWifiNetworkKey, ident.mWifiNetworkKey) && mMetered == ident.mMetered && mDefaultNetwork == ident.mDefaultNetwork - && mOemManaged == ident.mOemManaged; + && mOemManaged == ident.mOemManaged + && mSubId == ident.mSubId; } return false; } @@ -150,6 +154,7 @@ public class NetworkIdentity { builder.append(", metered=").append(mMetered); builder.append(", defaultNetwork=").append(mDefaultNetwork); builder.append(", oemManaged=").append(getOemManagedNames(mOemManaged)); + builder.append(", subId=").append(mSubId); return builder.append("}").toString(); } @@ -256,6 +261,11 @@ public class NetworkIdentity { return mOemManaged; } + /** Get the SubId of this instance. */ + public int getSubId() { + return mSubId; + } + /** * Assemble a {@link NetworkIdentity} from the passed arguments. * @@ -276,7 +286,8 @@ public class NetworkIdentity { public static NetworkIdentity buildNetworkIdentity(Context context, @NonNull NetworkStateSnapshot snapshot, boolean defaultNetwork, int ratType) { final NetworkIdentity.Builder builder = new NetworkIdentity.Builder() - .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork); + .setNetworkStateSnapshot(snapshot).setDefaultNetwork(defaultNetwork) + .setSubId(snapshot.getSubId()); if (snapshot.getLegacyType() == TYPE_MOBILE && ratType != NETWORK_TYPE_ALL) { builder.setRatType(ratType); } @@ -325,6 +336,9 @@ public class NetworkIdentity { if (res == 0) { res = Integer.compare(left.mOemManaged, right.mOemManaged); } + if (res == 0) { + res = Integer.compare(left.mSubId, right.mSubId); + } return res; } @@ -345,6 +359,7 @@ public class NetworkIdentity { private boolean mMetered; private boolean mDefaultNetwork; private int mOemManaged; + private int mSubId; /** * Creates a new Builder. @@ -359,6 +374,7 @@ public class NetworkIdentity { mMetered = false; mDefaultNetwork = false; mOemManaged = NetworkTemplate.OEM_MANAGED_NO; + mSubId = INVALID_SUBSCRIPTION_ID; } /** @@ -537,6 +553,19 @@ public class NetworkIdentity { return this; } + /** + * Set the Subscription Id. + * + * @param subId the Subscription Id of the network. Or INVALID_SUBSCRIPTION_ID if not + * applicable. + * @return this builder. + */ + @NonNull + public Builder setSubId(int subId) { + mSubId = subId; + return this; + } + private void ensureValidParameters() { // Assert non-mobile network cannot have a ratType. if (mType != TYPE_MOBILE && mRatType != NetworkTemplate.NETWORK_TYPE_ALL) { @@ -559,7 +588,7 @@ public class NetworkIdentity { public NetworkIdentity build() { ensureValidParameters(); return new NetworkIdentity(mType, mRatType, mSubscriberId, mWifiNetworkKey, - mRoaming, mMetered, mDefaultNetwork, mOemManaged); + mRoaming, mMetered, mDefaultNetwork, mOemManaged, mSubId); } } } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index 2236d70c35..56461babfe 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -17,6 +17,7 @@ package android.net; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.service.NetworkIdentitySetProto; @@ -42,6 +43,7 @@ public class NetworkIdentitySet extends HashSet { private static final int VERSION_ADD_METERED = 4; private static final int VERSION_ADD_DEFAULT_NETWORK = 5; private static final int VERSION_ADD_OEM_MANAGED_NETWORK = 6; + private static final int VERSION_ADD_SUB_ID = 7; /** * Construct a {@link NetworkIdentitySet} object. @@ -103,8 +105,15 @@ public class NetworkIdentitySet extends HashSet { oemNetCapabilities = NetworkIdentity.OEM_NONE; } + final int subId; + if (version >= VERSION_ADD_SUB_ID) { + subId = in.readInt(); + } else { + subId = INVALID_SUBSCRIPTION_ID; + } + add(new NetworkIdentity(type, ratType, subscriberId, networkId, roaming, metered, - defaultNetwork, oemNetCapabilities)); + defaultNetwork, oemNetCapabilities, subId)); } } @@ -113,7 +122,7 @@ public class NetworkIdentitySet extends HashSet { * @hide */ public void writeToStream(DataOutput out) throws IOException { - out.writeInt(VERSION_ADD_OEM_MANAGED_NETWORK); + out.writeInt(VERSION_ADD_SUB_ID); out.writeInt(size()); for (NetworkIdentity ident : this) { out.writeInt(ident.getType()); @@ -124,6 +133,7 @@ public class NetworkIdentitySet extends HashSet { out.writeBoolean(ident.isMetered()); out.writeBoolean(ident.isDefaultNetwork()); out.writeInt(ident.getOemManaged()); + out.writeInt(ident.getSubId()); } } diff --git a/framework-t/src/android/net/NetworkStateSnapshot.java b/framework-t/src/android/net/NetworkStateSnapshot.java index 3915634392..d3f785a8f9 100644 --- a/framework-t/src/android/net/NetworkStateSnapshot.java +++ b/framework-t/src/android/net/NetworkStateSnapshot.java @@ -17,6 +17,8 @@ package android.net; import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID; import android.annotation.NonNull; import android.annotation.Nullable; @@ -98,12 +100,29 @@ public final class NetworkStateSnapshot implements Parcelable { return mLinkProperties; } - /** Get the Subscriber Id of the network associated with this snapshot. */ + /** + * Get the Subscriber Id of the network associated with this snapshot. + * @deprecated Please use #getSubId, which doesn't return personally identifiable + * information. + */ + @Deprecated @Nullable public String getSubscriberId() { return mSubscriberId; } + /** Get the subId of the network associated with this snapshot. */ + public int getSubId() { + if (mNetworkCapabilities.hasTransport(TRANSPORT_CELLULAR)) { + final NetworkSpecifier spec = mNetworkCapabilities.getNetworkSpecifier(); + if (spec instanceof TelephonyNetworkSpecifier) { + return ((TelephonyNetworkSpecifier) spec).getSubscriptionId(); + } + } + return INVALID_SUBSCRIPTION_ID; + } + + /** * Get the legacy type of the network associated with this snapshot. * @return the legacy network type. See {@code ConnectivityManager#TYPE_*}. diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1579f1e171..ccca3daf7d 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1540,10 +1540,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { NetworkCapabilities.NET_CAPABILITY_IMS) && !ident.isMetered()) { // Copy the identify from IMS one but mark it as metered. - NetworkIdentity vtIdent = new NetworkIdentity(ident.getType(), - ident.getRatType(), ident.getSubscriberId(), ident.getWifiNetworkKey(), - ident.isRoaming(), true /* metered */, - true /* onDefaultNetwork */, ident.getOemManaged()); + NetworkIdentity vtIdent = new NetworkIdentity.Builder() + .setType(ident.getType()) + .setRatType(ident.getRatType()) + .setSubscriberId(ident.getSubscriberId()) + .setWifiNetworkKey(ident.getWifiNetworkKey()) + .setRoaming(ident.isRoaming()).setMetered(true) + .setDefaultNetwork(true) + .setOemManaged(ident.getOemManaged()) + .setSubId(ident.getSubId()).build(); final String ifaceVt = IFACE_VT + getSubIdForMobile(snapshot); findOrCreateNetworkIdentitySet(mActiveIfaces, ifaceVt).add(vtIdent); findOrCreateNetworkIdentitySet(mActiveUidIfaces, ifaceVt).add(vtIdent); From 5fbd57eab4ac27bf66d4be5ffb30098a7666179d Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 14 Feb 2022 21:26:44 +0800 Subject: [PATCH 1125/1150] Fix proto invalid write type While dumpProtoLocked is called, InvalidProtocolBufferException occurred because types are mismatched between platform side and module side. netstats.proto was moved into connectivity module, both the platform(incident.proto) and the module uses protoc-gen-javastream to generate the Java classes from it. It should be fine since platform includes the source of the proto, and jarjar the generated classess in the module to avoid conflict with platform. Bug: 218566849 Test: adb shell incident 3001 adb shell dumpsys netstats --proto atest CtsIncidentHostTestCases:IncidentdTest#testIncidentReportDumpAuto Change-Id: I4654350a59dc1ca1a925785ad37f34aa7b481235 Merged-In: I4654350a59dc1ca1a925785ad37f34aa7b481235 --- framework-t/src/android/net/NetworkIdentity.java | 10 +++++----- .../src/android/net/NetworkIdentitySet.java | 2 +- .../src/android/net/NetworkStatsCollection.java | 14 +++++++------- .../src/android/net/NetworkStatsHistory.java | 16 ++++++++-------- .../android/server/net/NetworkStatsRecorder.java | 4 ++-- .../android/server/net/NetworkStatsService.java | 16 ++++++++-------- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index a48f94b66d..da5f88dc3b 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -189,14 +189,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); + proto.write(NetworkIdentityProto.TYPE, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); - proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING, mRoaming); + proto.write(NetworkIdentityProto.METERED, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); proto.end(start); } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index 56461babfe..ad3a958a68 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -222,7 +222,7 @@ public class NetworkIdentitySet extends HashSet { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); } proto.end(start); diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 67d48f0000..735c44d5c8 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); - proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); + proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); proto.end(startStats); } diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 822a16e0bb..301fef9441 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,18 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); proto.end(startBucket); } diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index a006cd5975..f62765d074 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,11 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); } getOrLoadCompleteLocked().dumpDebug(proto, - NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); + NetworkStatsRecorderProto.COMPLETE_HISTORY); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ef6f39a5c0..b5e05395f2 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -2132,15 +2132,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); mUidTagRecorder.dumpDebugLocked(proto, - NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); + NetworkStatsServiceDumpProto.UID_TAG_STATS); proto.flush(); } @@ -2150,8 +2150,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); + proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); proto.end(start); } From 1a8a58449a1d26995d279224f8ab424cb5bcc3c5 Mon Sep 17 00:00:00 2001 From: markchien Date: Tue, 1 Mar 2022 15:16:11 +0800 Subject: [PATCH 1126/1150] Remove ConnectivityManager swapActiveStatsMap API swapActiveStatsMap is temporary added for the NetworkStatsFactory to call BpfNetMaps#swapActiveStatsMap in tethering mainline module. Now NetworkStatsFactory already be mainlined, calling BpfNetMaps#swapActiveStatsMap directly. Bug: 218494448 Test: atest ConnectivityCoverageTests atest FrameworksNetTests Change-Id: I25618020c078c7de3f0036c48d06d7816a431f62 --- .../server/net/NetworkStatsFactory.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java index 151c90dd41..3b93f1a190 100644 --- a/service-t/src/com/android/server/net/NetworkStatsFactory.java +++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java @@ -25,9 +25,9 @@ import static android.net.NetworkStats.UID_ALL; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.net.ConnectivityManager; import android.net.NetworkStats; import android.net.UnderlyingNetworkInfo; +import android.os.ServiceSpecificException; import android.os.StrictMode; import android.os.SystemClock; @@ -35,6 +35,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ProcFileReader; import com.android.net.module.util.CollectionUtils; +import com.android.server.BpfNetMaps; import libcore.io.IoUtils; @@ -74,6 +75,8 @@ public class NetworkStatsFactory { private final Context mContext; + private final BpfNetMaps mBpfNetMaps; + /** * Guards persistent data access in this class * @@ -170,6 +173,7 @@ public class NetworkStatsFactory { mStatsXtIfaceFmt = new File(procRoot, "net/xt_qtaguid/iface_stat_fmt"); mStatsXtUid = new File(procRoot, "net/xt_qtaguid/stats"); mUseBpfStats = useBpfStats; + mBpfNetMaps = new BpfNetMaps(); synchronized (mPersistentDataLock) { mPersistSnapshot = new NetworkStats(SystemClock.elapsedRealtime(), -1); mTunAnd464xlatAdjustedStats = new NetworkStats(SystemClock.elapsedRealtime(), -1); @@ -297,12 +301,14 @@ public class NetworkStatsFactory { } @GuardedBy("mPersistentDataLock") - private void requestSwapActiveStatsMapLocked() { - // Do a active map stats swap. When the binder call successfully returns, - // the system server should be able to safely read and clean the inactive map - // without race problem. - final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class); - cm.swapActiveStatsMap(); + private void requestSwapActiveStatsMapLocked() throws IOException { + try { + // Do a active map stats swap. Once the swap completes, this code + // can read and clean the inactive map without races. + mBpfNetMaps.swapActiveStatsMap(); + } catch (ServiceSpecificException e) { + throw new IOException(e); + } } /** @@ -328,11 +334,7 @@ public class NetworkStatsFactory { final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0 /* initialSize */); if (mUseBpfStats) { - try { - requestSwapActiveStatsMapLocked(); - } catch (RuntimeException e) { - throw new IOException(e); - } + requestSwapActiveStatsMapLocked(); // Stats are always read from the inactive map, so they must be read after the // swap if (nativeReadNetworkStatsDetail(stats, mStatsXtUid.getAbsolutePath(), UID_ALL, From fd5dcd2dd9f50c373c3d3d5218b28d6014adeb84 Mon Sep 17 00:00:00 2001 From: Frank Date: Mon, 7 Mar 2022 16:15:50 +0800 Subject: [PATCH 1127/1150] [DU09-2]Modify the NetworkStatsCollection Builder API 1. Adding the bucketDuration with unit as bucketDurationmillis 2. make the Key class be final 3. The Key set parameter be marked with an IntDef Bug: 220153505 Test: atest NetworkStatsCollectionTest Change-Id: Iab32b8fc129b77d6786c2f1f2339e515f2eb55f7 --- .../android/net/NetworkStatsCollection.java | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 67d48f0000..1ddc78bb4d 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -36,6 +36,7 @@ import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRation import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.SystemApi; +import android.net.NetworkStats.State; import android.net.NetworkStatsHistory.Entry; import android.os.Binder; import android.service.NetworkStatsCollectionKeyProto; @@ -102,7 +103,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private ArrayMap mStats = new ArrayMap<>(); - private final long mBucketDuration; + private final long mBucketDurationMillis; private long mStartMillis; private long mEndMillis; @@ -115,8 +116,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * @param bucketDuration duration of the buckets in this object, in milliseconds. * @hide */ - public NetworkStatsCollection(long bucketDuration) { - mBucketDuration = bucketDuration; + public NetworkStatsCollection(long bucketDurationMillis) { + mBucketDurationMillis = bucketDurationMillis; reset(); } @@ -148,7 +149,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W if (mStartMillis == Long.MAX_VALUE) { return Long.MAX_VALUE; } else { - return mStartMillis + mBucketDuration; + return mStartMillis + mBucketDurationMillis; } } @@ -184,10 +185,10 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W || time == SubscriptionPlan.TIME_UNKNOWN) { return time; } else { - final long mod = time % mBucketDuration; + final long mod = time % mBucketDurationMillis; if (mod > 0) { time -= mod; - time += mBucketDuration; + time += mBucketDurationMillis; } return time; } @@ -200,7 +201,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W || time == SubscriptionPlan.TIME_UNKNOWN) { return time; } else { - final long mod = time % mBucketDuration; + final long mod = time % mBucketDurationMillis; if (mod > 0) { time -= mod; } @@ -247,10 +248,10 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W // 180 days of history should be enough for anyone; if we end up needing // more, we'll dynamically grow the history object. final int bucketEstimate = (int) NetworkStatsUtils.constrain( - ((end - start) / mBucketDuration), 0, - (180 * DateUtils.DAY_IN_MILLIS) / mBucketDuration); + ((end - start) / mBucketDurationMillis), 0, + (180 * DateUtils.DAY_IN_MILLIS) / mBucketDurationMillis); final NetworkStatsHistory combined = new NetworkStatsHistory( - mBucketDuration, bucketEstimate, fields); + mBucketDurationMillis, bucketEstimate, fields); // shortcut when we know stats will be empty if (start == end) return combined; @@ -343,7 +344,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W // Finally we can slice data as originally requested final NetworkStatsHistory sliced = new NetworkStatsHistory( - mBucketDuration, bucketEstimate, fields); + mBucketDurationMillis, bucketEstimate, fields); sliced.recordHistory(combined, start, end); return sliced; } else { @@ -458,9 +459,9 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W // update when no existing, or when bucket duration changed NetworkStatsHistory updated = null; if (existing == null) { - updated = new NetworkStatsHistory(mBucketDuration, 10); - } else if (existing.getBucketDuration() != mBucketDuration) { - updated = new NetworkStatsHistory(existing, mBucketDuration); + updated = new NetworkStatsHistory(mBucketDurationMillis, 10); + } else if (existing.getBucketDuration() != mBucketDurationMillis) { + updated = new NetworkStatsHistory(existing, mBucketDurationMillis); } if (updated != null) { @@ -702,7 +703,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W private int estimateBuckets() { return (int) (Math.min(mEndMillis - mStartMillis, WEEK_IN_MILLIS * 5) - / mBucketDuration); + / mBucketDurationMillis); } private ArrayList getSortedKeys() { @@ -828,7 +829,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * Builder class for {@link NetworkStatsCollection}. */ public static final class Builder { - private final long mBucketDuration; + private final long mBucketDurationMillis; private final ArrayMap mEntries = new ArrayMap<>(); /** @@ -836,8 +837,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * * @param bucketDuration Duration of the buckets of the object, in milliseconds. */ - public Builder(long bucketDuration) { - mBucketDuration = bucketDuration; + public Builder(long bucketDurationMillis) { + mBucketDurationMillis = bucketDurationMillis; } /** @@ -855,7 +856,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final List historyEntries = history.getEntries(); final NetworkStatsHistory.Builder historyBuilder = - new NetworkStatsHistory.Builder(mBucketDuration, historyEntries.size()); + new NetworkStatsHistory.Builder(mBucketDurationMillis, historyEntries.size()); for (Entry entry : historyEntries) { historyBuilder.addEntry(entry); } @@ -871,7 +872,8 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W */ @NonNull public NetworkStatsCollection build() { - final NetworkStatsCollection collection = new NetworkStatsCollection(mBucketDuration); + final NetworkStatsCollection collection = + new NetworkStatsCollection(mBucketDurationMillis); for (int i = 0; i < mEntries.size(); i++) { collection.recordHistory(mEntries.keyAt(i), mEntries.valueAt(i)); } @@ -883,7 +885,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * the identifier that associate with the {@link NetworkStatsHistory} object to identify * a certain record in the {@link NetworkStatsCollection} object. */ - public static class Key { + public static final class Key { /** @hide */ public final NetworkIdentitySet ident; /** @hide */ @@ -903,7 +905,7 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W * @param set Set of the record, see {@code NetworkStats#SET_*}. * @param tag Tag of the record, see {@link TrafficStats#setThreadStatsTag(int)}. */ - public Key(@NonNull Set ident, int uid, int set, int tag) { + public Key(@NonNull Set ident, int uid, @State int set, int tag) { this(new NetworkIdentitySet(Objects.requireNonNull(ident)), uid, set, tag); } From 85b2dc0020fe0cedbcfa79045945b027702162e4 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Mon, 14 Feb 2022 21:26:44 +0800 Subject: [PATCH 1128/1150] Fix proto invalid write type While dumpProtoLocked is called, InvalidProtocolBufferException occurred because types are mismatched between platform side and module side. netstats.proto was moved into connectivity module, both the platform(incident.proto) and the module uses protoc-gen-javastream to generate the Java classes from it. It should be fine since platform includes the source of the proto, and jarjar the generated classess in the module to avoid conflict with platform. Bug: 218566849 Test: adb shell incident 3001 adb shell dumpsys netstats --proto atest CtsIncidentHostTestCases:IncidentdTest#testIncidentReportDumpAuto Change-Id: I4654350a59dc1ca1a925785ad37f34aa7b481235 Merged-In: I4654350a59dc1ca1a925785ad37f34aa7b481235 --- framework-t/src/android/net/NetworkIdentity.java | 10 +++++----- .../src/android/net/NetworkIdentitySet.java | 2 +- .../src/android/net/NetworkStatsCollection.java | 14 +++++++------- .../src/android/net/NetworkStatsHistory.java | 16 ++++++++-------- .../android/server/net/NetworkStatsRecorder.java | 4 ++-- .../android/server/net/NetworkStatsService.java | 16 ++++++++-------- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/framework-t/src/android/net/NetworkIdentity.java b/framework-t/src/android/net/NetworkIdentity.java index 4ebaf2b8cd..56faa52e82 100644 --- a/framework-t/src/android/net/NetworkIdentity.java +++ b/framework-t/src/android/net/NetworkIdentity.java @@ -184,14 +184,14 @@ public class NetworkIdentity { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkIdentityProto.TYPE_FIELD_NUMBER, mType); + proto.write(NetworkIdentityProto.TYPE, mType); // TODO: dump mRatType as well. - proto.write(NetworkIdentityProto.ROAMING_FIELD_NUMBER, mRoaming); - proto.write(NetworkIdentityProto.METERED_FIELD_NUMBER, mMetered); - proto.write(NetworkIdentityProto.DEFAULT_NETWORK_FIELD_NUMBER, mDefaultNetwork); - proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK_FIELD_NUMBER, mOemManaged); + proto.write(NetworkIdentityProto.ROAMING, mRoaming); + proto.write(NetworkIdentityProto.METERED, mMetered); + proto.write(NetworkIdentityProto.DEFAULT_NETWORK, mDefaultNetwork); + proto.write(NetworkIdentityProto.OEM_MANAGED_NETWORK, mOemManaged); proto.end(start); } diff --git a/framework-t/src/android/net/NetworkIdentitySet.java b/framework-t/src/android/net/NetworkIdentitySet.java index 2236d70c35..dfa347f6f1 100644 --- a/framework-t/src/android/net/NetworkIdentitySet.java +++ b/framework-t/src/android/net/NetworkIdentitySet.java @@ -212,7 +212,7 @@ public class NetworkIdentitySet extends HashSet { final long start = proto.start(tag); for (NetworkIdentity ident : this) { - ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES_FIELD_NUMBER); + ident.dumpDebug(proto, NetworkIdentitySetProto.IDENTITIES); } proto.end(start); diff --git a/framework-t/src/android/net/NetworkStatsCollection.java b/framework-t/src/android/net/NetworkStatsCollection.java index 67d48f0000..735c44d5c8 100644 --- a/framework-t/src/android/net/NetworkStatsCollection.java +++ b/framework-t/src/android/net/NetworkStatsCollection.java @@ -732,19 +732,19 @@ public class NetworkStatsCollection implements FileRotator.Reader, FileRotator.W final long start = proto.start(tag); for (Key key : getSortedKeys()) { - final long startStats = proto.start(NetworkStatsCollectionProto.STATS_FIELD_NUMBER); + final long startStats = proto.start(NetworkStatsCollectionProto.STATS); // Key - final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY_FIELD_NUMBER); - key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY_FIELD_NUMBER); - proto.write(NetworkStatsCollectionKeyProto.UID_FIELD_NUMBER, key.uid); - proto.write(NetworkStatsCollectionKeyProto.SET_FIELD_NUMBER, key.set); - proto.write(NetworkStatsCollectionKeyProto.TAG_FIELD_NUMBER, key.tag); + final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY); + key.ident.dumpDebug(proto, NetworkStatsCollectionKeyProto.IDENTITY); + proto.write(NetworkStatsCollectionKeyProto.UID, key.uid); + proto.write(NetworkStatsCollectionKeyProto.SET, key.set); + proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag); proto.end(startKey); // Value final NetworkStatsHistory history = mStats.get(key); - history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY_FIELD_NUMBER); + history.dumpDebug(proto, NetworkStatsCollectionStatsProto.HISTORY); proto.end(startStats); } diff --git a/framework-t/src/android/net/NetworkStatsHistory.java b/framework-t/src/android/net/NetworkStatsHistory.java index 822a16e0bb..301fef9441 100644 --- a/framework-t/src/android/net/NetworkStatsHistory.java +++ b/framework-t/src/android/net/NetworkStatsHistory.java @@ -915,18 +915,18 @@ public final class NetworkStatsHistory implements Parcelable { public void dumpDebug(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); - proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS_FIELD_NUMBER, bucketDuration); + proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration); for (int i = 0; i < bucketCount; i++) { - final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS_FIELD_NUMBER); + final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS); - proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS_FIELD_NUMBER, + proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES_FIELD_NUMBER, rxBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS_FIELD_NUMBER, rxPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES_FIELD_NUMBER, txBytes, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS_FIELD_NUMBER, txPackets, i); - dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS_FIELD_NUMBER, operations, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i); + dumpDebug(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i); proto.end(startBucket); } diff --git a/service-t/src/com/android/server/net/NetworkStatsRecorder.java b/service-t/src/com/android/server/net/NetworkStatsRecorder.java index a006cd5975..f62765d074 100644 --- a/service-t/src/com/android/server/net/NetworkStatsRecorder.java +++ b/service-t/src/com/android/server/net/NetworkStatsRecorder.java @@ -471,11 +471,11 @@ public class NetworkStatsRecorder { public void dumpDebugLocked(ProtoOutputStream proto, long tag) { final long start = proto.start(tag); if (mPending != null) { - proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES_FIELD_NUMBER, + proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes()); } getOrLoadCompleteLocked().dumpDebug(proto, - NetworkStatsRecorderProto.COMPLETE_HISTORY_FIELD_NUMBER); + NetworkStatsRecorderProto.COMPLETE_HISTORY); proto.end(start); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index 1579f1e171..1f63c3a822 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -2127,15 +2127,15 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // TODO Right now it writes all history. Should it limit to the "since-boot" log? - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES_FIELD_NUMBER, + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces); - dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES_FIELD_NUMBER, + dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces); - mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS_FIELD_NUMBER); - mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS_FIELD_NUMBER); - mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS_FIELD_NUMBER); + mDevRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS); + mXtRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.XT_STATS); + mUidRecorder.dumpDebugLocked(proto, NetworkStatsServiceDumpProto.UID_STATS); mUidTagRecorder.dumpDebugLocked(proto, - NetworkStatsServiceDumpProto.UID_TAG_STATS_FIELD_NUMBER); + NetworkStatsServiceDumpProto.UID_TAG_STATS); proto.flush(); } @@ -2145,8 +2145,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { for (int i = 0; i < ifaces.size(); i++) { final long start = proto.start(tag); - proto.write(NetworkInterfaceProto.INTERFACE_FIELD_NUMBER, ifaces.keyAt(i)); - ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES_FIELD_NUMBER); + proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i)); + ifaces.valueAt(i).dumpDebug(proto, NetworkInterfaceProto.IDENTITIES); proto.end(start); } From 02730cf4214d339ceeb3ae0315b104d78047d738 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Fri, 4 Feb 2022 13:14:13 +0100 Subject: [PATCH 1129/1150] Fix log message when failing to open bpf maps s/create/open/ Test: TH Change-Id: I7fd1b280ab15aaa0757cfb3afcc20bf377a3bcef --- .../com/android/server/net/NetworkStatsService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ef6f39a5c0..f8355817bf 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -565,7 +565,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new BpfMap(UID_COUNTERSET_MAP_PATH, BpfMap.BPF_F_RDWR, U32.class, U8.class); } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot create uid counter set map: " + e); + Log.wtf(TAG, "Cannot open uid counter set map: " + e); return null; } } @@ -576,7 +576,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new BpfMap(COOKIE_TAG_MAP_PATH, BpfMap.BPF_F_RDWR, CookieTagMapKey.class, CookieTagMapValue.class); } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot create cookie tag map: " + e); + Log.wtf(TAG, "Cannot open cookie tag map: " + e); return null; } } @@ -587,7 +587,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new BpfMap(STATS_MAP_A_PATH, BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot create stats map A: " + e); + Log.wtf(TAG, "Cannot open stats map A: " + e); return null; } } @@ -598,7 +598,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new BpfMap(STATS_MAP_B_PATH, BpfMap.BPF_F_RDWR, StatsMapKey.class, StatsMapValue.class); } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot create stats map B: " + e); + Log.wtf(TAG, "Cannot open stats map B: " + e); return null; } } @@ -609,7 +609,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return new BpfMap(APP_UID_STATS_MAP_PATH, BpfMap.BPF_F_RDWR, UidStatsMapKey.class, StatsMapValue.class); } catch (ErrnoException e) { - Log.wtf(TAG, "Cannot create app uid stats map: " + e); + Log.wtf(TAG, "Cannot open app uid stats map: " + e); return null; } } From db3007caca61beb9fb1c06c5a03bb4baea9728f1 Mon Sep 17 00:00:00 2001 From: James Mattis Date: Thu, 3 Mar 2022 16:07:11 -0800 Subject: [PATCH 1130/1150] Allowing for null net caps in updateConfiguration Marking NetworkCapabilities as nullable in updateConfiguration and updating where needed to support this. This will allow callers of the ethernet network management updateConfiguration API to use it primarily for setting an ethernet network's IP configuration. Bug: 222565654 Bug: 220017952 Bug: 210485380 Test: atest EthernetNetworkUpdateRequestTest Change-Id: I1f80e950acbd078a6b3378e1fa5f1e4173112e79 --- .../net/EthernetNetworkUpdateRequest.java | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index a626971105..43f4c40f2d 100644 --- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -24,36 +24,52 @@ import android.os.Parcelable; import java.util.Objects; -/** @hide */ +/** + * Represents a request to update an existing Ethernet interface. + * + * @see EthernetManager#updateConfiguration + * + * @hide + */ @SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { @NonNull private final IpConfiguration mIpConfig; - @NonNull + @Nullable private final NetworkCapabilities mNetworkCapabilities; + /** + * @return the new {@link IpConfiguration}. + */ @NonNull public IpConfiguration getIpConfiguration() { return new IpConfiguration(mIpConfig); } - @NonNull + /** + * Setting the {@link NetworkCapabilities} is optional in {@link EthernetNetworkUpdateRequest}. + * When set to null, the existing NetworkCapabilities are not updated. + * + * @return the new {@link NetworkCapabilities} or null. + */ + @Nullable public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); + return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities); } private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, - @NonNull final NetworkCapabilities networkCapabilities) { + @Nullable final NetworkCapabilities networkCapabilities) { Objects.requireNonNull(ipConfig); - Objects.requireNonNull(networkCapabilities); - mIpConfig = new IpConfiguration(ipConfig); - mNetworkCapabilities = new NetworkCapabilities(networkCapabilities); + mIpConfig = ipConfig; + mNetworkCapabilities = networkCapabilities; } private EthernetNetworkUpdateRequest(@NonNull final Parcel source) { Objects.requireNonNull(source); - mIpConfig = IpConfiguration.CREATOR.createFromParcel(source); - mNetworkCapabilities = NetworkCapabilities.CREATOR.createFromParcel(source); + mIpConfig = source.readParcelable(IpConfiguration.class.getClassLoader(), + IpConfiguration.class); + mNetworkCapabilities = source.readParcelable(NetworkCapabilities.class.getClassLoader(), + NetworkCapabilities.class); } /** @@ -75,7 +91,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { public Builder(@NonNull final EthernetNetworkUpdateRequest request) { Objects.requireNonNull(request); mBuilderIpConfig = new IpConfiguration(request.mIpConfig); - mBuilderNetworkCapabilities = new NetworkCapabilities(request.mNetworkCapabilities); + mBuilderNetworkCapabilities = null == request.mNetworkCapabilities + ? null : new NetworkCapabilities(request.mNetworkCapabilities); } /** @@ -85,7 +102,6 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { */ @NonNull public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { - Objects.requireNonNull(ipConfig); mBuilderIpConfig = new IpConfiguration(ipConfig); return this; } @@ -96,9 +112,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { * @return The builder to facilitate chaining. */ @NonNull - public Builder setNetworkCapabilities(@NonNull final NetworkCapabilities nc) { - Objects.requireNonNull(nc); - mBuilderNetworkCapabilities = new NetworkCapabilities(nc); + public Builder setNetworkCapabilities(@Nullable final NetworkCapabilities nc) { + mBuilderNetworkCapabilities = nc == null ? null : new NetworkCapabilities(nc); return this; } @@ -135,8 +150,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - mIpConfig.writeToParcel(dest, flags); - mNetworkCapabilities.writeToParcel(dest, flags); + dest.writeParcelable(mIpConfig, flags); + dest.writeParcelable(mNetworkCapabilities, flags); } @Override From faa9fe86b665e90d388e1339e27dac43143ee7d5 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Tue, 8 Mar 2022 17:07:50 +0100 Subject: [PATCH 1131/1150] Remove restriction that limits updateConfiguration API to Auto Test: TH Change-Id: Ibd1b6493778b98fc765e6eebdfe8f9c1fef29a73 --- framework-t/src/android/net/EthernetManager.java | 1 - 1 file changed, 1 deletion(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 72243f9e87..eba51c1148 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -511,7 +511,6 @@ public class EthernetManager { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) - @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) public void updateConfiguration( @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, From e6c13a7dd01313c44d9418716a58227708bdfd52 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Thu, 10 Mar 2022 17:44:49 +0800 Subject: [PATCH 1132/1150] Rename setUidForeground to noteUidForeground This patch addresses API review about the naming of NetworkStatsManager#setUidForeground and it would be more appropriate to rename it to noteUidForeground. Bug: 222291301 Test: atest FrameworksNetTests Change-Id: I952762872850889609c9808aa6e3cdfc04317806 --- framework-t/src/android/app/usage/NetworkStatsManager.java | 4 ++-- framework-t/src/android/net/INetworkStatsService.aidl | 2 +- service-t/src/com/android/server/net/NetworkStatsService.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index ca080ce4c6..bf518b2d5a 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -1061,9 +1061,9 @@ public class NetworkStatsManager { @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) - public void setUidForeground(int uid, boolean uidForeground) { + public void noteUidForeground(int uid, boolean uidForeground) { try { - mService.setUidForeground(uid, uidForeground); + mService.noteUidForeground(uid, uidForeground); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/framework-t/src/android/net/INetworkStatsService.aidl b/framework-t/src/android/net/INetworkStatsService.aidl index efe626d3c9..c86f7fd089 100644 --- a/framework-t/src/android/net/INetworkStatsService.aidl +++ b/framework-t/src/android/net/INetworkStatsService.aidl @@ -91,7 +91,7 @@ interface INetworkStatsService { in INetworkStatsProvider provider); /** Mark given UID as being in foreground for stats purposes. */ - void setUidForeground(int uid, boolean uidForeground); + void noteUidForeground(int uid, boolean uidForeground); /** Advise persistence threshold; may be overridden internally. */ void advisePersistThreshold(long thresholdBytes); diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index ef6f39a5c0..72eff87c16 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -1194,7 +1194,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @VisibleForTesting - public void setUidForeground(int uid, boolean uidForeground) { + public void noteUidForeground(int uid, boolean uidForeground) { PermissionUtils.enforceNetworkStackPermission(mContext); synchronized (mStatsLock) { final int set = uidForeground ? SET_FOREGROUND : SET_DEFAULT; From a9a3b4ce04cac0db58837007fea3a788c1c54dcb Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Tue, 28 Dec 2021 09:16:09 +0000 Subject: [PATCH 1133/1150] Split out the ethernet API surface and use framework-connectivity-t Ethernet framework and service source code is going to be moved to Connectivity mainline module, this CL contains below corresponding changes to adapt the migration in f/b side: 1. Split out ethernet module-lib APIs to Connectivity module. Add the ethernet resource filegroup to tiramisu-updatable-sources filegroup as well, build them together. Also update the module-lib and system api txt to reflect the APIs change. Remove the hidden APIs which are moved to Connectivity module. This removal fixes the api inconsistent issue with Tethering/apex/hidden/. 2. Remove EthernetService from SystemServer which will be registered from ConnectivityServiceInitializer. 3. Replace the BackgroundThread class(imported from f/b/core/java) with the one in the modules-utils-backgroundthread lib, which is visible to Connectivity module. Bug: 210586283 Test: m Test: atest FrameworksNetTests EthernetServiceTests Change-Id: I1956848d3248cc56e9841d221e5e4c160bed65a4 --- framework-t/Sources.bp | 6 +++--- ...nectivityFrameworkInitializerTiramisu.java | 14 ++++++++++++-- .../src/android/net/EthernetManager.java | 2 +- service-t/Sources.bp | 8 ++++---- .../android/server/net/IpConfigStoreTest.java | 19 +++++++++---------- 5 files changed, 29 insertions(+), 20 deletions(-) rename {services/tests/servicestests/src => tests/unit/java}/com/android/server/net/IpConfigStoreTest.java (92%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 66527802a0..217a1f67c3 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -154,17 +154,17 @@ filegroup { ], } +// TODO: remove this empty filegroup. filegroup { name: "framework-connectivity-tiramisu-sources", - srcs: [ - ":framework-connectivity-ethernet-sources", - ], + srcs: [], visibility: ["//frameworks/base"], } filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 9bffbfb27a..61b34d0bcf 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -34,8 +34,9 @@ public final class ConnectivityFrameworkInitializerTiramisu { private ConnectivityFrameworkInitializerTiramisu() {} /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to - * {@link Context}, so that {@link Context#getSystemService} can return them. + * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd, + * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can + * return them. * * @throws IllegalStateException if this is called anywhere besides * {@link SystemServiceRegistry}. @@ -68,5 +69,14 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NetworkStatsManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.ETHERNET_SERVICE, + EthernetManager.class, + (context, serviceBinder) -> { + IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder); + return new EthernetManager(context, service); + } + ); } } diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index eba51c1148..793f28d5aa 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -33,7 +33,7 @@ import android.os.Build; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; -import com.android.internal.os.BackgroundThread; +import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 5100e7c5b9..4b799c599b 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -102,17 +102,16 @@ filegroup { ], path: "src", visibility: [ - "//frameworks/opt/net/ethernet", + "//frameworks/opt/net/ethernet/tests", ], } // Connectivity-T common libraries. +// TODO: remove this empty filegroup. filegroup { name: "services.connectivity-tiramisu-sources", - srcs: [ - ":services.connectivity-ethernet-sources", - ], + srcs: [], path: "src", visibility: ["//frameworks/base/services/core"], } @@ -120,6 +119,7 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java similarity index 92% rename from services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java rename to tests/unit/java/com/android/server/net/IpConfigStoreTest.java index 2f771260ac..ad0be5862c 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java @@ -48,10 +48,16 @@ import java.util.Arrays; */ @RunWith(AndroidJUnit4.class) public class IpConfigStoreTest { + private static final int KEY_CONFIG = 17; + private static final String IFACE_1 = "eth0"; + private static final String IFACE_2 = "eth1"; + private static final String IP_ADDR_1 = "192.168.1.10/24"; + private static final String IP_ADDR_2 = "192.168.1.20/24"; + private static final String DNS_IP_ADDR_1 = "1.2.3.4"; + private static final String DNS_IP_ADDR_2 = "5.6.7.8"; @Test public void backwardCompatibility2to3() throws IOException { - final int KEY_CONFIG = 17; ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(byteStream); @@ -73,13 +79,6 @@ public class IpConfigStoreTest { @Test public void staticIpMultiNetworks() throws Exception { - final String IFACE_1 = "eth0"; - final String IFACE_2 = "eth1"; - final String IP_ADDR_1 = "192.168.1.10/24"; - final String IP_ADDR_2 = "192.168.1.20/24"; - final String DNS_IP_ADDR_1 = "1.2.3.4"; - final String DNS_IP_ADDR_2 = "5.6.7.8"; - final ArrayList dnsServers = new ArrayList<>(); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); @@ -144,11 +143,11 @@ public class IpConfigStoreTest { /** Synchronously writes into given byte steam */ private static class MockedDelayedDiskWrite extends DelayedDiskWrite { - final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); @Override public void write(String filePath, Writer w) { - DataOutputStream outputStream = new DataOutputStream(byteStream); + DataOutputStream outputStream = new DataOutputStream(mByteStream); try { w.onWriteCalled(outputStream); From d695111dc9bb0879b00b776b1a084c8ef79344c1 Mon Sep 17 00:00:00 2001 From: Aaron Huang Date: Fri, 11 Mar 2022 01:09:34 +0800 Subject: [PATCH 1134/1150] Let docs tool to list the newly-visible IntDef values Some *_ALL constants are exposed in T and they should be mentioned in documentation. Because there are already defined InDef values for this kind of constants. Thus, remove the list in the javadoc and leave these up to the doc tool to list the InDef values. Bug: 222291452 Test: m doc-comment-check-docs Change-Id: Ibbaee5389a85bb3d696a518deea0897845553bfa --- framework-t/src/android/net/NetworkStats.java | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index f681ba1c38..06f2a621bc 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -327,16 +327,11 @@ public final class NetworkStats implements Parcelable, Iterable Date: Tue, 28 Dec 2021 09:16:09 +0000 Subject: [PATCH 1135/1150] Split out the ethernet API surface and use framework-connectivity-t Ethernet framework and service source code is going to be moved to Connectivity mainline module, this CL contains below corresponding changes to adapt the migration in f/b side: 1. Split out ethernet module-lib APIs to Connectivity module. Add the ethernet resource filegroup to tiramisu-updatable-sources filegroup as well, build them together. Also update the module-lib and system api txt to reflect the APIs change. Remove the hidden APIs which are moved to Connectivity module. This removal fixes the api inconsistent issue with Tethering/apex/hidden/. 2. Remove EthernetService from SystemServer which will be registered from ConnectivityServiceInitializer. 3. Replace the BackgroundThread class(imported from f/b/core/java) with the one in the modules-utils-backgroundthread lib, which is visible to Connectivity module. Bug: 210586283 Test: m Test: atest FrameworksNetTests EthernetServiceTests Change-Id: I3e13cb9c0e348333af295c2537d459aa6700ff17 Merged-In: I1956848d3248cc56e9841d221e5e4c160bed65a4 --- framework-t/Sources.bp | 6 +++--- ...nectivityFrameworkInitializerTiramisu.java | 14 ++++++++++++-- .../src/android/net/EthernetManager.java | 2 +- service-t/Sources.bp | 8 ++++---- .../android/server/net/IpConfigStoreTest.java | 19 +++++++++---------- 5 files changed, 29 insertions(+), 20 deletions(-) rename {services/tests/servicestests/src => tests/unit/java}/com/android/server/net/IpConfigStoreTest.java (92%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 66527802a0..217a1f67c3 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -154,17 +154,17 @@ filegroup { ], } +// TODO: remove this empty filegroup. filegroup { name: "framework-connectivity-tiramisu-sources", - srcs: [ - ":framework-connectivity-ethernet-sources", - ], + srcs: [], visibility: ["//frameworks/base"], } filegroup { name: "framework-connectivity-tiramisu-updatable-sources", srcs: [ + ":framework-connectivity-ethernet-sources", ":framework-connectivity-ipsec-sources", ":framework-connectivity-netstats-sources", ":framework-connectivity-nsd-sources", diff --git a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java index 9bffbfb27a..61b34d0bcf 100644 --- a/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java +++ b/framework-t/src/android/net/ConnectivityFrameworkInitializerTiramisu.java @@ -34,8 +34,9 @@ public final class ConnectivityFrameworkInitializerTiramisu { private ConnectivityFrameworkInitializerTiramisu() {} /** - * Called by {@link SystemServiceRegistry}'s static initializer and registers nsd services to - * {@link Context}, so that {@link Context#getSystemService} can return them. + * Called by {@link SystemServiceRegistry}'s static initializer and registers NetworkStats, nsd, + * ipsec and ethernet services to {@link Context}, so that {@link Context#getSystemService} can + * return them. * * @throws IllegalStateException if this is called anywhere besides * {@link SystemServiceRegistry}. @@ -68,5 +69,14 @@ public final class ConnectivityFrameworkInitializerTiramisu { return new NetworkStatsManager(context, service); } ); + + SystemServiceRegistry.registerContextAwareService( + Context.ETHERNET_SERVICE, + EthernetManager.class, + (context, serviceBinder) -> { + IEthernetManager service = IEthernetManager.Stub.asInterface(serviceBinder); + return new EthernetManager(context, service); + } + ); } } diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index eba51c1148..793f28d5aa 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -33,7 +33,7 @@ import android.os.Build; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; -import com.android.internal.os.BackgroundThread; +import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; diff --git a/service-t/Sources.bp b/service-t/Sources.bp index 5100e7c5b9..4b799c599b 100644 --- a/service-t/Sources.bp +++ b/service-t/Sources.bp @@ -102,17 +102,16 @@ filegroup { ], path: "src", visibility: [ - "//frameworks/opt/net/ethernet", + "//frameworks/opt/net/ethernet/tests", ], } // Connectivity-T common libraries. +// TODO: remove this empty filegroup. filegroup { name: "services.connectivity-tiramisu-sources", - srcs: [ - ":services.connectivity-ethernet-sources", - ], + srcs: [], path: "src", visibility: ["//frameworks/base/services/core"], } @@ -120,6 +119,7 @@ filegroup { filegroup { name: "services.connectivity-tiramisu-updatable-sources", srcs: [ + ":services.connectivity-ethernet-sources", ":services.connectivity-ipsec-sources", ":services.connectivity-netstats-sources", ":services.connectivity-nsd-sources", diff --git a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java similarity index 92% rename from services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java rename to tests/unit/java/com/android/server/net/IpConfigStoreTest.java index 2f771260ac..ad0be5862c 100644 --- a/services/tests/servicestests/src/com/android/server/net/IpConfigStoreTest.java +++ b/tests/unit/java/com/android/server/net/IpConfigStoreTest.java @@ -48,10 +48,16 @@ import java.util.Arrays; */ @RunWith(AndroidJUnit4.class) public class IpConfigStoreTest { + private static final int KEY_CONFIG = 17; + private static final String IFACE_1 = "eth0"; + private static final String IFACE_2 = "eth1"; + private static final String IP_ADDR_1 = "192.168.1.10/24"; + private static final String IP_ADDR_2 = "192.168.1.20/24"; + private static final String DNS_IP_ADDR_1 = "1.2.3.4"; + private static final String DNS_IP_ADDR_2 = "5.6.7.8"; @Test public void backwardCompatibility2to3() throws IOException { - final int KEY_CONFIG = 17; ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); DataOutputStream outputStream = new DataOutputStream(byteStream); @@ -73,13 +79,6 @@ public class IpConfigStoreTest { @Test public void staticIpMultiNetworks() throws Exception { - final String IFACE_1 = "eth0"; - final String IFACE_2 = "eth1"; - final String IP_ADDR_1 = "192.168.1.10/24"; - final String IP_ADDR_2 = "192.168.1.20/24"; - final String DNS_IP_ADDR_1 = "1.2.3.4"; - final String DNS_IP_ADDR_2 = "5.6.7.8"; - final ArrayList dnsServers = new ArrayList<>(); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_1)); dnsServers.add(InetAddresses.parseNumericAddress(DNS_IP_ADDR_2)); @@ -144,11 +143,11 @@ public class IpConfigStoreTest { /** Synchronously writes into given byte steam */ private static class MockedDelayedDiskWrite extends DelayedDiskWrite { - final ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); + final ByteArrayOutputStream mByteStream = new ByteArrayOutputStream(); @Override public void write(String filePath, Writer w) { - DataOutputStream outputStream = new DataOutputStream(byteStream); + DataOutputStream outputStream = new DataOutputStream(mByteStream); try { w.onWriteCalled(outputStream); From 6e429bec00507a82aadfdc2490797e21b3a3b520 Mon Sep 17 00:00:00 2001 From: Frank Date: Fri, 4 Mar 2022 15:03:36 +0800 Subject: [PATCH 1136/1150] [DU04-2]Appropriate changes to the NetworkPolicyManager API Divide the NetworkPolicyManager API notifyStatsProviderWarningOrLimitReached into the following two APIs: 1. notifyStatsProviderWarningReached() 2. notifyStatsProviderLimitReached() Bug: 216474563 Test: atest NetworkStatsServiceTest NetworkPolicyManagerTest NetworkPolicyManagerServiceTest OffloadControllerTest Change-Id: Ic413eb532b5e24d4a7e2afabdcf643ab6607b1ed --- .../provider/INetworkStatsProviderCallback.aidl | 3 ++- .../net/netstats/provider/NetworkStatsProvider.java | 6 +++--- .../com/android/server/net/NetworkStatsService.java | 13 ++++++++++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl b/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl index 7eaa01e262..01ff02dfc5 100644 --- a/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl +++ b/framework-t/src/android/net/netstats/provider/INetworkStatsProviderCallback.aidl @@ -26,6 +26,7 @@ import android.net.NetworkStats; oneway interface INetworkStatsProviderCallback { void notifyStatsUpdated(int token, in NetworkStats ifaceStats, in NetworkStats uidStats); void notifyAlertReached(); - void notifyWarningOrLimitReached(); + void notifyWarningReached(); + void notifyLimitReached(); void unregister(); } diff --git a/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java b/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java index 23fc06927e..d37a53dbf1 100644 --- a/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java +++ b/framework-t/src/android/net/netstats/provider/NetworkStatsProvider.java @@ -152,19 +152,19 @@ public abstract class NetworkStatsProvider { try { // Reuse the code path to notify warning reached with limit reached // since framework handles them in the same way. - getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + getProviderCallbackBinderOrThrow().notifyWarningReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } } /** - * Notify system that the quota set by {@link #onSetLimit} or limit set by + * Notify system that the limit set by {@link #onSetLimit} or limit set by * {@link #onSetWarningAndLimit} has been reached. */ public void notifyLimitReached() { try { - getProviderCallbackBinderOrThrow().notifyWarningOrLimitReached(); + getProviderCallbackBinderOrThrow().notifyLimitReached(); } catch (RemoteException e) { e.rethrowAsRuntimeException(); } diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java index f8355817bf..e8827d8032 100644 --- a/service-t/src/com/android/server/net/NetworkStatsService.java +++ b/service-t/src/com/android/server/net/NetworkStatsService.java @@ -2393,10 +2393,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void notifyWarningOrLimitReached() { - Log.d(TAG, mTag + ": notifyWarningOrLimitReached"); + public void notifyWarningReached() { + Log.d(TAG, mTag + ": notifyWarningReached"); BinderUtils.withCleanCallingIdentity(() -> - mNetworkPolicyManager.notifyStatsProviderWarningOrLimitReached()); + mNetworkPolicyManager.notifyStatsProviderWarningReached()); + } + + @Override + public void notifyLimitReached() { + Log.d(TAG, mTag + ": notifyLimitReached"); + BinderUtils.withCleanCallingIdentity(() -> + mNetworkPolicyManager.notifyStatsProviderLimitReached()); } @Override From 5dc94ede390cb8b58946bdee6b60ad06e9da462f Mon Sep 17 00:00:00 2001 From: junyulai Date: Tue, 1 Mar 2022 16:53:28 +0800 Subject: [PATCH 1137/1150] [MS83.1] Make some APIs module-lib instead of system current Some of the internal classes are not available for priv-apps. Thus, make them module-lib instead. This change also adds some nullability annotations for existing APIs according to go/android-api-guidelines. Test: m Test: m frameworks-base-api-system-current-compat Fix: 217479745 Change-Id: I18de46b11df7232ab82b9465856fdde621283156 --- .../src/android/app/usage/NetworkStats.java | 10 +- .../app/usage/NetworkStatsManager.java | 113 +++++++++++++----- framework-t/src/android/net/NetworkStats.java | 36 +++++- framework-t/src/android/net/TrafficStats.java | 16 +-- 4 files changed, 130 insertions(+), 45 deletions(-) diff --git a/framework-t/src/android/app/usage/NetworkStats.java b/framework-t/src/android/app/usage/NetworkStats.java index 2b6570a6ec..74fe4bd46c 100644 --- a/framework-t/src/android/app/usage/NetworkStats.java +++ b/framework-t/src/android/app/usage/NetworkStats.java @@ -17,6 +17,7 @@ package android.app.usage; import android.annotation.IntDef; +import android.annotation.Nullable; import android.content.Context; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -474,10 +475,11 @@ public final class NetworkStats implements AutoCloseable { /** * Fills the recycled bucket with data of the next bin in the enumeration. - * @param bucketOut Bucket to be filled with data. + * @param bucketOut Bucket to be filled with data. If null, the method does + * nothing and returning false. * @return true if successfully filled the bucket, false otherwise. */ - public boolean getNextBucket(Bucket bucketOut) { + public boolean getNextBucket(@Nullable Bucket bucketOut) { if (mSummary != null) { return getNextSummaryBucket(bucketOut); } else { @@ -651,7 +653,7 @@ public final class NetworkStats implements AutoCloseable { * @param bucketOut Next item will be set here. * @return true if a next item could be set. */ - private boolean getNextSummaryBucket(Bucket bucketOut) { + private boolean getNextSummaryBucket(@Nullable Bucket bucketOut) { if (bucketOut != null && mEnumerationIndex < mSummary.size()) { mRecycledSummaryEntry = mSummary.getValues(mEnumerationIndex++, mRecycledSummaryEntry); fillBucketFromSummaryEntry(bucketOut); @@ -678,7 +680,7 @@ public final class NetworkStats implements AutoCloseable { * @param bucketOut Next item will be set here. * @return true if a next item could be set. */ - private boolean getNextHistoryBucket(Bucket bucketOut) { + private boolean getNextHistoryBucket(@Nullable Bucket bucketOut) { if (bucketOut != null && mHistory != null) { if (mEnumerationIndex < mHistory.size()) { mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++, diff --git a/framework-t/src/android/app/usage/NetworkStatsManager.java b/framework-t/src/android/app/usage/NetworkStatsManager.java index bf518b2d5a..f41475bea1 100644 --- a/framework-t/src/android/app/usage/NetworkStatsManager.java +++ b/framework-t/src/android/app/usage/NetworkStatsManager.java @@ -290,7 +290,7 @@ public class NetworkStatsManager { * statistics collection. */ @WorkerThread - public Bucket querySummaryForDevice(int networkType, String subscriberId, + public Bucket querySummaryForDevice(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { @@ -335,8 +335,8 @@ public class NetworkStatsManager { * statistics collection. */ @WorkerThread - public Bucket querySummaryForUser(int networkType, String subscriberId, long startTime, - long endTime) throws SecurityException, RemoteException { + public Bucket querySummaryForUser(int networkType, @Nullable String subscriberId, + long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { template = createTemplate(networkType, subscriberId); @@ -384,7 +384,7 @@ public class NetworkStatsManager { * statistics collection. */ @WorkerThread - public NetworkStats querySummary(int networkType, String subscriberId, long startTime, + public NetworkStats querySummary(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { @@ -508,15 +508,17 @@ public class NetworkStatsManager { * * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) */ + @NonNull @WorkerThread - public NetworkStats queryDetailsForUid(int networkType, String subscriberId, + public NetworkStats queryDetailsForUid(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); } /** @hide */ - public NetworkStats queryDetailsForUid(NetworkTemplate template, + @NonNull + public NetworkStats queryDetailsForUid(@NonNull NetworkTemplate template, long startTime, long endTime, int uid) throws SecurityException { return queryDetailsForUidTagState(template, startTime, endTime, uid, NetworkStats.Bucket.TAG_NONE, NetworkStats.Bucket.STATE_ALL); @@ -524,23 +526,59 @@ public class NetworkStatsManager { /** * Query network usage statistics details for a given uid and tag. + * + * This may take a long time, and apps should avoid calling this on their main thread. + * Only usable for uids belonging to calling user. Result is not aggregated over time. + * This means buckets' start and end timestamps are going to be between 'startTime' and + * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag + * the same as the 'tag' parameter, and the state the same as the 'state' parameter. + * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, + * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and + * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. + *

            Only includes buckets that atomically occur in the inclusive time range. Doesn't + * interpolate across partial buckets. Since bucket length is in the order of hours, this + * method cannot be used to measure data usage on a fine grained time scale. * This may take a long time, and apps should avoid calling this on their main thread. * - * @see #queryDetailsForUidTagState(int, String, long, long, int, int, int) + * @param networkType As defined in {@link ConnectivityManager}, e.g. + * {@link ConnectivityManager#TYPE_MOBILE}, {@link ConnectivityManager#TYPE_WIFI} + * etc. + * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when querying for the mobile network type to receive usage + * for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. + * @param startTime Start of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param endTime End of period. Defined in terms of "Unix time", see + * {@link java.lang.System#currentTimeMillis}. + * @param uid UID of app + * @param tag TAG of interest. Use {@link NetworkStats.Bucket#TAG_NONE} for aggregated data + * across all the tags. + * @return Statistics which is described above. + * @throws SecurityException if permissions are insufficient to read network statistics. */ + @NonNull @WorkerThread - public NetworkStats queryDetailsForUidTag(int networkType, String subscriberId, + public NetworkStats queryDetailsForUidTag(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid, int tag) throws SecurityException { return queryDetailsForUidTagState(networkType, subscriberId, startTime, endTime, uid, tag, NetworkStats.Bucket.STATE_ALL); } /** - * Query network usage statistics details for a given uid, tag, and state. Only usable for uids - * belonging to calling user. Result is not aggregated over time. This means buckets' start and - * end timestamps are going to be between 'startTime' and 'endTime' parameters. The uid is going - * to be the same as the 'uid' parameter, the tag the same as the 'tag' parameter, and the state - * the same as the 'state' parameter. + * Query network usage statistics details for a given uid, tag, and state. + * + * Only usable for uids belonging to calling user. Result is not aggregated over time. + * This means buckets' start and end timestamps are going to be between 'startTime' and + * 'endTime' parameters. The uid is going to be the same as the 'uid' parameter, the tag + * the same as the 'tag' parameter, and the state the same as the 'state' parameter. * defaultNetwork is going to be {@link NetworkStats.Bucket#DEFAULT_NETWORK_ALL}, * metered is going to be {@link NetworkStats.Bucket#METERED_ALL}, and * roaming is going to be {@link NetworkStats.Bucket#ROAMING_ALL}. @@ -572,11 +610,12 @@ public class NetworkStatsManager { * across all the tags. * @param state state of interest. Use {@link NetworkStats.Bucket#STATE_ALL} to aggregate * traffic from all states. - * @return Statistics object or null if an error happened during statistics collection. + * @return Statistics which is described above. * @throws SecurityException if permissions are insufficient to read network statistics. */ + @NonNull @WorkerThread - public NetworkStats queryDetailsForUidTagState(int networkType, String subscriberId, + public NetworkStats queryDetailsForUidTagState(int networkType, @Nullable String subscriberId, long startTime, long endTime, int uid, int tag, int state) throws SecurityException { NetworkTemplate template; template = createTemplate(networkType, subscriberId); @@ -669,7 +708,7 @@ public class NetworkStatsManager { * statistics collection. */ @WorkerThread - public NetworkStats queryDetails(int networkType, String subscriberId, long startTime, + public NetworkStats queryDetails(int networkType, @Nullable String subscriberId, long startTime, long endTime) throws SecurityException, RemoteException { NetworkTemplate template; try { @@ -698,7 +737,7 @@ public class NetworkStatsManager { * * @hide */ - @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @@ -724,7 +763,7 @@ public class NetworkStatsManager { * * @hide */ - @SystemApi + @SystemApi(client = MODULE_LIBRARIES) @RequiresPermission(anyOf = { NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) @@ -785,10 +824,28 @@ public class NetworkStatsManager { /** * Registers to receive notifications about data usage on specified networks. * - * @see #registerUsageCallback(int, String, long, UsageCallback, Handler) + *

            The callbacks will continue to be called as long as the process is live or + * {@link #unregisterUsageCallback} is called. + * + * @param networkType Type of network to monitor. Either + {@link ConnectivityManager#TYPE_MOBILE} or {@link ConnectivityManager#TYPE_WIFI}. + * @param subscriberId If applicable, the subscriber id of the network interface. + *

            Starting with API level 29, the {@code subscriberId} is guarded by + * additional restrictions. Calling apps that do not meet the new + * requirements to access the {@code subscriberId} can provide a {@code + * null} value when registering for the mobile network type to receive + * notifications for all mobile networks. For additional details see {@link + * TelephonyManager#getSubscriberId()}. + *

            Starting with API level 31, calling apps can provide a + * {@code subscriberId} with wifi network type to receive usage for + * wifi networks which is under the given subscription if applicable. + * Otherwise, pass {@code null} when querying all wifi networks. + * @param thresholdBytes Threshold in bytes to be notified on. + * @param callback The {@link UsageCallback} that the system will call when data usage + * has exceeded the specified threshold. */ - public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, - UsageCallback callback) { + public void registerUsageCallback(int networkType, @Nullable String subscriberId, + long thresholdBytes, @NonNull UsageCallback callback) { registerUsageCallback(networkType, subscriberId, thresholdBytes, callback, null /* handler */); } @@ -818,8 +875,8 @@ public class NetworkStatsManager { * @param handler to dispatch callback events through, otherwise if {@code null} it uses * the calling thread. */ - public void registerUsageCallback(int networkType, String subscriberId, long thresholdBytes, - UsageCallback callback, @Nullable Handler handler) { + public void registerUsageCallback(int networkType, @Nullable String subscriberId, + long thresholdBytes, @NonNull UsageCallback callback, @Nullable Handler handler) { NetworkTemplate template = createTemplate(networkType, subscriberId); if (DBG) { Log.d(TAG, "registerUsageCallback called with: {" @@ -839,7 +896,7 @@ public class NetworkStatsManager { * * @param callback The {@link UsageCallback} used when registering. */ - public void unregisterUsageCallback(UsageCallback callback) { + public void unregisterUsageCallback(@NonNull UsageCallback callback) { if (callback == null || callback.request == null || callback.request.requestId == DataUsageRequest.REQUEST_ID_UNSET) { throw new IllegalArgumentException("Invalid UsageCallback"); @@ -880,7 +937,7 @@ public class NetworkStatsManager { /** * Called when data usage has reached the given threshold. */ - public abstract void onThresholdReached(int networkType, String subscriberId); + public abstract void onThresholdReached(int networkType, @Nullable String subscriberId); /** * @hide used for internal bookkeeping @@ -924,7 +981,7 @@ public class NetworkStatsManager { @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STATS_PROVIDER, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public void registerNetworkStatsProvider( + public void registerNetworkStatsProvider( @NonNull String tag, @NonNull NetworkStatsProvider provider) { try { @@ -950,7 +1007,7 @@ public class NetworkStatsManager { @RequiresPermission(anyOf = { android.Manifest.permission.NETWORK_STATS_PROVIDER, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) - @NonNull public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { + public void unregisterNetworkStatsProvider(@NonNull NetworkStatsProvider provider) { try { provider.getProviderCallbackBinderOrThrow().unregister(); } catch (RemoteException e) { @@ -958,7 +1015,7 @@ public class NetworkStatsManager { } } - private static NetworkTemplate createTemplate(int networkType, String subscriberId) { + private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) { final NetworkTemplate template; switch (networkType) { case ConnectivityManager.TYPE_MOBILE: diff --git a/framework-t/src/android/net/NetworkStats.java b/framework-t/src/android/net/NetworkStats.java index 06f2a621bc..bcfeab9608 100644 --- a/framework-t/src/android/net/NetworkStats.java +++ b/framework-t/src/android/net/NetworkStats.java @@ -16,6 +16,8 @@ package android.net; +import static android.annotation.SystemApi.Client.MODULE_LIBRARIES; + import static com.android.net.module.util.NetworkStatsUtils.multiplySafeByRational; import android.annotation.IntDef; @@ -124,7 +126,6 @@ public final class NetworkStats implements Parcelable, Iterable iterator() { return new Iterator() { int mIndex = 0; diff --git a/framework-t/src/android/net/TrafficStats.java b/framework-t/src/android/net/TrafficStats.java index bc836d857e..dc4ac552a4 100644 --- a/framework-t/src/android/net/TrafficStats.java +++ b/framework-t/src/android/net/TrafficStats.java @@ -205,7 +205,7 @@ public class TrafficStats { * server context. * @hide */ - @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES) + @SystemApi(client = MODULE_LIBRARIES) @SuppressLint("VisiblySynchronized") public static synchronized void init(@NonNull final Context context) { if (sStatsService != null) { @@ -376,7 +376,7 @@ public class TrafficStats { * * @hide */ - @SystemApi + @SystemApi(client = MODULE_LIBRARIES) public static void setThreadStatsTagDownload() { setThreadStatsTag(TAG_SYSTEM_DOWNLOAD); } @@ -468,7 +468,7 @@ public class TrafficStats { * * @see #setThreadStatsTag(int) */ - public static void tagSocket(Socket socket) throws SocketException { + public static void tagSocket(@NonNull Socket socket) throws SocketException { SocketTagger.get().tag(socket); } @@ -483,7 +483,7 @@ public class TrafficStats { * calling {@code untagSocket()} before sending the socket to another * process. */ - public static void untagSocket(Socket socket) throws SocketException { + public static void untagSocket(@NonNull Socket socket) throws SocketException { SocketTagger.get().untag(socket); } @@ -496,14 +496,14 @@ public class TrafficStats { * * @see #setThreadStatsTag(int) */ - public static void tagDatagramSocket(DatagramSocket socket) throws SocketException { + public static void tagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException { SocketTagger.get().tag(socket); } /** * Remove any statistics parameters from the given {@link DatagramSocket}. */ - public static void untagDatagramSocket(DatagramSocket socket) throws SocketException { + public static void untagDatagramSocket(@NonNull DatagramSocket socket) throws SocketException { SocketTagger.get().untag(socket); } @@ -516,7 +516,7 @@ public class TrafficStats { * * @see #setThreadStatsTag(int) */ - public static void tagFileDescriptor(FileDescriptor fd) throws IOException { + public static void tagFileDescriptor(@NonNull FileDescriptor fd) throws IOException { SocketTagger.get().tag(fd); } @@ -524,7 +524,7 @@ public class TrafficStats { * Remove any statistics parameters from the given {@link FileDescriptor} * socket. */ - public static void untagFileDescriptor(FileDescriptor fd) throws IOException { + public static void untagFileDescriptor(@NonNull FileDescriptor fd) throws IOException { SocketTagger.get().untag(fd); } From 72155988527c6b95e8e6cb9f259c541b02a06703 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Mon, 14 Mar 2022 18:58:07 +0100 Subject: [PATCH 1138/1150] Add Nullable IpConfiguration to ethernet update request This is not currently used by anyone, but will allow us to only update NetworkCapabilities in the future. This could be useful for testing. Test: atest EthernetServiceTests Bug: 220017952 Change-Id: I9697399bad2bfe66c6f328064be75f4dfa10af81 --- .../net/EthernetNetworkUpdateRequest.java | 28 +++++++++++++------ 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java index 43f4c40f2d..1691942c36 100644 --- a/framework-t/src/android/net/EthernetNetworkUpdateRequest.java +++ b/framework-t/src/android/net/EthernetNetworkUpdateRequest.java @@ -33,17 +33,20 @@ import java.util.Objects; */ @SystemApi public final class EthernetNetworkUpdateRequest implements Parcelable { - @NonNull + @Nullable private final IpConfiguration mIpConfig; @Nullable private final NetworkCapabilities mNetworkCapabilities; /** - * @return the new {@link IpConfiguration}. + * Setting the {@link IpConfiguration} is optional in {@link EthernetNetworkUpdateRequest}. + * When set to null, the existing IpConfiguration is not updated. + * + * @return the new {@link IpConfiguration} or null. */ - @NonNull + @Nullable public IpConfiguration getIpConfiguration() { - return new IpConfiguration(mIpConfig); + return mIpConfig == null ? null : new IpConfiguration(mIpConfig); } /** @@ -57,9 +60,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { return mNetworkCapabilities == null ? null : new NetworkCapabilities(mNetworkCapabilities); } - private EthernetNetworkUpdateRequest(@NonNull final IpConfiguration ipConfig, + private EthernetNetworkUpdateRequest(@Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities networkCapabilities) { - Objects.requireNonNull(ipConfig); mIpConfig = ipConfig; mNetworkCapabilities = networkCapabilities; } @@ -90,7 +92,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { */ public Builder(@NonNull final EthernetNetworkUpdateRequest request) { Objects.requireNonNull(request); - mBuilderIpConfig = new IpConfiguration(request.mIpConfig); + mBuilderIpConfig = null == request.mIpConfig + ? null : new IpConfiguration(request.mIpConfig); mBuilderNetworkCapabilities = null == request.mNetworkCapabilities ? null : new NetworkCapabilities(request.mNetworkCapabilities); } @@ -101,8 +104,8 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { * @return The builder to facilitate chaining. */ @NonNull - public Builder setIpConfiguration(@NonNull final IpConfiguration ipConfig) { - mBuilderIpConfig = new IpConfiguration(ipConfig); + public Builder setIpConfiguration(@Nullable final IpConfiguration ipConfig) { + mBuilderIpConfig = ipConfig == null ? null : new IpConfiguration(ipConfig); return this; } @@ -119,9 +122,16 @@ public final class EthernetNetworkUpdateRequest implements Parcelable { /** * Build {@link EthernetNetworkUpdateRequest} return the current update request. + * + * @throws IllegalStateException when both mBuilderNetworkCapabilities and mBuilderIpConfig + * are null. */ @NonNull public EthernetNetworkUpdateRequest build() { + if (mBuilderIpConfig == null && mBuilderNetworkCapabilities == null) { + throw new IllegalStateException( + "Cannot construct an empty EthernetNetworkUpdateRequest"); + } return new EthernetNetworkUpdateRequest(mBuilderIpConfig, mBuilderNetworkCapabilities); } } From 77a3a8408b04496241e8695d4afd88c057bc8826 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 11:31:06 +0100 Subject: [PATCH 1139/1150] Change Ethernet API to use OutcomeReceiver This change addresses API review feedback. In addition, it changes the returned result from Network to the interface name. The current API returning a Network object is racy and cannot be implemented correctly. Users should instead use the ConnectivityManager#requestNetwork() API to get hold of the Network for a given interface. Bug: 220017952 Test: TH Change-Id: I7c46545a47034be409071c2ec007d9e1480c6ed0 --- framework-t/Sources.bp | 2 +- .../src/android/net/EthernetManager.java | 102 ++++++++++-------- .../src/android/net/IEthernetManager.aidl | 9 +- ... => INetworkInterfaceOutcomeReceiver.aidl} | 6 +- 4 files changed, 66 insertions(+), 53 deletions(-) rename framework-t/src/android/net/{IEthernetNetworkManagementListener.aidl => INetworkInterfaceOutcomeReceiver.aidl} (80%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 217a1f67c3..bc27852857 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -131,8 +131,8 @@ filegroup { "src/android/net/EthernetNetworkUpdateRequest.java", "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 793f28d5aa..4f61dbf38b 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; +import android.os.OutcomeReceiver; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; @@ -40,7 +41,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.function.BiConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -443,41 +443,45 @@ public class EthernetManager { return new TetheredInterfaceRequest(mService, cbInternal); } - private static final class InternalNetworkManagementListener - extends IEthernetNetworkManagementListener.Stub { + private static final class NetworkInterfaceOutcomeReceiver + extends INetworkInterfaceOutcomeReceiver.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer mListener; + private final OutcomeReceiver mCallback; - InternalNetworkManagementListener( + NetworkInterfaceOutcomeReceiver( @NonNull final Executor executor, - @NonNull final BiConsumer listener) { + @NonNull final OutcomeReceiver + callback) { Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(listener, "Pass a non-null listener"); + Objects.requireNonNull(callback, "Pass a non-null callback"); mExecutor = executor; - mListener = listener; + mCallback = callback; } @Override - public void onComplete( - @Nullable final Network network, - @Nullable final EthernetNetworkManagementException e) { - mExecutor.execute(() -> mListener.accept(network, e)); + public void onResult(@NonNull String iface) { + mExecutor.execute(() -> mCallback.onResult(iface)); + } + + @Override + public void onError(@NonNull EthernetNetworkManagementException e) { + mExecutor.execute(() -> mCallback.onError(e)); } } - private InternalNetworkManagementListener getInternalNetworkManagementListener( + private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( @Nullable final Executor executor, - @Nullable final BiConsumer listener) { - if (null != listener) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); + @Nullable final OutcomeReceiver callback) { + if (null != callback) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); } - final InternalNetworkManagementListener proxy; - if (null == listener) { + final NetworkInterfaceOutcomeReceiver proxy; + if (null == callback) { proxy = null; } else { - proxy = new InternalNetworkManagementListener(executor, listener); + proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); } return proxy; } @@ -492,14 +496,17 @@ public class EthernetManager { * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} * object for this network to put inside the {@code request}. * - * If non-null, the listener will be called exactly once after this is called, unless - * a synchronous exception was thrown. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * * @param iface the name of the interface to act upon. * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device or on an @@ -515,11 +522,11 @@ public class EthernetManager { @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); Objects.requireNonNull(request, "request must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.updateConfiguration(iface, request, proxy); } catch (RemoteException e) { @@ -530,15 +537,17 @@ public class EthernetManager { /** * Set an ethernet network's link state up. * - * When the link is successfully turned up, the listener will be called with the resulting - * network. If any error or unexpected condition happens while the system tries to turn the - * interface up, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method, but this - * may take an unbounded amount of time depending on the actual network conditions. + * When the link is successfully turned up, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -553,10 +562,10 @@ public class EthernetManager { public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.connectNetwork(iface, proxy); } catch (RemoteException e) { @@ -567,14 +576,17 @@ public class EthernetManager { /** * Set an ethernet network's link state down. * - * When the link is successfully turned down, the listener will be called with the network that - * was torn down, if any. If any error or unexpected condition happens while the system tries to - * turn the interface down, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned down, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -589,10 +601,10 @@ public class EthernetManager { public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.disconnectNetwork(iface, proxy); } catch (RemoteException e) { diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 544d02ba76..95ae907a3d 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,9 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.EthernetNetworkUpdateRequest; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; /** @@ -39,7 +40,7 @@ interface IEthernetManager void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in IEthernetNetworkManagementListener listener); - void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); - void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); + in INetworkInterfaceOutcomeReceiver listener); + void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); } diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl similarity index 80% rename from framework-t/src/android/net/IEthernetNetworkManagementListener.aidl rename to framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl index 93edccfdaf..85795ead7a 100644 --- a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl +++ b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl @@ -17,9 +17,9 @@ package android.net; import android.net.EthernetNetworkManagementException; -import android.net.Network; /** @hide */ -oneway interface IEthernetNetworkManagementListener { - void onComplete(in Network network, in EthernetNetworkManagementException exception); +oneway interface INetworkInterfaceOutcomeReceiver { + void onResult(in String iface); + void onError(in EthernetNetworkManagementException e); } \ No newline at end of file From 7844d4151309dc8ab0f32512f5961077b59ba60e Mon Sep 17 00:00:00 2001 From: Quentin Perret Date: Thu, 17 Mar 2022 15:20:53 +0000 Subject: [PATCH 1140/1150] Revert "Change Ethernet API to use OutcomeReceiver" Revert "Change network management listener to outcome receiver" Revert submission 2028203-ethernet-outcomereceiver Reason for revert: BuildMonitor investigating b/225169800 Reverted Changes: I4c204a848:Change Ethernet API to use OutcomeReceiver I7c46545a4:Change Ethernet API to use OutcomeReceiver Id8fadfed9:Change network management listener to outcome rece... Change-Id: I45af594f7233ed89113f4cf7f977092271980672 --- framework-t/Sources.bp | 2 +- .../src/android/net/EthernetManager.java | 102 ++++++++---------- .../src/android/net/IEthernetManager.aidl | 9 +- ...> IEthernetNetworkManagementListener.aidl} | 6 +- 4 files changed, 53 insertions(+), 66 deletions(-) rename framework-t/src/android/net/{INetworkInterfaceOutcomeReceiver.aidl => IEthernetNetworkManagementListener.aidl} (80%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index bc27852857..217a1f67c3 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -131,8 +131,8 @@ filegroup { "src/android/net/EthernetNetworkUpdateRequest.java", "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", + "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", - "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b..793f28d5aa 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -30,7 +30,6 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; -import android.os.OutcomeReceiver; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; @@ -41,6 +40,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.BiConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -443,45 +443,41 @@ public class EthernetManager { return new TetheredInterfaceRequest(mService, cbInternal); } - private static final class NetworkInterfaceOutcomeReceiver - extends INetworkInterfaceOutcomeReceiver.Stub { + private static final class InternalNetworkManagementListener + extends IEthernetNetworkManagementListener.Stub { @NonNull private final Executor mExecutor; @NonNull - private final OutcomeReceiver mCallback; + private final BiConsumer mListener; - NetworkInterfaceOutcomeReceiver( + InternalNetworkManagementListener( @NonNull final Executor executor, - @NonNull final OutcomeReceiver - callback) { + @NonNull final BiConsumer listener) { Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(callback, "Pass a non-null callback"); + Objects.requireNonNull(listener, "Pass a non-null listener"); mExecutor = executor; - mCallback = callback; + mListener = listener; } @Override - public void onResult(@NonNull String iface) { - mExecutor.execute(() -> mCallback.onResult(iface)); - } - - @Override - public void onError(@NonNull EthernetNetworkManagementException e) { - mExecutor.execute(() -> mCallback.onError(e)); + public void onComplete( + @Nullable final Network network, + @Nullable final EthernetNetworkManagementException e) { + mExecutor.execute(() -> mListener.accept(network, e)); } } - private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( + private InternalNetworkManagementListener getInternalNetworkManagementListener( @Nullable final Executor executor, - @Nullable final OutcomeReceiver callback) { - if (null != callback) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); + @Nullable final BiConsumer listener) { + if (null != listener) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); } - final NetworkInterfaceOutcomeReceiver proxy; - if (null == callback) { + final InternalNetworkManagementListener proxy; + if (null == listener) { proxy = null; } else { - proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); + proxy = new InternalNetworkManagementListener(executor, listener); } return proxy; } @@ -496,17 +492,14 @@ public class EthernetManager { * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} * object for this network to put inside the {@code request}. * - * This function accepts an {@link OutcomeReceiver} that is called once the operation has - * finished execution. + * If non-null, the listener will be called exactly once after this is called, unless + * a synchronous exception was thrown. * * @param iface the name of the interface to act upon. * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device or on an @@ -522,11 +515,11 @@ public class EthernetManager { @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { + @Nullable BiConsumer listener) { Objects.requireNonNull(iface, "iface must be non-null"); Objects.requireNonNull(request, "request must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); try { mService.updateConfiguration(iface, request, proxy); } catch (RemoteException e) { @@ -537,17 +530,15 @@ public class EthernetManager { /** * Set an ethernet network's link state up. * - * When the link is successfully turned up, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned up, the listener will be called with the resulting + * network. If any error or unexpected condition happens while the system tries to turn the + * interface up, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method, but this + * may take an unbounded amount of time depending on the actual network conditions. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -562,10 +553,10 @@ public class EthernetManager { public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { + @Nullable BiConsumer listener) { Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); try { mService.connectNetwork(iface, proxy); } catch (RemoteException e) { @@ -576,17 +567,14 @@ public class EthernetManager { /** * Set an ethernet network's link state down. * - * When the link is successfully turned down, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned down, the listener will be called with the network that + * was torn down, if any. If any error or unexpected condition happens while the system tries to + * turn the interface down, the listener will be called with an appropriate exception. + * The listener is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. - * @param callback an optional {@link OutcomeReceiver} to listen for completion of the - * operation. On success, {@link OutcomeReceiver#onResult} is called with the - * interface name. On error, {@link OutcomeReceiver#onError} is called with more - * information about the error. + * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. + * @param listener an optional {@link BiConsumer} to listen for completion of the operation. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -601,10 +589,10 @@ public class EthernetManager { public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable OutcomeReceiver callback) { + @Nullable BiConsumer listener) { Objects.requireNonNull(iface, "iface must be non-null"); - final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( - executor, callback); + final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( + executor, listener); try { mService.disconnectNetwork(iface, proxy); } catch (RemoteException e) { diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 95ae907a3d..544d02ba76 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,9 +18,8 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.EthernetNetworkManagementException; +import android.net.IEthernetNetworkManagementListener; import android.net.EthernetNetworkUpdateRequest; -import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; /** @@ -40,7 +39,7 @@ interface IEthernetManager void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in INetworkInterfaceOutcomeReceiver listener); - void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); - void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + in IEthernetNetworkManagementListener listener); + void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); + void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); } diff --git a/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl b/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl similarity index 80% rename from framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl rename to framework-t/src/android/net/IEthernetNetworkManagementListener.aidl index 85795ead7a..93edccfdaf 100644 --- a/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl +++ b/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl @@ -17,9 +17,9 @@ package android.net; import android.net.EthernetNetworkManagementException; +import android.net.Network; /** @hide */ -oneway interface INetworkInterfaceOutcomeReceiver { - void onResult(in String iface); - void onError(in EthernetNetworkManagementException e); +oneway interface IEthernetNetworkManagementListener { + void onComplete(in Network network, in EthernetNetworkManagementException exception); } \ No newline at end of file From 39ef30ce644ca5f6d6d68680061156825b97f3a0 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Thu, 17 Mar 2022 19:19:21 +0000 Subject: [PATCH 1141/1150] Revert^2 "Change Ethernet API to use OutcomeReceiver" 7844d4151309dc8ab0f32512f5961077b59ba60e Merged-In: I7c46545a47034be409071c2ec007d9e1480c6ed0 Change-Id: If9b055e0862755f1d33b5ba6e026fd827bc1d0ea --- framework-t/Sources.bp | 2 +- .../src/android/net/EthernetManager.java | 102 ++++++++++-------- .../src/android/net/IEthernetManager.aidl | 9 +- ... => INetworkInterfaceOutcomeReceiver.aidl} | 6 +- 4 files changed, 66 insertions(+), 53 deletions(-) rename framework-t/src/android/net/{IEthernetNetworkManagementListener.aidl => INetworkInterfaceOutcomeReceiver.aidl} (80%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 217a1f67c3..bc27852857 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -131,8 +131,8 @@ filegroup { "src/android/net/EthernetNetworkUpdateRequest.java", "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 793f28d5aa..4f61dbf38b 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; +import android.os.OutcomeReceiver; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; @@ -40,7 +41,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.function.BiConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -443,41 +443,45 @@ public class EthernetManager { return new TetheredInterfaceRequest(mService, cbInternal); } - private static final class InternalNetworkManagementListener - extends IEthernetNetworkManagementListener.Stub { + private static final class NetworkInterfaceOutcomeReceiver + extends INetworkInterfaceOutcomeReceiver.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer mListener; + private final OutcomeReceiver mCallback; - InternalNetworkManagementListener( + NetworkInterfaceOutcomeReceiver( @NonNull final Executor executor, - @NonNull final BiConsumer listener) { + @NonNull final OutcomeReceiver + callback) { Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(listener, "Pass a non-null listener"); + Objects.requireNonNull(callback, "Pass a non-null callback"); mExecutor = executor; - mListener = listener; + mCallback = callback; } @Override - public void onComplete( - @Nullable final Network network, - @Nullable final EthernetNetworkManagementException e) { - mExecutor.execute(() -> mListener.accept(network, e)); + public void onResult(@NonNull String iface) { + mExecutor.execute(() -> mCallback.onResult(iface)); + } + + @Override + public void onError(@NonNull EthernetNetworkManagementException e) { + mExecutor.execute(() -> mCallback.onError(e)); } } - private InternalNetworkManagementListener getInternalNetworkManagementListener( + private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( @Nullable final Executor executor, - @Nullable final BiConsumer listener) { - if (null != listener) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); + @Nullable final OutcomeReceiver callback) { + if (null != callback) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); } - final InternalNetworkManagementListener proxy; - if (null == listener) { + final NetworkInterfaceOutcomeReceiver proxy; + if (null == callback) { proxy = null; } else { - proxy = new InternalNetworkManagementListener(executor, listener); + proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); } return proxy; } @@ -492,14 +496,17 @@ public class EthernetManager { * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} * object for this network to put inside the {@code request}. * - * If non-null, the listener will be called exactly once after this is called, unless - * a synchronous exception was thrown. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * * @param iface the name of the interface to act upon. * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device or on an @@ -515,11 +522,11 @@ public class EthernetManager { @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); Objects.requireNonNull(request, "request must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.updateConfiguration(iface, request, proxy); } catch (RemoteException e) { @@ -530,15 +537,17 @@ public class EthernetManager { /** * Set an ethernet network's link state up. * - * When the link is successfully turned up, the listener will be called with the resulting - * network. If any error or unexpected condition happens while the system tries to turn the - * interface up, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method, but this - * may take an unbounded amount of time depending on the actual network conditions. + * When the link is successfully turned up, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -553,10 +562,10 @@ public class EthernetManager { public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.connectNetwork(iface, proxy); } catch (RemoteException e) { @@ -567,14 +576,17 @@ public class EthernetManager { /** * Set an ethernet network's link state down. * - * When the link is successfully turned down, the listener will be called with the network that - * was torn down, if any. If any error or unexpected condition happens while the system tries to - * turn the interface down, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned down, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -589,10 +601,10 @@ public class EthernetManager { public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.disconnectNetwork(iface, proxy); } catch (RemoteException e) { diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 544d02ba76..95ae907a3d 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,9 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.EthernetNetworkUpdateRequest; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; /** @@ -39,7 +40,7 @@ interface IEthernetManager void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in IEthernetNetworkManagementListener listener); - void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); - void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); + in INetworkInterfaceOutcomeReceiver listener); + void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); } diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl similarity index 80% rename from framework-t/src/android/net/IEthernetNetworkManagementListener.aidl rename to framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl index 93edccfdaf..85795ead7a 100644 --- a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl +++ b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl @@ -17,9 +17,9 @@ package android.net; import android.net.EthernetNetworkManagementException; -import android.net.Network; /** @hide */ -oneway interface IEthernetNetworkManagementListener { - void onComplete(in Network network, in EthernetNetworkManagementException exception); +oneway interface INetworkInterfaceOutcomeReceiver { + void onResult(in String iface); + void onError(in EthernetNetworkManagementException e); } \ No newline at end of file From 58b2dffa1c6e8f2edeb9c00f10b38b71d5345cf6 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 11:31:06 +0100 Subject: [PATCH 1142/1150] Change Ethernet API to use OutcomeReceiver This change addresses API review feedback. In addition, it changes the returned result from Network to the interface name. The current API returning a Network object is racy and cannot be implemented correctly. Users should instead use the ConnectivityManager#requestNetwork() API to get hold of the Network for a given interface. Bug: 220017952 Test: TH Ignore-AOSP-First: CP to make automerger happy. Change-Id: I7c46545a47034be409071c2ec007d9e1480c6ed0 --- framework-t/Sources.bp | 2 +- .../src/android/net/EthernetManager.java | 102 ++++++++++-------- .../src/android/net/IEthernetManager.aidl | 9 +- ... => INetworkInterfaceOutcomeReceiver.aidl} | 6 +- 4 files changed, 66 insertions(+), 53 deletions(-) rename framework-t/src/android/net/{IEthernetNetworkManagementListener.aidl => INetworkInterfaceOutcomeReceiver.aidl} (80%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 217a1f67c3..bc27852857 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -131,8 +131,8 @@ filegroup { "src/android/net/EthernetNetworkUpdateRequest.java", "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 793f28d5aa..4f61dbf38b 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; +import android.os.OutcomeReceiver; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; @@ -40,7 +41,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.function.BiConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -443,41 +443,45 @@ public class EthernetManager { return new TetheredInterfaceRequest(mService, cbInternal); } - private static final class InternalNetworkManagementListener - extends IEthernetNetworkManagementListener.Stub { + private static final class NetworkInterfaceOutcomeReceiver + extends INetworkInterfaceOutcomeReceiver.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer mListener; + private final OutcomeReceiver mCallback; - InternalNetworkManagementListener( + NetworkInterfaceOutcomeReceiver( @NonNull final Executor executor, - @NonNull final BiConsumer listener) { + @NonNull final OutcomeReceiver + callback) { Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(listener, "Pass a non-null listener"); + Objects.requireNonNull(callback, "Pass a non-null callback"); mExecutor = executor; - mListener = listener; + mCallback = callback; } @Override - public void onComplete( - @Nullable final Network network, - @Nullable final EthernetNetworkManagementException e) { - mExecutor.execute(() -> mListener.accept(network, e)); + public void onResult(@NonNull String iface) { + mExecutor.execute(() -> mCallback.onResult(iface)); + } + + @Override + public void onError(@NonNull EthernetNetworkManagementException e) { + mExecutor.execute(() -> mCallback.onError(e)); } } - private InternalNetworkManagementListener getInternalNetworkManagementListener( + private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( @Nullable final Executor executor, - @Nullable final BiConsumer listener) { - if (null != listener) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); + @Nullable final OutcomeReceiver callback) { + if (null != callback) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); } - final InternalNetworkManagementListener proxy; - if (null == listener) { + final NetworkInterfaceOutcomeReceiver proxy; + if (null == callback) { proxy = null; } else { - proxy = new InternalNetworkManagementListener(executor, listener); + proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); } return proxy; } @@ -492,14 +496,17 @@ public class EthernetManager { * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} * object for this network to put inside the {@code request}. * - * If non-null, the listener will be called exactly once after this is called, unless - * a synchronous exception was thrown. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * * @param iface the name of the interface to act upon. * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device or on an @@ -515,11 +522,11 @@ public class EthernetManager { @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); Objects.requireNonNull(request, "request must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.updateConfiguration(iface, request, proxy); } catch (RemoteException e) { @@ -530,15 +537,17 @@ public class EthernetManager { /** * Set an ethernet network's link state up. * - * When the link is successfully turned up, the listener will be called with the resulting - * network. If any error or unexpected condition happens while the system tries to turn the - * interface up, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method, but this - * may take an unbounded amount of time depending on the actual network conditions. + * When the link is successfully turned up, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -553,10 +562,10 @@ public class EthernetManager { public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.connectNetwork(iface, proxy); } catch (RemoteException e) { @@ -567,14 +576,17 @@ public class EthernetManager { /** * Set an ethernet network's link state down. * - * When the link is successfully turned down, the listener will be called with the network that - * was torn down, if any. If any error or unexpected condition happens while the system tries to - * turn the interface down, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned down, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -589,10 +601,10 @@ public class EthernetManager { public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.disconnectNetwork(iface, proxy); } catch (RemoteException e) { diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 544d02ba76..95ae907a3d 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,9 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.EthernetNetworkUpdateRequest; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; /** @@ -39,7 +40,7 @@ interface IEthernetManager void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in IEthernetNetworkManagementListener listener); - void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); - void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); + in INetworkInterfaceOutcomeReceiver listener); + void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); } diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl similarity index 80% rename from framework-t/src/android/net/IEthernetNetworkManagementListener.aidl rename to framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl index 93edccfdaf..85795ead7a 100644 --- a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl +++ b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl @@ -17,9 +17,9 @@ package android.net; import android.net.EthernetNetworkManagementException; -import android.net.Network; /** @hide */ -oneway interface IEthernetNetworkManagementListener { - void onComplete(in Network network, in EthernetNetworkManagementException exception); +oneway interface INetworkInterfaceOutcomeReceiver { + void onResult(in String iface); + void onError(in EthernetNetworkManagementException e); } \ No newline at end of file From dceb89599597804dd1c562e94f268b4f3abd9d83 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 12:34:41 +0100 Subject: [PATCH 1143/1150] Fix ethernet enable / disable API The ethernet APIs connectNetwork() / disconnectNetwork() are inaccurately named. Physical link state cannot be changed by calling an API. This change renames these functions to enableInterface and disableInterface, respectively, to better reflect their intention and behavior. Test: atest EthernetManagerPermissionTest Ignore-AOSP-First: CP to make automerger happy. Change-Id: I3361ad0e01e761ffd77faf6c55924fa4612ede90 --- .../src/android/net/EthernetManager.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b..d2d49702cf 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -535,14 +535,13 @@ public class EthernetManager { } /** - * Set an ethernet network's link state up. + * Enable a network interface. * - * When the link is successfully turned up, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Enables a previously disabled network interface. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to enable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -550,7 +549,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -559,7 +557,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void connectNetwork( + public void enableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver callback) { @@ -574,14 +572,14 @@ public class EthernetManager { } /** - * Set an ethernet network's link state down. + * Disable a network interface. * - * When the link is successfully turned down, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Disables the use of a network interface to fulfill network requests. If the interface + * currently serves a request, the network will be torn down. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to disable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -589,7 +587,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -598,7 +595,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void disconnectNetwork( + public void disableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver callback) { From db9e89aa7bd52d840bf547c071cb495f6b932745 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 17 Mar 2022 18:19:39 +0800 Subject: [PATCH 1144/1150] Add setEthernetEnabled and its listener API Bug: 171872016 Test: atest EthernetServiceTests Change-Id: Iefd24d955572589c5bd3ca9a8139ea6e44979e8a --- .../src/android/net/EthernetManager.java | 151 +++++++++++++++--- .../src/android/net/IEthernetManager.aidl | 1 + .../android/net/IEthernetServiceListener.aidl | 1 + 3 files changed, 128 insertions(+), 25 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b..217d670743 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -41,6 +41,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.IntConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -53,15 +54,31 @@ public class EthernetManager { private static final String TAG = "EthernetManager"; private final IEthernetManager mService; - @GuardedBy("mListeners") - private final ArrayList mListeners = new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList> mIfaceListeners = + new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList> mEthernetStateListeners = + new ArrayList<>(); + final Object mListenerLock = new Object(); private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { + @Override + public void onEthernetStateChanged(int state) { + synchronized (mListenerLock) { + for (ListenerInfo li : mEthernetStateListeners) { + li.executor.execute(() -> { + li.listener.accept(state); + }); + } + } + } + @Override public void onInterfaceStateChanged(String iface, int state, int role, IpConfiguration configuration) { - synchronized (mListeners) { - for (ListenerInfo li : mListeners) { + synchronized (mListenerLock) { + for (ListenerInfo li : mIfaceListeners) { li.executor.execute(() -> li.listener.onInterfaceStateChanged(iface, state, role, configuration)); @@ -70,13 +87,29 @@ public class EthernetManager { } }; - private static class ListenerInfo { + /** + * Indicates that Ethernet is disabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_DISABLED = 0; + + /** + * Indicates that Ethernet is enabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_ENABLED = 1; + + private static class ListenerInfo { @NonNull public final Executor executor; @NonNull - public final InterfaceStateListener listener; + public final T listener; - private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull T listener) { this.executor = executor; this.listener = listener; } @@ -289,18 +322,24 @@ public class EthernetManager { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } - synchronized (mListeners) { - mListeners.add(new ListenerInfo(executor, listener)); - if (mListeners.size() == 1) { - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + maybeAddServiceListener(); + mIfaceListeners.add(new ListenerInfo(executor, listener)); } } + @GuardedBy("mListenerLock") + private void maybeAddServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.addListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + /** * Returns an array of available Ethernet interface names. * @hide @@ -323,15 +362,20 @@ public class EthernetManager { @SystemApi(client = MODULE_LIBRARIES) public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { Objects.requireNonNull(listener); - synchronized (mListeners) { - mListeners.removeIf(l -> l.listener == listener); - if (mListeners.isEmpty()) { - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + mIfaceListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } + + @GuardedBy("mListenerLock") + private void maybeRemoveServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.removeListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -611,4 +655,61 @@ public class EthernetManager { throw e.rethrowFromSystemServer(); } } + + /** + * Change ethernet setting. + * + * @param enabled enable or disable ethernet settings. + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) + public void setEthernetEnabled(boolean enabled) { + try { + mService.setEthernetEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Listen to changes in the state of ethernet. + * + * @param executor to run callbacks on. + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addEthernetStateListener(@NonNull Executor executor, + @NonNull IntConsumer listener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + maybeAddServiceListener(); + mEthernetStateListeners.add(new ListenerInfo(executor, listener)); + } + } + + /** + * Removes a listener. + * + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void removeEthernetStateListener(@NonNull IntConsumer listener) { + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + mEthernetStateListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 95ae907a3d..44e27e26f5 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -43,4 +43,5 @@ interface IEthernetManager in INetworkInterfaceOutcomeReceiver listener); void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void setEthernetEnabled(boolean enabled); } diff --git a/framework-t/src/android/net/IEthernetServiceListener.aidl b/framework-t/src/android/net/IEthernetServiceListener.aidl index 6d2ba03f78..751605bb38 100644 --- a/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -21,6 +21,7 @@ import android.net.IpConfiguration; /** @hide */ oneway interface IEthernetServiceListener { + void onEthernetStateChanged(int state); void onInterfaceStateChanged(String iface, int state, int role, in IpConfiguration configuration); } From 217c99da20bd6956bb558371641953d2c2a0e908 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Fri, 18 Mar 2022 13:07:32 +0900 Subject: [PATCH 1145/1150] Add getInterfaceList module-lib API in EthernetManager. Bug: 171872016 Test: m Change-Id: Ib0e6c8f67c6ded7d17bb9e0ff49e7ff495c8819d --- .../src/android/net/EthernetManager.java | 17 +++++++++++++++++ .../src/android/net/IEthernetManager.aidl | 3 +++ 2 files changed, 20 insertions(+) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 217d670743..fc9f1c6366 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -39,6 +39,7 @@ import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.IntConsumer; @@ -712,4 +713,20 @@ public class EthernetManager { maybeRemoveServiceListener(); } } + + /** + * Returns an array of existing Ethernet interface names regardless whether the interface + * is available or not currently. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + @NonNull + public List getInterfaceList() { + try { + return mService.getInterfaceList(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 44e27e26f5..42e4c1ac55 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -23,6 +23,8 @@ import android.net.EthernetNetworkUpdateRequest; import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; +import java.util.List; + /** * Interface that answers queries about, and allows changing * ethernet configuration. @@ -44,4 +46,5 @@ interface IEthernetManager void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void setEthernetEnabled(boolean enabled); + List getInterfaceList(); } From 1d36db9653bf832fb907b4d73687120ea95410f2 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Tue, 15 Mar 2022 16:17:50 +0000 Subject: [PATCH 1146/1150] Add Executors to NSD callbacks Add Executor variants to all methods with callbacks. Bug: 218752665 Test: atest NsdManagerTest Change-Id: I4c31e2d7ae601ea808b1fd64df32d116c6fff97f --- .../src/android/net/nsd/NsdManager.java | 152 +++++++++++++----- 1 file changed, 115 insertions(+), 37 deletions(-) diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java index 512fbcee93..209f372fd3 100644 --- a/framework-t/src/android/net/nsd/NsdManager.java +++ b/framework-t/src/android/net/nsd/NsdManager.java @@ -45,6 +45,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; +import java.util.concurrent.Executor; /** * The Network Service Discovery Manager class provides the API to discover services @@ -285,8 +286,12 @@ public final class NsdManager { private final Context mContext; private int mListenerKey = FIRST_LISTENER_KEY; + @GuardedBy("mMapLock") private final SparseArray mListenerMap = new SparseArray(); + @GuardedBy("mMapLock") private final SparseArray mServiceMap = new SparseArray<>(); + @GuardedBy("mMapLock") + private final SparseArray mExecutorMap = new SparseArray<>(); private final Object mMapLock = new Object(); // Map of listener key sent by client -> per-network discovery tracker @GuardedBy("mPerNetworkDiscoveryMap") @@ -299,6 +304,7 @@ public final class NsdManager { final String mServiceType; final int mProtocolType; final DiscoveryListener mBaseListener; + final Executor mBaseExecutor; final ArrayMap mPerNetworkListeners = new ArrayMap<>(); @@ -308,7 +314,8 @@ public final class NsdManager { final DelegatingDiscoveryListener wrappedListener = new DelegatingDiscoveryListener( network, mBaseListener); mPerNetworkListeners.put(network, wrappedListener); - discoverServices(mServiceType, mProtocolType, network, wrappedListener); + discoverServices(mServiceType, mProtocolType, network, mBaseExecutor, + wrappedListener); } @Override @@ -355,9 +362,10 @@ public final class NsdManager { } private PerNetworkDiscoveryTracker(String serviceType, int protocolType, - DiscoveryListener baseListener) { + Executor baseExecutor, DiscoveryListener baseListener) { mServiceType = serviceType; mProtocolType = protocolType; + mBaseExecutor = baseExecutor; mBaseListener = baseListener; } @@ -644,9 +652,11 @@ public final class NsdManager { final int key = message.arg2; final Object listener; final NsdServiceInfo ns; + final Executor executor; synchronized (mMapLock) { listener = mListenerMap.get(key); ns = mServiceMap.get(key); + executor = mExecutorMap.get(key); } if (listener == null) { Log.d(TAG, "Stale key " + message.arg2); @@ -657,56 +667,64 @@ public final class NsdManager { } switch (what) { case DISCOVER_SERVICES_STARTED: - String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); - ((DiscoveryListener) listener).onDiscoveryStarted(s); + final String s = getNsdServiceInfoType((NsdServiceInfo) message.obj); + executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStarted(s)); break; case DISCOVER_SERVICES_FAILED: removeListener(key); - ((DiscoveryListener) listener).onStartDiscoveryFailed(getNsdServiceInfoType(ns), - message.arg1); + executor.execute(() -> ((DiscoveryListener) listener).onStartDiscoveryFailed( + getNsdServiceInfoType(ns), message.arg1)); break; case SERVICE_FOUND: - ((DiscoveryListener) listener).onServiceFound((NsdServiceInfo) message.obj); + executor.execute(() -> ((DiscoveryListener) listener).onServiceFound( + (NsdServiceInfo) message.obj)); break; case SERVICE_LOST: - ((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj); + executor.execute(() -> ((DiscoveryListener) listener).onServiceLost( + (NsdServiceInfo) message.obj)); break; case STOP_DISCOVERY_FAILED: // TODO: failure to stop discovery should be internal and retried internally, as // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED removeListener(key); - ((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns), - message.arg1); + executor.execute(() -> ((DiscoveryListener) listener).onStopDiscoveryFailed( + getNsdServiceInfoType(ns), message.arg1)); break; case STOP_DISCOVERY_SUCCEEDED: removeListener(key); - ((DiscoveryListener) listener).onDiscoveryStopped(getNsdServiceInfoType(ns)); + executor.execute(() -> ((DiscoveryListener) listener).onDiscoveryStopped( + getNsdServiceInfoType(ns))); break; case REGISTER_SERVICE_FAILED: removeListener(key); - ((RegistrationListener) listener).onRegistrationFailed(ns, message.arg1); + executor.execute(() -> ((RegistrationListener) listener).onRegistrationFailed( + ns, message.arg1)); break; case REGISTER_SERVICE_SUCCEEDED: - ((RegistrationListener) listener).onServiceRegistered( - (NsdServiceInfo) message.obj); + executor.execute(() -> ((RegistrationListener) listener).onServiceRegistered( + (NsdServiceInfo) message.obj)); break; case UNREGISTER_SERVICE_FAILED: removeListener(key); - ((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1); + executor.execute(() -> ((RegistrationListener) listener).onUnregistrationFailed( + ns, message.arg1)); break; case UNREGISTER_SERVICE_SUCCEEDED: // TODO: do not unregister listener until service is unregistered, or provide // alternative way for unregistering ? removeListener(message.arg2); - ((RegistrationListener) listener).onServiceUnregistered(ns); + executor.execute(() -> ((RegistrationListener) listener).onServiceUnregistered( + ns)); break; case RESOLVE_SERVICE_FAILED: removeListener(key); - ((ResolveListener) listener).onResolveFailed(ns, message.arg1); + executor.execute(() -> ((ResolveListener) listener).onResolveFailed( + ns, message.arg1)); break; case RESOLVE_SERVICE_SUCCEEDED: removeListener(key); - ((ResolveListener) listener).onServiceResolved((NsdServiceInfo) message.obj); + executor.execute(() -> ((ResolveListener) listener).onServiceResolved( + (NsdServiceInfo) message.obj)); break; default: Log.d(TAG, "Ignored " + message); @@ -722,7 +740,7 @@ public final class NsdManager { } // Assert that the listener is not in the map, then add it and returns its key - private int putListener(Object listener, NsdServiceInfo s) { + private int putListener(Object listener, Executor e, NsdServiceInfo s) { checkListener(listener); final int key; synchronized (mMapLock) { @@ -733,6 +751,7 @@ public final class NsdManager { key = nextListenerKey(); mListenerMap.put(key, listener); mServiceMap.put(key, s); + mExecutorMap.put(key, e); } return key; } @@ -741,6 +760,7 @@ public final class NsdManager { synchronized (mMapLock) { mListenerMap.remove(key); mServiceMap.remove(key); + mExecutorMap.remove(key); } } @@ -779,12 +799,33 @@ public final class NsdManager { */ public void registerService(NsdServiceInfo serviceInfo, int protocolType, RegistrationListener listener) { + registerService(serviceInfo, protocolType, Runnable::run, listener); + } + + /** + * Register a service to be discovered by other services. + * + *

            The function call immediately returns after sending a request to register service + * to the framework. The application is notified of a successful registration + * through the callback {@link RegistrationListener#onServiceRegistered} or a failure + * through {@link RegistrationListener#onRegistrationFailed}. + * + *

            The application should call {@link #unregisterService} when the service + * registration is no longer required, and/or whenever the application is stopped. + * @param serviceInfo The service being registered + * @param protocolType The service discovery protocol + * @param executor Executor to run listener callbacks with + * @param listener The listener notifies of a successful registration and is used to + * unregister this service through a call on {@link #unregisterService}. Cannot be null. + */ + public void registerService(@NonNull NsdServiceInfo serviceInfo, int protocolType, + @NonNull Executor executor, @NonNull RegistrationListener listener) { if (serviceInfo.getPort() <= 0) { throw new IllegalArgumentException("Invalid port number"); } checkServiceInfo(serviceInfo); checkProtocol(protocolType); - int key = putListener(listener, serviceInfo); + int key = putListener(listener, executor, serviceInfo); try { mService.registerService(key, serviceInfo); } catch (RemoteException e) { @@ -814,14 +855,6 @@ public final class NsdManager { } } - /** - * Same as {@link #discoverServices(String, int, Network, DiscoveryListener)} with a null - * {@link Network}. - */ - public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { - discoverServices(serviceType, protocolType, (Network) null, listener); - } - /** * Initiate service discovery to browse for instances of a service type. Service discovery * consumes network bandwidth and will continue until the application calls @@ -846,13 +879,45 @@ public final class NsdManager { * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers * @param protocolType The service discovery protocol - * @param network Network to discover services on, or null to discover on all available networks * @param listener The listener notifies of a successful discovery and is used * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. * Cannot be null. Cannot be in use for an active service discovery. */ + public void discoverServices(String serviceType, int protocolType, DiscoveryListener listener) { + discoverServices(serviceType, protocolType, (Network) null, Runnable::run, listener); + } + + /** + * Initiate service discovery to browse for instances of a service type. Service discovery + * consumes network bandwidth and will continue until the application calls + * {@link #stopServiceDiscovery}. + * + *

            The function call immediately returns after sending a request to start service + * discovery to the framework. The application is notified of a success to initiate + * discovery through the callback {@link DiscoveryListener#onDiscoveryStarted} or a failure + * through {@link DiscoveryListener#onStartDiscoveryFailed}. + * + *

            Upon successful start, application is notified when a service is found with + * {@link DiscoveryListener#onServiceFound} or when a service is lost with + * {@link DiscoveryListener#onServiceLost}. + * + *

            Upon failure to start, service discovery is not active and application does + * not need to invoke {@link #stopServiceDiscovery} + * + *

            The application should call {@link #stopServiceDiscovery} when discovery of this + * service type is no longer required, and/or whenever the application is paused or + * stopped. + * @param serviceType The service type being discovered. Examples include "_http._tcp" for + * http services or "_ipp._tcp" for printers + * @param protocolType The service discovery protocol + * @param network Network to discover services on, or null to discover on all available networks + * @param executor Executor to run listener callbacks with + * @param listener The listener notifies of a successful discovery and is used + * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. + */ public void discoverServices(@NonNull String serviceType, int protocolType, - @Nullable Network network, @NonNull DiscoveryListener listener) { + @Nullable Network network, @NonNull Executor executor, + @NonNull DiscoveryListener listener) { if (TextUtils.isEmpty(serviceType)) { throw new IllegalArgumentException("Service type cannot be empty"); } @@ -862,7 +927,7 @@ public final class NsdManager { s.setServiceType(serviceType); s.setNetwork(network); - int key = putListener(listener, s); + int key = putListener(listener, executor, s); try { mService.discoverServices(key, s); } catch (RemoteException e) { @@ -899,18 +964,18 @@ public final class NsdManager { * themselves are encouraged to use this method instead of other overloads of * {@code discoverServices}, as they will receive proper notifications when a service becomes * available or unavailable due to network changes. - * * @param serviceType The service type being discovered. Examples include "_http._tcp" for * http services or "_ipp._tcp" for printers * @param protocolType The service discovery protocol * @param networkRequest Request specifying networks that should be considered when discovering + * @param executor Executor to run listener callbacks with * @param listener The listener notifies of a successful discovery and is used * to stop discovery on this serviceType through a call on {@link #stopServiceDiscovery}. - * Cannot be null. Cannot be in use for an active service discovery. */ @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void discoverServices(@NonNull String serviceType, int protocolType, - @NonNull NetworkRequest networkRequest, @NonNull DiscoveryListener listener) { + @NonNull NetworkRequest networkRequest, @NonNull Executor executor, + @NonNull DiscoveryListener listener) { if (TextUtils.isEmpty(serviceType)) { throw new IllegalArgumentException("Service type cannot be empty"); } @@ -920,10 +985,10 @@ public final class NsdManager { NsdServiceInfo s = new NsdServiceInfo(); s.setServiceType(serviceType); - final int baseListenerKey = putListener(listener, s); + final int baseListenerKey = putListener(listener, executor, s); final PerNetworkDiscoveryTracker discoveryInfo = new PerNetworkDiscoveryTracker( - serviceType, protocolType, listener); + serviceType, protocolType, executor, listener); synchronized (mPerNetworkDiscoveryMap) { mPerNetworkDiscoveryMap.put(baseListenerKey, discoveryInfo); @@ -974,8 +1039,21 @@ public final class NsdManager { * Cannot be in use for an active service resolution. */ public void resolveService(NsdServiceInfo serviceInfo, ResolveListener listener) { + resolveService(serviceInfo, Runnable::run, listener); + } + + /** + * Resolve a discovered service. An application can resolve a service right before + * establishing a connection to fetch the IP and port details on which to setup + * the connection. + * @param serviceInfo service to be resolved + * @param executor Executor to run listener callbacks with + * @param listener to receive callback upon success or failure. + */ + public void resolveService(@NonNull NsdServiceInfo serviceInfo, + @NonNull Executor executor, @NonNull ResolveListener listener) { checkServiceInfo(serviceInfo); - int key = putListener(listener, serviceInfo); + int key = putListener(listener, executor, serviceInfo); try { mService.resolveService(key, serviceInfo); } catch (RemoteException e) { From f4282112591ed65b3f71a18ada596ecdda7a6589 Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 12:34:41 +0100 Subject: [PATCH 1147/1150] Fix ethernet enable / disable API The ethernet APIs connectNetwork() / disconnectNetwork() are inaccurately named. Physical link state cannot be changed by calling an API. This change renames these functions to enableInterface and disableInterface, respectively, to better reflect their intention and behavior. Test: atest EthernetManagerPermissionTest Merged-In: I3361ad0e01e761ffd77faf6c55924fa4612ede90 Change-Id: I3361ad0e01e761ffd77faf6c55924fa4612ede90 --- .../src/android/net/EthernetManager.java | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b..d2d49702cf 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -535,14 +535,13 @@ public class EthernetManager { } /** - * Set an ethernet network's link state up. + * Enable a network interface. * - * When the link is successfully turned up, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Enables a previously disabled network interface. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to enable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -550,7 +549,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -559,7 +557,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void connectNetwork( + public void enableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver callback) { @@ -574,14 +572,14 @@ public class EthernetManager { } /** - * Set an ethernet network's link state down. + * Disable a network interface. * - * When the link is successfully turned down, the callback will be called with the network - * interface was torn down, if any. If any error or unexpected condition happens while the - * system tries to turn the interface down, the callback will be called with an appropriate - * exception. The callback is guaranteed to be called exactly once for each call to this method. + * Disables the use of a network interface to fulfill network requests. If the interface + * currently serves a request, the network will be torn down. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * - * @param iface the name of the interface to act upon. + * @param iface the name of the interface to disable. * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. * @param callback an optional {@link OutcomeReceiver} to listen for completion of the * operation. On success, {@link OutcomeReceiver#onResult} is called with the @@ -589,7 +587,6 @@ public class EthernetManager { * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. - * @throws UnsupportedOperationException if called on a non-automotive device. * @hide */ @SystemApi @@ -598,7 +595,7 @@ public class EthernetManager { android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}) @RequiresFeature(PackageManager.FEATURE_AUTOMOTIVE) - public void disconnectNetwork( + public void disableInterface( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, @Nullable OutcomeReceiver callback) { From c854d709b30bcf79d0dd910762eb0e8697d4b1d2 Mon Sep 17 00:00:00 2001 From: markchien Date: Thu, 17 Mar 2022 18:19:39 +0800 Subject: [PATCH 1148/1150] Add setEthernetEnabled and its listener API Bug: 171872016 Test: atest EthernetServiceTests Merged-In: Iefd24d955572589c5bd3ca9a8139ea6e44979e8a Change-Id: Iefd24d955572589c5bd3ca9a8139ea6e44979e8a --- .../src/android/net/EthernetManager.java | 151 +++++++++++++++--- .../src/android/net/IEthernetManager.aidl | 1 + .../android/net/IEthernetServiceListener.aidl | 1 + 3 files changed, 128 insertions(+), 25 deletions(-) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 4f61dbf38b..217d670743 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -41,6 +41,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; +import java.util.function.IntConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -53,15 +54,31 @@ public class EthernetManager { private static final String TAG = "EthernetManager"; private final IEthernetManager mService; - @GuardedBy("mListeners") - private final ArrayList mListeners = new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList> mIfaceListeners = + new ArrayList<>(); + @GuardedBy("mListenerLock") + private final ArrayList> mEthernetStateListeners = + new ArrayList<>(); + final Object mListenerLock = new Object(); private final IEthernetServiceListener.Stub mServiceListener = new IEthernetServiceListener.Stub() { + @Override + public void onEthernetStateChanged(int state) { + synchronized (mListenerLock) { + for (ListenerInfo li : mEthernetStateListeners) { + li.executor.execute(() -> { + li.listener.accept(state); + }); + } + } + } + @Override public void onInterfaceStateChanged(String iface, int state, int role, IpConfiguration configuration) { - synchronized (mListeners) { - for (ListenerInfo li : mListeners) { + synchronized (mListenerLock) { + for (ListenerInfo li : mIfaceListeners) { li.executor.execute(() -> li.listener.onInterfaceStateChanged(iface, state, role, configuration)); @@ -70,13 +87,29 @@ public class EthernetManager { } }; - private static class ListenerInfo { + /** + * Indicates that Ethernet is disabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_DISABLED = 0; + + /** + * Indicates that Ethernet is enabled. + * + * @hide + */ + @SystemApi(client = MODULE_LIBRARIES) + public static final int ETHERNET_STATE_ENABLED = 1; + + private static class ListenerInfo { @NonNull public final Executor executor; @NonNull - public final InterfaceStateListener listener; + public final T listener; - private ListenerInfo(@NonNull Executor executor, @NonNull InterfaceStateListener listener) { + private ListenerInfo(@NonNull Executor executor, @NonNull T listener) { this.executor = executor; this.listener = listener; } @@ -289,18 +322,24 @@ public class EthernetManager { if (listener == null || executor == null) { throw new NullPointerException("listener and executor must not be null"); } - synchronized (mListeners) { - mListeners.add(new ListenerInfo(executor, listener)); - if (mListeners.size() == 1) { - try { - mService.addListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + maybeAddServiceListener(); + mIfaceListeners.add(new ListenerInfo(executor, listener)); } } + @GuardedBy("mListenerLock") + private void maybeAddServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.addListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + + } + /** * Returns an array of available Ethernet interface names. * @hide @@ -323,15 +362,20 @@ public class EthernetManager { @SystemApi(client = MODULE_LIBRARIES) public void removeInterfaceStateListener(@NonNull InterfaceStateListener listener) { Objects.requireNonNull(listener); - synchronized (mListeners) { - mListeners.removeIf(l -> l.listener == listener); - if (mListeners.isEmpty()) { - try { - mService.removeListener(mServiceListener); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } + synchronized (mListenerLock) { + mIfaceListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } + + @GuardedBy("mListenerLock") + private void maybeRemoveServiceListener() { + if (!mIfaceListeners.isEmpty() || !mEthernetStateListeners.isEmpty()) return; + + try { + mService.removeListener(mServiceListener); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); } } @@ -611,4 +655,61 @@ public class EthernetManager { throw e.rethrowFromSystemServer(); } } + + /** + * Change ethernet setting. + * + * @param enabled enable or disable ethernet settings. + * + * @hide + */ + @RequiresPermission(anyOf = { + NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, + android.Manifest.permission.NETWORK_STACK, + android.Manifest.permission.NETWORK_SETTINGS}) + @SystemApi(client = MODULE_LIBRARIES) + public void setEthernetEnabled(boolean enabled) { + try { + mService.setEthernetEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Listen to changes in the state of ethernet. + * + * @param executor to run callbacks on. + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void addEthernetStateListener(@NonNull Executor executor, + @NonNull IntConsumer listener) { + Objects.requireNonNull(executor); + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + maybeAddServiceListener(); + mEthernetStateListeners.add(new ListenerInfo(executor, listener)); + } + } + + /** + * Removes a listener. + * + * @param listener to listen ethernet state changed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + public void removeEthernetStateListener(@NonNull IntConsumer listener) { + Objects.requireNonNull(listener); + synchronized (mListenerLock) { + mEthernetStateListeners.removeIf(l -> l.listener == listener); + maybeRemoveServiceListener(); + } + } } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 95ae907a3d..44e27e26f5 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -43,4 +43,5 @@ interface IEthernetManager in INetworkInterfaceOutcomeReceiver listener); void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void setEthernetEnabled(boolean enabled); } diff --git a/framework-t/src/android/net/IEthernetServiceListener.aidl b/framework-t/src/android/net/IEthernetServiceListener.aidl index 6d2ba03f78..751605bb38 100644 --- a/framework-t/src/android/net/IEthernetServiceListener.aidl +++ b/framework-t/src/android/net/IEthernetServiceListener.aidl @@ -21,6 +21,7 @@ import android.net.IpConfiguration; /** @hide */ oneway interface IEthernetServiceListener { + void onEthernetStateChanged(int state); void onInterfaceStateChanged(String iface, int state, int role, in IpConfiguration configuration); } From 332338bd75cdb391af3348c3f426d15fe6c9e756 Mon Sep 17 00:00:00 2001 From: Xiao Ma Date: Thu, 17 Mar 2022 05:56:09 +0000 Subject: [PATCH 1149/1150] Add getInterfaceList module-lib API in EthernetManager. Bug: 171872016 Test: m Merged-In: Ib0e6c8f67c6ded7d17bb9e0ff49e7ff495c8819d Change-Id: I94fd147d0f8cf09cb7445fd2b5bc8e4528e8390e --- .../src/android/net/EthernetManager.java | 17 +++++++++++++++++ .../src/android/net/IEthernetManager.aidl | 3 +++ 2 files changed, 20 insertions(+) diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 217d670743..fc9f1c6366 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -39,6 +39,7 @@ import com.android.modules.utils.BackgroundThread; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; +import java.util.List; import java.util.Objects; import java.util.concurrent.Executor; import java.util.function.IntConsumer; @@ -712,4 +713,20 @@ public class EthernetManager { maybeRemoveServiceListener(); } } + + /** + * Returns an array of existing Ethernet interface names regardless whether the interface + * is available or not currently. + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) + @SystemApi(client = MODULE_LIBRARIES) + @NonNull + public List getInterfaceList() { + try { + return mService.getInterfaceList(); + } catch (RemoteException e) { + throw e.rethrowAsRuntimeException(); + } + } } diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 44e27e26f5..42e4c1ac55 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -23,6 +23,8 @@ import android.net.EthernetNetworkUpdateRequest; import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; +import java.util.List; + /** * Interface that answers queries about, and allows changing * ethernet configuration. @@ -44,4 +46,5 @@ interface IEthernetManager void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); void setEthernetEnabled(boolean enabled); + List getInterfaceList(); } From 2e6c345418b840a22a83b89946c52f9c18bd197e Mon Sep 17 00:00:00 2001 From: Patrick Rohr Date: Wed, 16 Mar 2022 11:31:06 +0100 Subject: [PATCH 1150/1150] Change Ethernet API to use OutcomeReceiver This change addresses API review feedback. In addition, it changes the returned result from Network to the interface name. The current API returning a Network object is racy and cannot be implemented correctly. Users should instead use the ConnectivityManager#requestNetwork() API to get hold of the Network for a given interface. CP note: the Merged-In ID is not the actual Change-Id of this change in tm-dev. This change was originally merged in aosp, but was subsequently reverted and cherry-picked into tm-dev. The cherry-pick falsely reused the Change-Id of the (now reverted) original change. This causes automerger to skip this change on all branches between aosp-master and tm-dev when the correct Merged-In ID is used. Therefore, the Merged-In ID listed is the Change-Id of an unrelated change that is present in tm-dev but not aosp-master. Bug: 220017952 Test: TH Ignore-AOSP-First: CP to make automerger happy. Merged-In: Iefd24d955572589c5bd3ca9a8139ea6e44979e8a Change-Id: I7c46545a47034be409071c2ec007d9e1480c6ed0 --- framework-t/Sources.bp | 2 +- .../src/android/net/EthernetManager.java | 102 ++++++++++-------- .../src/android/net/IEthernetManager.aidl | 9 +- ... => INetworkInterfaceOutcomeReceiver.aidl} | 6 +- 4 files changed, 66 insertions(+), 53 deletions(-) rename framework-t/src/android/net/{IEthernetNetworkManagementListener.aidl => INetworkInterfaceOutcomeReceiver.aidl} (80%) diff --git a/framework-t/Sources.bp b/framework-t/Sources.bp index 217a1f67c3..bc27852857 100644 --- a/framework-t/Sources.bp +++ b/framework-t/Sources.bp @@ -131,8 +131,8 @@ filegroup { "src/android/net/EthernetNetworkUpdateRequest.java", "src/android/net/EthernetNetworkUpdateRequest.aidl", "src/android/net/IEthernetManager.aidl", - "src/android/net/IEthernetNetworkManagementListener.aidl", "src/android/net/IEthernetServiceListener.aidl", + "src/android/net/INetworkInterfaceOutcomeReceiver.aidl", "src/android/net/ITetheredInterfaceCallback.aidl", ], path: "src", diff --git a/framework-t/src/android/net/EthernetManager.java b/framework-t/src/android/net/EthernetManager.java index 793f28d5aa..4f61dbf38b 100644 --- a/framework-t/src/android/net/EthernetManager.java +++ b/framework-t/src/android/net/EthernetManager.java @@ -30,6 +30,7 @@ import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; import android.content.pm.PackageManager; import android.os.Build; +import android.os.OutcomeReceiver; import android.os.RemoteException; import com.android.internal.annotations.GuardedBy; @@ -40,7 +41,6 @@ import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.Objects; import java.util.concurrent.Executor; -import java.util.function.BiConsumer; /** * A class that manages and configures Ethernet interfaces. @@ -443,41 +443,45 @@ public class EthernetManager { return new TetheredInterfaceRequest(mService, cbInternal); } - private static final class InternalNetworkManagementListener - extends IEthernetNetworkManagementListener.Stub { + private static final class NetworkInterfaceOutcomeReceiver + extends INetworkInterfaceOutcomeReceiver.Stub { @NonNull private final Executor mExecutor; @NonNull - private final BiConsumer mListener; + private final OutcomeReceiver mCallback; - InternalNetworkManagementListener( + NetworkInterfaceOutcomeReceiver( @NonNull final Executor executor, - @NonNull final BiConsumer listener) { + @NonNull final OutcomeReceiver + callback) { Objects.requireNonNull(executor, "Pass a non-null executor"); - Objects.requireNonNull(listener, "Pass a non-null listener"); + Objects.requireNonNull(callback, "Pass a non-null callback"); mExecutor = executor; - mListener = listener; + mCallback = callback; } @Override - public void onComplete( - @Nullable final Network network, - @Nullable final EthernetNetworkManagementException e) { - mExecutor.execute(() -> mListener.accept(network, e)); + public void onResult(@NonNull String iface) { + mExecutor.execute(() -> mCallback.onResult(iface)); + } + + @Override + public void onError(@NonNull EthernetNetworkManagementException e) { + mExecutor.execute(() -> mCallback.onError(e)); } } - private InternalNetworkManagementListener getInternalNetworkManagementListener( + private NetworkInterfaceOutcomeReceiver makeNetworkInterfaceOutcomeReceiver( @Nullable final Executor executor, - @Nullable final BiConsumer listener) { - if (null != listener) { - Objects.requireNonNull(executor, "Pass a non-null executor, or a null listener"); + @Nullable final OutcomeReceiver callback) { + if (null != callback) { + Objects.requireNonNull(executor, "Pass a non-null executor, or a null callback"); } - final InternalNetworkManagementListener proxy; - if (null == listener) { + final NetworkInterfaceOutcomeReceiver proxy; + if (null == callback) { proxy = null; } else { - proxy = new InternalNetworkManagementListener(executor, listener); + proxy = new NetworkInterfaceOutcomeReceiver(executor, callback); } return proxy; } @@ -492,14 +496,17 @@ public class EthernetManager { * Similarly, use {@link NetworkCapabilities.Builder} to build a {@code NetworkCapabilities} * object for this network to put inside the {@code request}. * - * If non-null, the listener will be called exactly once after this is called, unless - * a synchronous exception was thrown. + * This function accepts an {@link OutcomeReceiver} that is called once the operation has + * finished execution. * * @param iface the name of the interface to act upon. * @param request the {@link EthernetNetworkUpdateRequest} used to set an ethernet network's * {@link StaticIpConfiguration} and {@link NetworkCapabilities} values. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device or on an @@ -515,11 +522,11 @@ public class EthernetManager { @NonNull String iface, @NonNull EthernetNetworkUpdateRequest request, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); Objects.requireNonNull(request, "request must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.updateConfiguration(iface, request, proxy); } catch (RemoteException e) { @@ -530,15 +537,17 @@ public class EthernetManager { /** * Set an ethernet network's link state up. * - * When the link is successfully turned up, the listener will be called with the resulting - * network. If any error or unexpected condition happens while the system tries to turn the - * interface up, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method, but this - * may take an unbounded amount of time depending on the actual network conditions. + * When the link is successfully turned up, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -553,10 +562,10 @@ public class EthernetManager { public void connectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.connectNetwork(iface, proxy); } catch (RemoteException e) { @@ -567,14 +576,17 @@ public class EthernetManager { /** * Set an ethernet network's link state down. * - * When the link is successfully turned down, the listener will be called with the network that - * was torn down, if any. If any error or unexpected condition happens while the system tries to - * turn the interface down, the listener will be called with an appropriate exception. - * The listener is guaranteed to be called exactly once for each call to this method. + * When the link is successfully turned down, the callback will be called with the network + * interface was torn down, if any. If any error or unexpected condition happens while the + * system tries to turn the interface down, the callback will be called with an appropriate + * exception. The callback is guaranteed to be called exactly once for each call to this method. * * @param iface the name of the interface to act upon. - * @param executor an {@link Executor} to execute the listener on. Optional if listener is null. - * @param listener an optional {@link BiConsumer} to listen for completion of the operation. + * @param executor an {@link Executor} to execute the callback on. Optional if callback is null. + * @param callback an optional {@link OutcomeReceiver} to listen for completion of the + * operation. On success, {@link OutcomeReceiver#onResult} is called with the + * interface name. On error, {@link OutcomeReceiver#onError} is called with more + * information about the error. * @throws SecurityException if the process doesn't hold * {@link android.Manifest.permission.MANAGE_ETHERNET_NETWORKS}. * @throws UnsupportedOperationException if called on a non-automotive device. @@ -589,10 +601,10 @@ public class EthernetManager { public void disconnectNetwork( @NonNull String iface, @Nullable @CallbackExecutor Executor executor, - @Nullable BiConsumer listener) { + @Nullable OutcomeReceiver callback) { Objects.requireNonNull(iface, "iface must be non-null"); - final InternalNetworkManagementListener proxy = getInternalNetworkManagementListener( - executor, listener); + final NetworkInterfaceOutcomeReceiver proxy = makeNetworkInterfaceOutcomeReceiver( + executor, callback); try { mService.disconnectNetwork(iface, proxy); } catch (RemoteException e) { diff --git a/framework-t/src/android/net/IEthernetManager.aidl b/framework-t/src/android/net/IEthernetManager.aidl index 544d02ba76..95ae907a3d 100644 --- a/framework-t/src/android/net/IEthernetManager.aidl +++ b/framework-t/src/android/net/IEthernetManager.aidl @@ -18,8 +18,9 @@ package android.net; import android.net.IpConfiguration; import android.net.IEthernetServiceListener; -import android.net.IEthernetNetworkManagementListener; +import android.net.EthernetNetworkManagementException; import android.net.EthernetNetworkUpdateRequest; +import android.net.INetworkInterfaceOutcomeReceiver; import android.net.ITetheredInterfaceCallback; /** @@ -39,7 +40,7 @@ interface IEthernetManager void requestTetheredInterface(in ITetheredInterfaceCallback callback); void releaseTetheredInterface(in ITetheredInterfaceCallback callback); void updateConfiguration(String iface, in EthernetNetworkUpdateRequest request, - in IEthernetNetworkManagementListener listener); - void connectNetwork(String iface, in IEthernetNetworkManagementListener listener); - void disconnectNetwork(String iface, in IEthernetNetworkManagementListener listener); + in INetworkInterfaceOutcomeReceiver listener); + void connectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); + void disconnectNetwork(String iface, in INetworkInterfaceOutcomeReceiver listener); } diff --git a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl similarity index 80% rename from framework-t/src/android/net/IEthernetNetworkManagementListener.aidl rename to framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl index 93edccfdaf..85795ead7a 100644 --- a/framework-t/src/android/net/IEthernetNetworkManagementListener.aidl +++ b/framework-t/src/android/net/INetworkInterfaceOutcomeReceiver.aidl @@ -17,9 +17,9 @@ package android.net; import android.net.EthernetNetworkManagementException; -import android.net.Network; /** @hide */ -oneway interface IEthernetNetworkManagementListener { - void onComplete(in Network network, in EthernetNetworkManagementException exception); +oneway interface INetworkInterfaceOutcomeReceiver { + void onResult(in String iface); + void onError(in EthernetNetworkManagementException e); } \ No newline at end of file