PackageManager lock reduction: IntentResolver

Bug: 161323622

Address two comments on the IntentResolver: doCopy() is renamed to
copyFrom() and WatchableIntentResolver.java is moved to be a peer of
IntentResolver.java.

Test: atest
 * FrameworksServicesTests:UserSystemPackageInstallerTest
 * FrameworksServicesTests:PackageManagerSettingsTests
 * FrameworksServicesTests:PackageManagerServiceTest
 * FrameworksServicesTests:AppsFilterTest
 * FrameworksServicesTests:PackageInstallerSessionTest
 * FrameworksServicesTests:ScanTests
 * FrameworksServicesTests:WatcherTest

Change-Id: I0b17c3e8531e3e1324f9ca93516237297f810c1e
diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java
index ea1ac0c..2906cee 100644
--- a/services/core/java/com/android/server/IntentResolver.java
+++ b/services/core/java/com/android/server/IntentResolver.java
@@ -839,14 +839,22 @@
         }
     };
 
-    // Make <this> a copy of <orig>.  The presumption is that <this> is empty.
-    protected void doCopy(IntentResolver orig) {
+    // Make <this> a copy of <orig>.  The presumption is that <this> is empty but all
+    // arrays are cleared out explicitly, just to be sure.
+    protected void copyFrom(IntentResolver orig) {
+        mFilters.clear();
         mFilters.addAll(orig.mFilters);
+        mTypeToFilter.clear();
         mTypeToFilter.putAll(orig.mTypeToFilter);
+        mBaseTypeToFilter.clear();
         mBaseTypeToFilter.putAll(orig.mBaseTypeToFilter);
+        mWildTypeToFilter.clear();
         mWildTypeToFilter.putAll(orig.mWildTypeToFilter);
+        mSchemeToFilter.clear();
         mSchemeToFilter.putAll(orig.mSchemeToFilter);
+        mActionToFilter.clear();
         mActionToFilter.putAll(orig.mActionToFilter);
+        mTypedActionToFilter.clear();
         mTypedActionToFilter.putAll(orig.mTypedActionToFilter);
     }
 
diff --git a/services/core/java/com/android/server/utils/WatchableIntentResolver.java b/services/core/java/com/android/server/WatchableIntentResolver.java
similarity index 93%
rename from services/core/java/com/android/server/utils/WatchableIntentResolver.java
rename to services/core/java/com/android/server/WatchableIntentResolver.java
index 767fc07..3b5d168 100644
--- a/services/core/java/com/android/server/utils/WatchableIntentResolver.java
+++ b/services/core/java/com/android/server/WatchableIntentResolver.java
@@ -14,12 +14,14 @@
  * limitations under the License.
  */
 
-package com.android.server.utils;
+package com.android.server;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 
-import com.android.server.IntentResolver;
+import com.android.server.utils.Watchable;
+import com.android.server.utils.WatchableImpl;
+import com.android.server.utils.Watcher;
 
 import java.util.List;
 
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
index bf7f466..aae6ce4 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentResolver.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
+import com.android.server.WatchableIntentResolver;
 import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
 
 import java.util.List;
 
@@ -57,7 +57,7 @@
      */
     public CrossProfileIntentResolver snapshot() {
         CrossProfileIntentResolver result = new CrossProfileIntentResolver();
-        result.doCopy(this);
+        result.copyFrom(this);
         return result;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
index d0f9787..c1bfcac 100644
--- a/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PersistentPreferredIntentResolver.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
+import com.android.server.WatchableIntentResolver;
 import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
 
 public class PersistentPreferredIntentResolver
         extends WatchableIntentResolver<PersistentPreferredActivity, PersistentPreferredActivity>
@@ -47,7 +47,7 @@
      */
     public PersistentPreferredIntentResolver snapshot() {
         PersistentPreferredIntentResolver result = new PersistentPreferredIntentResolver();
-        result.doCopy(this);
+        result.copyFrom(this);
         return result;
     }
 }
diff --git a/services/core/java/com/android/server/pm/PreferredIntentResolver.java b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
index b62421e..0e3b85c 100644
--- a/services/core/java/com/android/server/pm/PreferredIntentResolver.java
+++ b/services/core/java/com/android/server/pm/PreferredIntentResolver.java
@@ -19,8 +19,8 @@
 import android.annotation.NonNull;
 import android.content.IntentFilter;
 
+import com.android.server.WatchableIntentResolver;
 import com.android.server.utils.Snappable;
-import com.android.server.utils.WatchableIntentResolver;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -76,7 +76,7 @@
      */
     public PreferredIntentResolver snapshot() {
         PreferredIntentResolver result = new PreferredIntentResolver();
-        result.doCopy(this);
+        result.copyFrom(this);
         return result;
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index 205548c..9a52643 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -209,7 +209,10 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
         verify(mFeatureConfigMock).onSystemReady();
     }
 
@@ -218,45 +221,60 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasicAndroid");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("add package");
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID);
+        watcher.verifyChangeReported("add package");
 
         assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
                 SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterAplication");
     }
-
     @Test
     public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception {
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         final Signature frameworkSignature = Mockito.mock(Signature.class);
         final PackageParser.SigningDetails frameworkSigningDetails =
                 new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1);
         final ParsingPackage android = pkg("android");
+        watcher.verifyNoChangeReported("prepare");
         android.addProtectedBroadcast("TEST_ACTION");
         simulateAddPackage(appsFilter, android, 1000,
                 b -> b.setSigningDetails(frameworkSigningDetails));
+        watcher.verifyChangeReported("addPackage");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         final int activityUid = DUMMY_TARGET_APPID;
         PackageSetting targetActivity = simulateAddPackage(appsFilter,
                 pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid);
+        watcher.verifyChangeReported("addPackage");
         final int receiverUid = DUMMY_TARGET_APPID + 1;
         PackageSetting targetReceiver = simulateAddPackage(appsFilter,
                 pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")),
                 receiverUid);
+        watcher.verifyChangeReported("addPackage");
         final int callingUid = DUMMY_CALLING_APPID;
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid);
+        watcher.verifyChangeReported("addPackage");
         final int wildcardUid = DUMMY_CALLING_APPID + 1;
         PackageSetting callingWildCard = simulateAddPackage(appsFilter,
                 pkg("com.calling.wildcard", new Intent("*")), wildcardUid);
+        watcher.verifyChangeReported("addPackage");
 
         assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity,
                 SYSTEM_USER));
@@ -267,6 +285,7 @@
                 wildcardUid, callingWildCard, targetActivity, SYSTEM_USER));
         assertTrue(appsFilter.shouldFilterApplication(
                 wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterApplication");
     }
 
     @Test
@@ -274,17 +293,24 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addPackage");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("addPackage");
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.authority"),
                 DUMMY_CALLING_APPID);
+        watcher.verifyChangeReported("addPackage");
 
         assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
                 SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterApplication");
     }
 
     @Test
@@ -292,17 +318,24 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addPackage");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter,
                 pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("addPackage");
         PackageSetting calling = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.some.other.package", "com.some.other.authority"),
                 DUMMY_CALLING_APPID);
+        watcher.verifyChangeReported("addPackage");
 
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
                 SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterApplication");
     }
 
     @Test
@@ -779,16 +812,23 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasicAndroid");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("add package");
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
                 DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, null, false));
+        watcher.verifyChangeReported("add package");
 
         assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
                 SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterAplication");
     }
 
     @Test
@@ -796,16 +836,23 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasicAndroid");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("add package");
         PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"),
                 DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, null, false));
+        watcher.verifyChangeReported("add package");
 
         assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target,
                 SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterAplication");
     }
 
     @Test
@@ -813,15 +860,20 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasicAndroid");
         appsFilter.onSystemReady();
-
+        watcher.verifyChangeReported("systemReady");
 
         PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 DUMMY_TARGET_APPID);
+        watcher.verifyChangeReported("add package");
         PackageSetting instrumentation = simulateAddPackage(appsFilter,
                 pkgWithInstrumentation("com.some.other.package", "com.some.package"),
                 DUMMY_CALLING_APPID);
+        watcher.verifyChangeReported("add package");
 
         assertFalse(
                 appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target,
@@ -829,6 +881,7 @@
         assertFalse(
                 appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation,
                         SYSTEM_USER));
+        watcher.verifyNoChangeReported("shouldFilterAplication");
     }
 
     @Test
@@ -836,8 +889,12 @@
         final AppsFilter appsFilter =
                 new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null,
                         mMockExecutor);
+        final WatchableTester watcher = new WatchableTester(appsFilter, "onChange");
+        watcher.register();
         simulateAddBasicAndroid(appsFilter);
+        watcher.verifyChangeReported("addBasicAndroid");
         appsFilter.onSystemReady();
+        watcher.verifyChangeReported("systemReady");
 
         final int systemAppId = Process.FIRST_APPLICATION_UID - 1;
         final int seesNothingAppId = Process.FIRST_APPLICATION_UID;
@@ -845,25 +902,34 @@
         final int queriesProviderAppId = Process.FIRST_APPLICATION_UID + 2;
 
         PackageSetting system = simulateAddPackage(appsFilter, pkg("some.system.pkg"), systemAppId);
+        watcher.verifyChangeReported("add package");
         PackageSetting seesNothing = simulateAddPackage(appsFilter, pkg("com.some.package"),
                 seesNothingAppId);
+        watcher.verifyChangeReported("add package");
         PackageSetting hasProvider = simulateAddPackage(appsFilter,
                 pkgWithProvider("com.some.other.package", "com.some.authority"), hasProviderAppId);
+        watcher.verifyChangeReported("add package");
         PackageSetting queriesProvider = simulateAddPackage(appsFilter,
                 pkgQueriesProvider("com.yet.some.other.package", "com.some.authority"),
                 queriesProviderAppId);
+        watcher.verifyChangeReported("add package");
 
         final SparseArray<int[]> systemFilter =
                 appsFilter.getVisibilityAllowList(system, USER_ARRAY, mExisting);
+        watcher.verifyNoChangeReported("getVisibility");
         assertThat(toList(systemFilter.get(SYSTEM_USER)),
                 contains(seesNothingAppId, hasProviderAppId, queriesProviderAppId));
+        watcher.verifyNoChangeReported("getVisibility");
 
         final SparseArray<int[]> seesNothingFilter =
                 appsFilter.getVisibilityAllowList(seesNothing, USER_ARRAY, mExisting);
+        watcher.verifyNoChangeReported("getVisibility");
         assertThat(toList(seesNothingFilter.get(SYSTEM_USER)),
                 contains(seesNothingAppId));
+        watcher.verifyNoChangeReported("getVisibility");
         assertThat(toList(seesNothingFilter.get(SECONDARY_USER)),
                 contains(seesNothingAppId));
+        watcher.verifyNoChangeReported("getVisibility");
 
         final SparseArray<int[]> hasProviderFilter =
                 appsFilter.getVisibilityAllowList(hasProvider, USER_ARRAY, mExisting);
@@ -872,17 +938,22 @@
 
         SparseArray<int[]> queriesProviderFilter =
                 appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+        watcher.verifyNoChangeReported("getVisibility");
         assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(queriesProviderAppId));
+        watcher.verifyNoChangeReported("getVisibility");
 
         // provider read
         appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+        watcher.verifyChangeReported("grantImplicitAccess");
 
         // ensure implicit access is included in the filter
         queriesProviderFilter =
                 appsFilter.getVisibilityAllowList(queriesProvider, USER_ARRAY, mExisting);
+        watcher.verifyNoChangeReported("getVisibility");
         assertThat(toList(queriesProviderFilter.get(SYSTEM_USER)),
                 contains(hasProviderAppId, queriesProviderAppId));
+        watcher.verifyNoChangeReported("getVisibility");
     }
 
     @Test