diff options
author | Ishneet Ahuja <ishneet@google.com> | 2023-10-05 11:21:58 +0000 |
---|---|---|
committer | Ishneet Ahuja <ishneet@google.com> | 2023-10-25 14:47:53 +0000 |
commit | 2e2ccb63df8dc600bbd266db46f1a50f4af66983 (patch) | |
tree | 8dc661e710c7d523e0d9f68e2566e4f53e97299e | |
parent | 884f642eef0047523421abbb188cea870a8919e4 (diff) | |
download | ContactsProvider-2e2ccb63df8dc600bbd266db46f1a50f4af66983.tar.gz |
CP2 handling of stopped state apps
This includes changes required for handling stopped state apps in
CP2.
Bug: 300253342
Test: atest ContactsProviderTests CtsContactsProviderTestCases, Manual
testing by following go/cp2-stopped-state-apps-testing
Change-Id: Iac8d186f9d442f8bfccf834fb52d407653622f38
8 files changed, 138 insertions, 20 deletions
@@ -18,6 +18,7 @@ android_app { "android-common", "com.android.vcard", "guava", + "android.content.pm.flags-aconfig-java", ], // The Jacoco tool analyzes code coverage when running unit tests on the diff --git a/src/com/android/providers/contacts/ContactDirectoryManager.java b/src/com/android/providers/contacts/ContactDirectoryManager.java index 09e3ff37..5dcf788c 100644 --- a/src/com/android/providers/contacts/ContactDirectoryManager.java +++ b/src/com/android/providers/contacts/ContactDirectoryManager.java @@ -19,6 +19,8 @@ package com.android.providers.contacts; import android.annotation.NonNull; import android.content.ContentValues; import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.Flags; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -39,6 +41,7 @@ import android.util.Log; import com.android.providers.contacts.ContactsDatabaseHelper.DbProperties; import com.android.providers.contacts.ContactsDatabaseHelper.DirectoryColumns; import com.android.providers.contacts.ContactsDatabaseHelper.Tables; + import com.google.android.collect.Lists; import com.google.android.collect.Sets; import com.google.common.annotations.VisibleForTesting; @@ -418,7 +421,8 @@ public class ContactDirectoryManager { * Scans the specified package for content directories and updates the {@link Directory} * table accordingly. */ - private List<DirectoryInfo> updateDirectoriesForPackage( + @VisibleForTesting + List<DirectoryInfo> updateDirectoriesForPackage( PackageInfo packageInfo, boolean initialScan) { if (DEBUG) { Log.d(TAG, "updateDirectoriesForPackage packageName=" + packageInfo.packageName @@ -427,6 +431,15 @@ public class ContactDirectoryManager { ArrayList<DirectoryInfo> directories = Lists.newArrayList(); + if (Flags.stayStopped() + && (packageInfo.applicationInfo != null + && ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0))) { + if (DEBUG) { + Log.d(TAG, "Package " + packageInfo.packageName + " is in stopped state"); + } + return null; + } + ProviderInfo[] providers = packageInfo.providers; if (providers != null) { for (ProviderInfo provider : providers) { diff --git a/src/com/android/providers/contacts/ContactsPackageMonitor.java b/src/com/android/providers/contacts/ContactsPackageMonitor.java index 06565cd9..93c7df90 100644 --- a/src/com/android/providers/contacts/ContactsPackageMonitor.java +++ b/src/com/android/providers/contacts/ContactsPackageMonitor.java @@ -95,6 +95,7 @@ public class ContactsPackageMonitor { private void registerReceiver() { final IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_UNSTOPPED); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addAction(Intent.ACTION_PACKAGE_REPLACED); diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java index 25264598..7662b32b 100644 --- a/src/com/android/providers/contacts/ContactsProvider2.java +++ b/src/com/android/providers/contacts/ContactsProvider2.java @@ -46,6 +46,7 @@ import android.content.OperationApplicationException; import android.content.SharedPreferences; import android.content.SyncAdapterType; import android.content.UriMatcher; +import android.content.pm.Flags; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ProviderInfo; @@ -175,7 +176,6 @@ import com.android.providers.contacts.aggregation.AbstractContactAggregator.Aggr import com.android.providers.contacts.aggregation.ContactAggregator; import com.android.providers.contacts.aggregation.ContactAggregator2; import com.android.providers.contacts.aggregation.ProfileAggregator; -import com.android.providers.contacts.aggregation.util.CommonNicknameCache; import com.android.providers.contacts.database.ContactsTableUtil; import com.android.providers.contacts.database.DeletedContactsTableUtil; import com.android.providers.contacts.database.MoreDatabaseUtils; @@ -187,13 +187,10 @@ import com.android.providers.contacts.util.DbQueryUtils; import com.android.providers.contacts.util.LogFields; import com.android.providers.contacts.util.LogUtils; import com.android.providers.contacts.util.NeededForTesting; -import com.android.providers.contacts.util.PhoneAccountHandleMigrationUtils; import com.android.providers.contacts.util.UserUtils; import com.android.vcard.VCardComposer; import com.android.vcard.VCardConfig; -import libcore.io.IoUtils; - import com.google.android.collect.Lists; import com.google.android.collect.Maps; import com.google.android.collect.Sets; @@ -201,6 +198,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import com.google.common.primitives.Ints; +import libcore.io.IoUtils; + import java.io.BufferedWriter; import java.io.ByteArrayOutputStream; import java.io.File; @@ -5937,6 +5936,22 @@ public class ContactsProvider2 extends AbstractContactsProvider return null; } + if (projection == null) { + projection = getDefaultProjection(uri); + } + + // Handle directories in stopped state + try { + if (Flags.stayStopped() + && getContext().getPackageManager() + .isPackageStopped(directoryInfo.packageName)) { + return new MatrixCursor(projection, 0); + } + } catch (NameNotFoundException e) { + Log.w(TAG, "Package name " + directoryInfo.packageName + " not found"); + } + + Builder builder = new Uri.Builder(); builder.scheme(ContentResolver.SCHEME_CONTENT); builder.authority(directoryInfo.authority); @@ -5960,9 +5975,6 @@ public class ContactsProvider2 extends AbstractContactsProvider Uri directoryUri = builder.build(); - if (projection == null) { - projection = getDefaultProjection(uri); - } int galUid = -1; try { galUid = getContext().getPackageManager().getPackageUid(directoryInfo.packageName, diff --git a/tests/Android.bp b/tests/Android.bp index beb2d313..06d19540 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -9,6 +9,8 @@ android_test { "ContactsProviderTestUtils", "androidx.test.rules", "mockito-target-minus-junit4", + "flag-junit", + "android.content.pm.flags-aconfig-java", ], libs: [ "android.test.runner", diff --git a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java index e8920530..9f433987 100644 --- a/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java +++ b/tests/src/com/android/providers/contacts/BaseContactsProvider2Test.java @@ -55,11 +55,13 @@ import android.provider.ContactsContract.RawContacts; import android.provider.ContactsContract.Settings; import android.provider.ContactsContract.StatusUpdates; import android.provider.ContactsContract.StreamItems; -import android.provider.VoicemailContract; import android.telephony.SubscriptionManager; import android.test.MoreAsserts; import android.test.mock.MockContentResolver; import android.util.Log; + +import androidx.test.platform.app.InstrumentationRegistry; + import com.android.providers.contacts.ContactsDatabaseHelper.AccountsColumns; import com.android.providers.contacts.ContactsDatabaseHelper.Tables; import com.android.providers.contacts.testutil.CommonDatabaseUtils; @@ -68,23 +70,23 @@ import com.android.providers.contacts.testutil.RawContactUtil; import com.android.providers.contacts.testutil.TestUtil; import com.android.providers.contacts.util.Hex; import com.android.providers.contacts.util.MockClock; + import com.google.android.collect.Sets; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; - /** * A common superclass for {@link ContactsProvider2}-related tests. */ @@ -103,6 +105,7 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { static final String WRITE_VOICEMAIL_PERMISSION = "com.android.voicemail.permission.WRITE_VOICEMAIL"; + protected Context mContext; protected static final String PACKAGE = "ContactsProvider2Test"; public static final String READ_ONLY_ACCOUNT_TYPE = SynchronousContactsProvider2.READ_ONLY_ACCOUNT_TYPE; @@ -136,9 +139,11 @@ public abstract class BaseContactsProvider2Test extends PhotoLoadingTestCase { @Override protected void setUp() throws Exception { super.setUp(); + mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + MockitoAnnotations.initMocks(this); - mTestContext = new ContextWithServiceOverrides(getContext()); + mTestContext = new ContextWithServiceOverrides(mContext); mTestContext.injectSystemService(SubscriptionManager.class, mSubscriptionManager); mActor = new ContactsActor( diff --git a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java index a4165ce5..e2434960 100644 --- a/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java +++ b/tests/src/com/android/providers/contacts/ContactDirectoryManagerTest.java @@ -16,9 +16,12 @@ package com.android.providers.contacts; +import static android.content.pm.Flags.FLAG_STAY_STOPPED; + import android.accounts.Account; import android.content.ContentValues; import android.content.Context; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; @@ -27,21 +30,29 @@ import android.database.Cursor; import android.database.MatrixCursor; import android.net.Uri; import android.os.Bundle; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.ContactsContract; import android.provider.ContactsContract.AggregationExceptions; import android.provider.ContactsContract.Contacts; import android.provider.ContactsContract.Directory; import android.provider.ContactsContract.RawContacts; import android.test.mock.MockContentProvider; -import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; import com.android.providers.contacts.ContactsDatabaseHelper.AggregationExceptionColumns; import com.google.android.collect.Lists; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.util.Arrays; import java.util.Set; @@ -52,8 +63,11 @@ import java.util.Set; -w com.android.providers.contacts.tests/android.test.InstrumentationTestRunner * */ -@MediumTest +@RunWith(AndroidJUnit4.class) public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); private static final String TAG = "ContactDirectoryManagerTest"; private ContactsMockPackageManager mPackageManager; @@ -114,8 +128,10 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { } } + @Before @Override public void setUp() throws Exception { + super.setUp(); mProvider = (ContactsProvider2) getProvider(); @@ -129,9 +145,10 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { protected String getContextPackageName() { // In this test, we need to use the real package name, because that'll be recorded in the // directory table, and if it's wrong, the tests would get confused. - return getContext().getPackageName(); + return mContext.getPackageName(); } + @Test public void testIsDirectoryProvider() { ProviderInfo provider = new ProviderInfo(); @@ -158,6 +175,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { assertTrue(ContactDirectoryManager.isDirectoryProvider(provider)); } + @Test public void testScanAllProviders() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -209,13 +227,13 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); assertTrue(cursor.moveToPosition(3)); - assertDirectoryRow(cursor, getContext().getPackageName(), + assertDirectoryRow(cursor, mContext.getPackageName(), "com.android.contacts", null, null, null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); assertTrue(cursor.moveToPosition(4)); - assertDirectoryRow(cursor, getContext().getPackageName(), + assertDirectoryRow(cursor, mContext.getPackageName(), "com.android.contacts", null, null, null, -1 /* =any */, Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_FULL, Directory.PHOTO_SUPPORT_FULL); @@ -223,6 +241,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testScanAllProviders_scanCondition() throws Exception { testScanAllProviders(); @@ -254,6 +273,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { } + @Test public void testPackageInstalled() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -305,6 +325,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testPackageUninstalled() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -351,6 +372,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testPackageReplaced() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -409,6 +431,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { * Tests if the manager works correctly when the package name for a directory is changed * (on system update). */ + @Test public void testPackageRenamed() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -472,6 +495,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testAccountRemoval() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList( @@ -513,6 +537,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testNotifyDirectoryChange() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -547,6 +572,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testForwardingToDirectoryProvider() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -587,6 +613,7 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { cursor.close(); } + @Test public void testProjectionPopulated() throws Exception { mPackageManager.setInstalledPackages( Lists.newArrayList(createProviderPackage("test.package1", "authority1"), @@ -625,8 +652,9 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { * Test {@link ContactDirectoryManager#getDirectoryProviderPackages} with the actual * package manager, and see if it returns the google sync package. */ + @Test public void testGetDirectoryProviderPackages() { - final PackageManager pm = getContext().getPackageManager(); + final PackageManager pm = mContext.getPackageManager(); final String googleSync = "com.google.android.gms"; // Skip if the package is not installed. @@ -650,6 +678,55 @@ public class ContactDirectoryManagerTest extends BaseContactsProvider2Test { dirProviderPackages.contains(googleSync)); } + @Test + public void testUpdateDirectoriesForUnstoppedPackage() throws Exception { + mPackageManager.setInstalledPackages( + Lists.newArrayList(createProviderPackage("test.package1", "authority1"))); + + MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority1"); + MatrixCursor response1 = provider1.createResponseCursor(); + addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, + Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + PackageInfo packageInfo = mPackageManager.getPackageInfo("test.package1", + PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageInfo.packageName; + packageInfo.applicationInfo = applicationInfo; + // Package is not in stopped state + packageInfo.applicationInfo.flags = 0; + + assertEquals(mDirectoryManager.updateDirectoriesForPackage(packageInfo, true).size(), 1); + } + + @Test + @RequiresFlagsEnabled(FLAG_STAY_STOPPED) + public void testUpdateDirectoriesForStoppedPackage() throws Exception { + mPackageManager.setInstalledPackages( + Lists.newArrayList(createProviderPackage("test.package1", "authority1"))); + + MockContactDirectoryProvider provider1 = (MockContactDirectoryProvider) addProvider( + MockContactDirectoryProvider.class, "authority1"); + MatrixCursor response1 = provider1.createResponseCursor(); + addDirectoryRow(response1, "account-name1", "account-type1", "display-name1", 1, + Directory.EXPORT_SUPPORT_NONE, Directory.SHORTCUT_SUPPORT_NONE, + Directory.PHOTO_SUPPORT_NONE); + + PackageInfo packageInfo = mPackageManager.getPackageInfo("test.package1", + PackageManager.GET_PROVIDERS | PackageManager.GET_META_DATA); + + ApplicationInfo applicationInfo = new ApplicationInfo(); + applicationInfo.packageName = packageInfo.packageName; + packageInfo.applicationInfo = applicationInfo; + // Put the package in stopped state: set associated app flags to true + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED; + + assertNull(mDirectoryManager.updateDirectoriesForPackage(packageInfo, true)); + } + protected PackageInfo createProviderPackage(String packageName, String authority) { return createPackage(packageName, authority, true); } diff --git a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java index 62f17eab..b96d6d52 100644 --- a/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java +++ b/tests/src/com/android/providers/contacts/ContactsMockPackageManager.java @@ -161,4 +161,11 @@ public class ContactsMockPackageManager extends MockPackageManager { public int getPackageUid(String packageName, int flags) throws NameNotFoundException { return 123; } + + @Override + public boolean isPackageStopped(String packageName) throws NameNotFoundException { + PackageInfo packageInfo = getPackageInfo(packageName, 0); + return packageInfo.applicationInfo != null + && ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0); + } } |