Merge "Skip RAT type listener registration if IMSI is not available" into rvc-d1-dev am: 5403c7646a

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/12406769

Change-Id: Ia10dc546e107e9c1fc249766c2bcfc5856ce1bd2
diff --git a/core/java/android/net/ITetheredInterfaceCallback.aidl b/core/java/android/net/ITetheredInterfaceCallback.aidl
index e3d0759..14aa023 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
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 3c1b86b..51f09a0 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -26,6 +26,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.net.NetworkUtils.multiplySafeByRational;
 import static android.text.format.DateUtils.SECOND_IN_MILLIS;
 
 import static com.android.internal.util.ArrayUtils.total;
@@ -364,11 +365,12 @@
             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 @@
             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/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
index 1b763ce..29c0a81 100644
--- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java
+++ b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
@@ -19,7 +19,7 @@
  * 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;
 
 }
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 6402e07..b2f0c83 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -1477,7 +1477,7 @@
     }
 
     /**
-     * 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) {
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index e3e02e3..f0bf5c0 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.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 @@
                             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;
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index 05ab2ae..342a11b 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.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 @@
         }
     }
 
-    /**
-     * Safely multiple a value by a rational.
-     * <p>
-     * 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 @@
             }
 
             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 @@
                 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;
diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java
index 86ad0b3..e9868fd 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 @@
     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 @@
                             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 9eff5d1..ce74169 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 @@
         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) {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index ba9f486..71e7c8a 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.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.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 @@
 
     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";
@@ -437,7 +442,10 @@
         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);
     }
 
     /**
@@ -460,11 +468,31 @@
          */
         @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());
+        }
+
+        /**
+         * 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();
+                    }
+                }
+            };
         }
     }
 
@@ -530,11 +558,14 @@
         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 +591,8 @@
             mNetworkStatsSubscriptionsMonitor.stop();
         }
 
+        mContentResolver.unregisterContentObserver(mContentObserver);
+
         final long currentTime = mClock.millis();
 
         // persist any pending stats
diff --git a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
index 1c79332..d202a2a 100644
--- a/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
+++ b/services/core/java/com/android/server/net/NetworkStatsSubscriptionsMonitor.java
@@ -21,6 +21,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;
@@ -77,9 +78,9 @@
     @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);