Merge "[BOT.9] Add unit test for data warning in BpfCoordinator"
diff --git a/api/current.txt b/api/current.txt
index 8163426..c5c15be 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11559,7 +11559,7 @@
   }
 
   public abstract class PackageManager {
-    ctor public PackageManager();
+    ctor @Deprecated public PackageManager();
     method @Deprecated public abstract void addPackageToPreferred(@NonNull String);
     method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
     method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index a2a5469..8df7948 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3400,6 +3400,13 @@
     }
 
     /**
+     * @deprecated Do not instantiate or subclass - obtain an instance from
+     * {@link Context#getPackageManager}
+     */
+    @Deprecated
+    public PackageManager() {}
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      *
diff --git a/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java b/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java
index 26f81d9..dafb924 100644
--- a/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java
+++ b/core/java/com/android/internal/os/KernelCpuUidBpfMapReader.java
@@ -16,7 +16,6 @@
 
 package com.android.internal.os;
 
-import android.os.StrictMode;
 import android.os.SystemClock;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -90,9 +89,21 @@
         if (mErrors > ERROR_THRESHOLD) {
             return;
         }
+        if (endUid < startUid || startUid < 0) {
+            return;
+        }
+
         mWriteLock.lock();
         int firstIndex = mData.indexOfKey(startUid);
+        if (firstIndex < 0) {
+            mData.put(startUid, null);
+            firstIndex = mData.indexOfKey(startUid);
+        }
         int lastIndex = mData.indexOfKey(endUid);
+        if (lastIndex < 0) {
+            mData.put(endUid, null);
+            lastIndex = mData.indexOfKey(endUid);
+        }
         mData.removeAtRange(firstIndex, lastIndex - firstIndex + 1);
         mWriteLock.unlock();
     }
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 22f2498..dc60ede 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -41,6 +41,7 @@
     ENABLE_DISABLE_REASON_USER_SWITCH = 8;
     ENABLE_DISABLE_REASON_RESTORE_USER_SETTING = 9;
     ENABLE_DISABLE_REASON_FACTORY_RESET = 10;
+    ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED = 11;
 }
 
 enum DirectionEnum {
diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt
index 37fc83f..9fb012b 100644
--- a/non-updatable-api/current.txt
+++ b/non-updatable-api/current.txt
@@ -11559,7 +11559,7 @@
   }
 
   public abstract class PackageManager {
-    ctor public PackageManager();
+    ctor @Deprecated public PackageManager();
     method @Deprecated public abstract void addPackageToPreferred(@NonNull String);
     method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
     method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
index d03deda..593d04a 100644
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
@@ -24,8 +24,10 @@
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.NetworkCapabilities;
@@ -253,6 +255,14 @@
     }
 
     @VisibleForTesting
+    static String getSettingsPackageName(@NonNull final PackageManager pm) {
+        final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
+        final ComponentName settingsComponent = settingsIntent.resolveActivity(pm);
+        return settingsComponent != null
+                ? settingsComponent.getPackageName() : "com.android.settings";
+    }
+
+    @VisibleForTesting
     void notifyTetheringDisabledByRestriction() {
         final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
         final String title = res.getString(R.string.disable_tether_notification_title);
@@ -262,8 +272,9 @@
         final PendingIntent pi = PendingIntent.getActivity(
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
-                new Intent(Settings.ACTION_TETHER_SETTINGS),
-                Intent.FLAG_ACTIVITY_NEW_TASK,
+                new Intent(Settings.ACTION_TETHER_SETTINGS)
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -284,7 +295,7 @@
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
                 intent,
-                0 /* flags */);
+                PendingIntent.FLAG_IMMUTABLE);
         final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build();
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
@@ -305,8 +316,9 @@
         final PendingIntent pi = PendingIntent.getActivity(
                 mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
                 0 /* requestCode */,
-                new Intent(Settings.ACTION_TETHER_SETTINGS),
-                Intent.FLAG_ACTIVITY_NEW_TASK,
+                new Intent(Settings.ACTION_TETHER_SETTINGS)
+                        .setPackage(getSettingsPackageName(mContext.getPackageManager())),
+                Intent.FLAG_ACTIVITY_NEW_TASK | PendingIntent.FLAG_IMMUTABLE,
                 null /* options */);
 
         showNotification(R.drawable.stat_sys_tether_general, title, message,
diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
index 7d5471f..4b6bbac 100644
--- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
+++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringNotificationUpdaterTest.kt
@@ -19,6 +19,10 @@
 import android.app.Notification
 import android.app.NotificationManager
 import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.content.pm.PackageManager
+import android.content.pm.ResolveInfo
 import android.content.res.Resources
 import android.net.ConnectivityManager.TETHERING_WIFI
 import android.os.Handler
@@ -51,6 +55,7 @@
 import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.doReturn
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.times
@@ -351,4 +356,26 @@
         notificationUpdater.onUpstreamCapabilitiesChanged(ROAMING_CAPABILITIES)
         verifyNotificationCancelled(listOf(NO_UPSTREAM_NOTIFICATION_ID, ROAMING_NOTIFICATION_ID))
     }
+
+    @Test
+    fun testGetSettingsPackageName() {
+        val defaultSettingsPackageName = "com.android.settings"
+        val testSettingsPackageName = "com.android.test.settings"
+        val pm = mock(PackageManager::class.java)
+        doReturn(null).`when`(pm).resolveActivity(any(), anyInt())
+        assertEquals(defaultSettingsPackageName,
+                TetheringNotificationUpdater.getSettingsPackageName(pm))
+
+        val resolveInfo = ResolveInfo().apply {
+            activityInfo = ActivityInfo().apply {
+                name = "test"
+                applicationInfo = ApplicationInfo().apply {
+                    packageName = testSettingsPackageName
+                }
+            }
+        }
+        doReturn(resolveInfo).`when`(pm).resolveActivity(any(), anyInt())
+        assertEquals(testSettingsPackageName,
+                TetheringNotificationUpdater.getSettingsPackageName(pm))
+    }
 }
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 8f07633..151f4d1 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -59,6 +59,7 @@
 import android.os.UserManager;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.text.TextUtils;
@@ -109,6 +110,7 @@
     private static final int ADD_PROXY_DELAY_MS = 100;
     // Delay for retrying enable and disable in msec
     private static final int ENABLE_DISABLE_DELAY_MS = 300;
+    private static final int DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS = 300;
 
     private static final int MESSAGE_ENABLE = 1;
     private static final int MESSAGE_DISABLE = 2;
@@ -128,6 +130,7 @@
     private static final int MESSAGE_ADD_PROXY_DELAYED = 400;
     private static final int MESSAGE_BIND_PROFILE_SERVICE = 401;
     private static final int MESSAGE_RESTORE_USER_SETTING = 500;
+    private static final int MESSAGE_INIT_FLAGS_CHANGED = 600;
 
     private static final int RESTORE_SETTING_TO_ON = 1;
     private static final int RESTORE_SETTING_TO_OFF = 0;
@@ -267,6 +270,30 @@
                 }
             };
 
+    private final DeviceConfig.OnPropertiesChangedListener mDeviceConfigChangedListener =
+            new DeviceConfig.OnPropertiesChangedListener() {
+                @Override
+                public void onPropertiesChanged(DeviceConfig.Properties properties) {
+                    if (!properties.getNamespace().equals(DeviceConfig.NAMESPACE_BLUETOOTH)) {
+                        return;
+                    }
+                    boolean foundInit = false;
+                    for (String name : properties.getKeyset()) {
+                        if (name.startsWith("INIT_")) {
+                            foundInit = true;
+                            break;
+                        }
+                    }
+                    if (!foundInit) {
+                        return;
+                    }
+                    mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
+                    mHandler.sendEmptyMessageDelayed(
+                            MESSAGE_INIT_FLAGS_CHANGED,
+                            DELAY_BEFORE_RESTART_DUE_TO_INIT_FLAGS_CHANGED_MS);
+                }
+            };
+
     public boolean onFactoryReset() {
         // Wait for stable state if bluetooth is temporary state.
         int state = getState();
@@ -496,6 +523,10 @@
             Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
         }
         mSystemUiUid = systemUiUid;
+        DeviceConfig.addOnPropertiesChangedListener(
+                DeviceConfig.NAMESPACE_BLUETOOTH,
+                (Runnable r) -> r.run(),
+                mDeviceConfigChangedListener);
     }
 
     /**
@@ -2108,80 +2139,7 @@
 
                     /* disable and enable BT when detect a user switch */
                     if (mBluetooth != null && isEnabled()) {
-                        try {
-                            mBluetoothLock.readLock().lock();
-                            if (mBluetooth != null) {
-                                mBluetooth.unregisterCallback(mBluetoothCallback);
-                            }
-                        } catch (RemoteException re) {
-                            Slog.e(TAG, "Unable to unregister", re);
-                        } finally {
-                            mBluetoothLock.readLock().unlock();
-                        }
-
-                        if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
-                            // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
-                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
-                            mState = BluetoothAdapter.STATE_OFF;
-                        }
-                        if (mState == BluetoothAdapter.STATE_OFF) {
-                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
-                            mState = BluetoothAdapter.STATE_TURNING_ON;
-                        }
-
-                        waitForState(Set.of(BluetoothAdapter.STATE_ON));
-
-                        if (mState == BluetoothAdapter.STATE_TURNING_ON) {
-                            bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
-                        }
-
-                        unbindAllBluetoothProfileServices();
-                        // disable
-                        addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH,
-                                mContext.getPackageName(), false);
-                        handleDisable();
-                        // Pbap service need receive STATE_TURNING_OFF intent to close
-                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
-                                BluetoothAdapter.STATE_TURNING_OFF);
-
-                        boolean didDisableTimeout =
-                                !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
-
-                        bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
-                                BluetoothAdapter.STATE_OFF);
-                        sendBluetoothServiceDownCallback();
-
-                        try {
-                            mBluetoothLock.writeLock().lock();
-                            if (mBluetooth != null) {
-                                mBluetooth = null;
-                                // Unbind
-                                mContext.unbindService(mConnection);
-                            }
-                            mBluetoothGatt = null;
-                        } finally {
-                            mBluetoothLock.writeLock().unlock();
-                        }
-
-                        //
-                        // If disabling Bluetooth times out, wait for an
-                        // additional amount of time to ensure the process is
-                        // shut down completely before attempting to restart.
-                        //
-                        if (didDisableTimeout) {
-                            SystemClock.sleep(3000);
-                        } else {
-                            SystemClock.sleep(100);
-                        }
-
-                        mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
-                        mState = BluetoothAdapter.STATE_OFF;
-                        // enable
-                        addActiveLog(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH,
-                                mContext.getPackageName(), true);
-                        // mEnable flag could have been reset on disableBLE. Reenable it.
-                        mEnable = true;
-                        handleEnable(mQuietEnable);
+                        restartForReason(BluetoothProtoEnums.ENABLE_DISABLE_REASON_USER_SWITCH);
                     } else if (mBinding || mBluetooth != null) {
                         Message userMsg = mHandler.obtainMessage(MESSAGE_USER_SWITCHED);
                         userMsg.arg2 = 1 + msg.arg2;
@@ -2208,9 +2166,96 @@
                         }
                         handleEnable(mQuietEnable);
                     }
+                    break;
+                }
+                case MESSAGE_INIT_FLAGS_CHANGED: {
+                    if (DBG) {
+                        Slog.d(TAG, "MESSAGE_INIT_FLAGS_CHANGED");
+                    }
+                    mHandler.removeMessages(MESSAGE_INIT_FLAGS_CHANGED);
+                    if (mBluetooth != null && isEnabled()) {
+                        restartForReason(
+                                BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED);
+                    }
+                    break;
                 }
             }
         }
+
+        private void restartForReason(int reason) {
+            try {
+                mBluetoothLock.readLock().lock();
+                if (mBluetooth != null) {
+                    mBluetooth.unregisterCallback(mBluetoothCallback);
+                }
+            } catch (RemoteException re) {
+                Slog.e(TAG, "Unable to unregister", re);
+            } finally {
+                mBluetoothLock.readLock().unlock();
+            }
+
+            if (mState == BluetoothAdapter.STATE_TURNING_OFF) {
+                // MESSAGE_USER_SWITCHED happened right after MESSAGE_ENABLE
+                bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_OFF);
+                mState = BluetoothAdapter.STATE_OFF;
+            }
+            if (mState == BluetoothAdapter.STATE_OFF) {
+                bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_TURNING_ON);
+                mState = BluetoothAdapter.STATE_TURNING_ON;
+            }
+
+            waitForState(Set.of(BluetoothAdapter.STATE_ON));
+
+            if (mState == BluetoothAdapter.STATE_TURNING_ON) {
+                bluetoothStateChangeHandler(mState, BluetoothAdapter.STATE_ON);
+            }
+
+            unbindAllBluetoothProfileServices();
+            // disable
+            addActiveLog(reason, mContext.getPackageName(), false);
+            handleDisable();
+            // Pbap service need receive STATE_TURNING_OFF intent to close
+            bluetoothStateChangeHandler(BluetoothAdapter.STATE_ON,
+                    BluetoothAdapter.STATE_TURNING_OFF);
+
+            boolean didDisableTimeout =
+                    !waitForState(Set.of(BluetoothAdapter.STATE_OFF));
+
+            bluetoothStateChangeHandler(BluetoothAdapter.STATE_TURNING_OFF,
+                    BluetoothAdapter.STATE_OFF);
+            sendBluetoothServiceDownCallback();
+
+            try {
+                mBluetoothLock.writeLock().lock();
+                if (mBluetooth != null) {
+                    mBluetooth = null;
+                    // Unbind
+                    mContext.unbindService(mConnection);
+                }
+                mBluetoothGatt = null;
+            } finally {
+                mBluetoothLock.writeLock().unlock();
+            }
+
+            //
+            // If disabling Bluetooth times out, wait for an
+            // additional amount of time to ensure the process is
+            // shut down completely before attempting to restart.
+            //
+            if (didDisableTimeout) {
+                SystemClock.sleep(3000);
+            } else {
+                SystemClock.sleep(100);
+            }
+
+            mHandler.removeMessages(MESSAGE_BLUETOOTH_STATE_CHANGE);
+            mState = BluetoothAdapter.STATE_OFF;
+            // enable
+            addActiveLog(reason, mContext.getPackageName(), true);
+            // mEnable flag could have been reset on disableBLE. Reenable it.
+            mEnable = true;
+            handleEnable(mQuietEnable);
+        }
     }
 
     private void handleEnable(boolean quietMode) {
@@ -2643,6 +2688,8 @@
                 return "RESTORE_USER_SETTING";
             case BluetoothProtoEnums.ENABLE_DISABLE_REASON_FACTORY_RESET:
                 return "FACTORY_RESET";
+            case BluetoothProtoEnums.ENABLE_DISABLE_REASON_INIT_FLAGS_CHANGED:
+                return "INIT_FLAGS_CHANGED";
             case BluetoothProtoEnums.ENABLE_DISABLE_REASON_UNSPECIFIED:
             default: return "UNKNOWN[" + reason + "]";
         }