Merge "Cleanup : don't mix seconds and milliseconds in retry delays"
diff --git a/packages/SettingsProvider/src/android/provider/settings/OWNERS b/packages/SettingsProvider/src/android/provider/settings/OWNERS
index 0f88811..d901e2c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/OWNERS
+++ b/packages/SettingsProvider/src/android/provider/settings/OWNERS
@@ -1,4 +1,4 @@
 # Bug component: 656484
 
-include platform/frameworks/base:/services/backup/OWNERS
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
 
diff --git a/packages/SettingsProvider/test/src/android/provider/OWNERS b/packages/SettingsProvider/test/src/android/provider/OWNERS
index 0f88811..db4b27c 100644
--- a/packages/SettingsProvider/test/src/android/provider/OWNERS
+++ b/packages/SettingsProvider/test/src/android/provider/OWNERS
@@ -1,4 +1,3 @@
 # Bug component: 656484
 
-include platform/frameworks/base:/services/backup/OWNERS
-
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
diff --git a/services/backup/BACKUP_OWNERS b/services/backup/BACKUP_OWNERS
new file mode 100644
index 0000000..f8f4f4f
--- /dev/null
+++ b/services/backup/BACKUP_OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 1193469
+
+jstemmer@google.com
+martinoh@google.com
+millmore@google.com
+niamhfw@google.com
+piee@google.com
+philippov@google.com
+rthakohov@google.com
+sarpm@google.com
\ No newline at end of file
diff --git a/services/backup/OWNERS b/services/backup/OWNERS
index 79709a3..3bd2db1 100644
--- a/services/backup/OWNERS
+++ b/services/backup/OWNERS
@@ -2,12 +2,4 @@
 
 set noparent
 
-bryanmawhinney@google.com
-jstemmer@google.com
-martinoh@google.com
-millmore@google.com
-niamhfw@google.com
-piee@google.com
-philippov@google.com
-rthakohov@google.com
-sarpm@google.com
+include platform/frameworks/base:/services/backup/BACKUP_OWNERS
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a2783f3..1dc2725 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -708,6 +708,14 @@
                 boolean isIpv4) {
             return MtuUtils.getMtu(childProposals, maxMtu, underlyingMtu, isIpv4);
         }
+
+        /** Verify the binder calling UID is the one passed in arguments */
+        public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
+            final int callingUid = Binder.getCallingUid();
+            if (getAppUid(context, packageName, userId) != callingUid) {
+                throw new SecurityException(packageName + " does not belong to uid " + callingUid);
+            }
+        }
     }
 
     @VisibleForTesting
@@ -755,7 +763,7 @@
         mUserManager = mContext.getSystemService(UserManager.class);
 
         mPackage = VpnConfig.LEGACY_VPN;
-        mOwnerUID = getAppUid(mPackage, mUserId);
+        mOwnerUID = getAppUid(mContext, mPackage, mUserId);
         mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(mPackage);
 
         try {
@@ -852,7 +860,7 @@
     }
 
     /**
-     * Chooses whether to force all connections to go though VPN.
+     * Chooses whether to force all connections to go through VPN.
      *
      * Used to enable/disable legacy VPN lockdown.
      *
@@ -860,7 +868,7 @@
      * {@link #setAlwaysOnPackage(String, boolean, List<String>)}; previous settings from calling
      * that function will be replaced and saved with the always-on state.
      *
-     * @param lockdown whether to prevent all traffic outside of a VPN.
+     * @param lockdown whether to prevent all traffic outside of the VPN.
      */
     public synchronized void setLockdown(boolean lockdown) {
         enforceControlPermissionOrInternalCaller();
@@ -1137,6 +1145,7 @@
             mAlwaysOn = false;
         }
 
+        final boolean oldLockdownState = mLockdown;
         mLockdown = (mAlwaysOn && lockdown);
         mLockdownAllowlist = (mLockdown && lockdownAllowlist != null)
                 ? Collections.unmodifiableList(new ArrayList<>(lockdownAllowlist))
@@ -1147,6 +1156,13 @@
         if (isCurrentPreparedPackage(packageName)) {
             updateAlwaysOnNotification(mNetworkInfo.getDetailedState());
             setVpnForcedLocked(mLockdown);
+
+            // Lockdown forces the VPN to be non-bypassable (see #agentConnect) because it makes
+            // no sense for a VPN to be bypassable when connected but not when not connected.
+            // As such, changes in lockdown need to restart the agent.
+            if (mNetworkAgent != null && oldLockdownState != mLockdown) {
+                startNewNetworkAgent(mNetworkAgent, "Lockdown mode changed");
+            }
         } else {
             // Prepare this app. The notification will update as a side-effect of updateState().
             // It also calls setVpnForcedLocked().
@@ -1384,7 +1400,8 @@
         // We can't just check that packageName matches mPackage, because if the app was uninstalled
         // and reinstalled it will no longer be prepared. Similarly if there is a shared UID, the
         // calling package may not be the same as the prepared package. Check both UID and package.
-        return getAppUid(packageName, mUserId) == mOwnerUID && mPackage.equals(packageName);
+        return getAppUid(mContext, packageName, mUserId) == mOwnerUID
+                && mPackage.equals(packageName);
     }
 
     /** Prepare the VPN for the given package. Does not perform permission checks. */
@@ -1425,7 +1442,7 @@
 
             Log.i(TAG, "Switched from " + mPackage + " to " + newPackage);
             mPackage = newPackage;
-            mOwnerUID = getAppUid(newPackage, mUserId);
+            mOwnerUID = getAppUid(mContext, newPackage, mUserId);
             mIsPackageTargetingAtLeastQ = doesPackageTargetAtLeastQ(newPackage);
             try {
                 mNms.allowProtect(mOwnerUID);
@@ -1446,7 +1463,7 @@
         // Check if the caller is authorized.
         enforceControlPermissionOrInternalCaller();
 
-        final int uid = getAppUid(packageName, mUserId);
+        final int uid = getAppUid(mContext, packageName, mUserId);
         if (uid == -1 || VpnConfig.LEGACY_VPN.equals(packageName)) {
             // Authorization for nonexistent packages (or fake ones) can't be updated.
             return false;
@@ -1526,11 +1543,11 @@
                 || isVpnServicePreConsented(context, packageName);
     }
 
-    private int getAppUid(final String app, final int userId) {
+    private static int getAppUid(final Context context, final String app, final int userId) {
         if (VpnConfig.LEGACY_VPN.equals(app)) {
             return Process.myUid();
         }
-        PackageManager pm = mContext.getPackageManager();
+        PackageManager pm = context.getPackageManager();
         final long token = Binder.clearCallingIdentity();
         try {
             return pm.getPackageUidAsUser(app, userId);
@@ -1659,6 +1676,10 @@
      */
     private boolean updateLinkPropertiesInPlaceIfPossible(NetworkAgent agent, VpnConfig oldConfig) {
         // NetworkAgentConfig cannot be updated without registering a new NetworkAgent.
+        // Strictly speaking, bypassability is affected by lockdown and therefore it's possible
+        // it doesn't actually change even if mConfig.allowBypass changed. It might be theoretically
+        // possible to do handover in this case, but this is far from obvious to VPN authors and
+        // it's simpler if the rule is just "can't update in place if you change allow bypass".
         if (oldConfig.allowBypass != mConfig.allowBypass) {
             Log.i(TAG, "Handover not possible due to changes to allowBypass");
             return false;
@@ -1700,10 +1721,11 @@
         mLegacyState = LegacyVpnInfo.STATE_CONNECTING;
         updateState(DetailedState.CONNECTING, "agentConnect");
 
+        final boolean bypassable = mConfig.allowBypass && !mLockdown;
         final NetworkAgentConfig networkAgentConfig = new NetworkAgentConfig.Builder()
                 .setLegacyType(ConnectivityManager.TYPE_VPN)
                 .setLegacyTypeName("VPN")
-                .setBypassableVpn(mConfig.allowBypass && !mLockdown)
+                .setBypassableVpn(bypassable)
                 .setVpnRequiresValidation(mConfig.requiresInternetValidation)
                 .setLocalRoutesExcludedForVpn(mConfig.excludeLocalRoutes)
                 .build();
@@ -1717,7 +1739,7 @@
         capsBuilder.setTransportInfo(new VpnTransportInfo(
                 getActiveVpnType(),
                 mConfig.session,
-                mConfig.allowBypass,
+                bypassable,
                 expensive));
 
         // Only apps targeting Q and above can explicitly declare themselves as metered.
@@ -1748,6 +1770,10 @@
             Binder.restoreCallingIdentity(token);
         }
         updateState(DetailedState.CONNECTED, "agentConnect");
+        if (isIkev2VpnRunner()) {
+            final IkeSessionWrapper session = ((IkeV2VpnRunner) mVpnRunner).mSession;
+            if (null != session) session.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
+        }
     }
 
     private static boolean areLongLivedTcpConnectionsExpensive(@NonNull VpnRunner runner) {
@@ -1942,7 +1968,7 @@
     private SortedSet<Integer> getAppsUids(List<String> packageNames, int userId) {
         SortedSet<Integer> uids = new TreeSet<>();
         for (String app : packageNames) {
-            int uid = getAppUid(app, userId);
+            int uid = getAppUid(mContext, app, userId);
             if (uid != -1) uids.add(uid);
             // TODO(b/230548427): Remove SDK check once VPN related stuff are decoupled from
             // ConnectivityServiceTest.
@@ -3261,7 +3287,6 @@
                             prepareStatusIntent();
                         }
                         agentConnect(this::onValidationStatus);
-                        mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
                         return; // Link properties are already sent.
                     } else {
                         // Underlying networks also set in agentConnect()
@@ -3378,7 +3403,6 @@
                     if (!removedAddrs.isEmpty()) {
                         startNewNetworkAgent(
                                 mNetworkAgent, "MTU too low for IPv6; restarting network agent");
-                        mSession.setUnderpinnedNetwork(mNetworkAgent.getNetwork());
 
                         for (LinkAddress removed : removedAddrs) {
                             mTunnelIface.removeAddress(
@@ -3657,7 +3681,7 @@
             final VpnTransportInfo info = new VpnTransportInfo(
                     getActiveVpnType(),
                     mConfig.session,
-                    mConfig.allowBypass,
+                    mConfig.allowBypass && !mLockdown,
                     areLongLivedTcpConnectionsExpensive(keepaliveDelaySec));
             final boolean ncUpdateRequired = !info.equals(mNetworkCapabilities.getTransportInfo());
             if (ncUpdateRequired) {
@@ -4514,10 +4538,7 @@
     }
 
     private void verifyCallingUidAndPackage(String packageName) {
-        final int callingUid = Binder.getCallingUid();
-        if (getAppUid(packageName, mUserId) != callingUid) {
-            throw new SecurityException(packageName + " does not belong to uid " + callingUid);
-        }
+        mDeps.verifyCallingUidAndPackage(mContext, packageName, mUserId);
     }
 
     @VisibleForTesting
diff --git a/services/core/java/com/android/server/infra/OWNERS b/services/core/java/com/android/server/infra/OWNERS
index 0466d8a..4fea05d 100644
--- a/services/core/java/com/android/server/infra/OWNERS
+++ b/services/core/java/com/android/server/infra/OWNERS
@@ -1,3 +1,3 @@
 # Bug component: 655446
 
-include /core/java/android/service/cloudsearch/OWNERS
+srazdan@google.com
diff --git a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
index c099628..8c79875 100644
--- a/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
+++ b/services/core/java/com/android/server/wm/TaskFpsCallbackController.java
@@ -26,8 +26,8 @@
 final class TaskFpsCallbackController {
 
     private final Context mContext;
-    private final HashMap<ITaskFpsCallback, Long> mTaskFpsCallbacks;
-    private final HashMap<ITaskFpsCallback, IBinder.DeathRecipient> mDeathRecipients;
+    private final HashMap<IBinder, Long> mTaskFpsCallbacks;
+    private final HashMap<IBinder, IBinder.DeathRecipient> mDeathRecipients;
 
     TaskFpsCallbackController(Context context) {
         mContext = context;
@@ -36,32 +36,42 @@
     }
 
     void registerListener(int taskId, ITaskFpsCallback callback) {
-        if (mTaskFpsCallbacks.containsKey(callback)) {
+        if (callback == null) {
+            return;
+        }
+
+        IBinder binder = callback.asBinder();
+        if (mTaskFpsCallbacks.containsKey(binder)) {
             return;
         }
 
         final long nativeListener = nativeRegister(callback, taskId);
-        mTaskFpsCallbacks.put(callback, nativeListener);
+        mTaskFpsCallbacks.put(binder, nativeListener);
 
         final IBinder.DeathRecipient deathRecipient = () -> unregisterListener(callback);
         try {
-            callback.asBinder().linkToDeath(deathRecipient, 0);
-            mDeathRecipients.put(callback, deathRecipient);
+            binder.linkToDeath(deathRecipient, 0);
+            mDeathRecipients.put(binder, deathRecipient);
         } catch (RemoteException e) {
             // ignore
         }
     }
 
     void unregisterListener(ITaskFpsCallback callback) {
-        if (!mTaskFpsCallbacks.containsKey(callback)) {
+        if (callback == null) {
             return;
         }
 
-        callback.asBinder().unlinkToDeath(mDeathRecipients.get(callback), 0);
-        mDeathRecipients.remove(callback);
+        IBinder binder = callback.asBinder();
+        if (!mTaskFpsCallbacks.containsKey(binder)) {
+            return;
+        }
 
-        nativeUnregister(mTaskFpsCallbacks.get(callback));
-        mTaskFpsCallbacks.remove(callback);
+        binder.unlinkToDeath(mDeathRecipients.get(binder), 0);
+        mDeathRecipients.remove(binder);
+
+        nativeUnregister(mTaskFpsCallbacks.get(binder));
+        mTaskFpsCallbacks.remove(binder);
     }
 
     private static native long nativeRegister(ITaskFpsCallback callback, int taskId);