diff options
6 files changed, 103 insertions, 10 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index eb529bebe617..51033191d993 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -2298,6 +2298,7 @@ package android.content.pm { field public static final int MATCH_ANY_USER = 4194304; // 0x400000 field public static final int MATCH_FACTORY_ONLY = 2097152; // 0x200000 field public static final int MATCH_INSTANT = 8388608; // 0x800000 + field public static final int MODULE_APEX_NAME = 1; // 0x1 field public static final int RESTRICTION_HIDE_FROM_SUGGESTIONS = 1; // 0x1 field public static final int RESTRICTION_HIDE_NOTIFICATIONS = 2; // 0x2 field public static final int RESTRICTION_NONE = 0; // 0x0 diff --git a/core/java/android/content/pm/ModuleInfo.java b/core/java/android/content/pm/ModuleInfo.java index d930c92d66ed..a6db662bcc43 100644 --- a/core/java/android/content/pm/ModuleInfo.java +++ b/core/java/android/content/pm/ModuleInfo.java @@ -37,6 +37,12 @@ public final class ModuleInfo implements Parcelable { /** The package name of this module. */ private String mPackageName; + /** + * The name of the APEX this module is distributed as, or null if it is not distributed via + * APEX. + */ + @Nullable private String mApexModuleName; + /** Whether or not this module is hidden from the user. */ private boolean mHidden; @@ -54,6 +60,7 @@ public final class ModuleInfo implements Parcelable { mName = orig.mName; mPackageName = orig.mPackageName; mHidden = orig.mHidden; + mApexModuleName = orig.mApexModuleName; } /** @hide Sets the public name of this module. */ @@ -89,6 +96,17 @@ public final class ModuleInfo implements Parcelable { return mHidden; } + /** @hide Sets the apex module name. */ + public ModuleInfo setApexModuleName(@Nullable String apexModuleName) { + mApexModuleName = apexModuleName; + return this; + } + + /** @hide Gets the apex module name. */ + public @Nullable String getApexModuleName() { + return mApexModuleName; + } + /** Returns a string representation of this object. */ public String toString() { return "ModuleInfo{" @@ -106,6 +124,7 @@ public final class ModuleInfo implements Parcelable { int hashCode = 0; hashCode = 31 * hashCode + Objects.hashCode(mName); hashCode = 31 * hashCode + Objects.hashCode(mPackageName); + hashCode = 31 * hashCode + Objects.hashCode(mApexModuleName); hashCode = 31 * hashCode + Boolean.hashCode(mHidden); return hashCode; } @@ -118,6 +137,7 @@ public final class ModuleInfo implements Parcelable { final ModuleInfo other = (ModuleInfo) obj; return Objects.equals(mName, other.mName) && Objects.equals(mPackageName, other.mPackageName) + && Objects.equals(mApexModuleName, other.mApexModuleName) && mHidden == other.mHidden; } @@ -126,12 +146,14 @@ public final class ModuleInfo implements Parcelable { dest.writeCharSequence(mName); dest.writeString(mPackageName); dest.writeBoolean(mHidden); + dest.writeString(mApexModuleName); } private ModuleInfo(Parcel source) { mName = source.readCharSequence(); mPackageName = source.readString(); mHidden = source.readBoolean(); + mApexModuleName = source.readString(); } public static final @android.annotation.NonNull Parcelable.Creator<ModuleInfo> CREATOR = diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 6694335f264c..3c083023f68d 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -230,7 +230,7 @@ public abstract class PackageManager { MATCH_ALL, }) @Retention(RetentionPolicy.SOURCE) - public @interface ModuleInfoFlags {} + public @interface InstalledModulesFlags {} /** @hide */ @IntDef(flag = true, prefix = { "GET_", "MATCH_" }, value = { @@ -582,6 +582,22 @@ public abstract class PackageManager { public static final int ONLY_IF_NO_MATCH_FOUND = 0x00000004; /** @hide */ + @IntDef(flag = true, prefix = { "MODULE_" }, value = { + MODULE_APEX_NAME, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ModuleInfoFlags {} + + /** + * Flag for {@link #getModuleInfo}: allow ModuleInfo to be retrieved using the apex module + * name, rather than the package name. + * + * @hide + */ + @SystemApi + public static final int MODULE_APEX_NAME = 0x00000001; + + /** @hide */ @IntDef(prefix = { "PERMISSION_" }, value = { PERMISSION_GRANTED, PERMISSION_DENIED @@ -3929,7 +3945,7 @@ public abstract class PackageManager { * there are no installed modules, an empty list is returned. */ @NonNull - public List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) { + public List<ModuleInfo> getInstalledModules(@InstalledModulesFlags int flags) { throw new UnsupportedOperationException( "getInstalledModules not implemented in subclass"); } diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java index 28079099469a..c6d2b334bd71 100644 --- a/services/core/java/com/android/server/pm/ApexManager.java +++ b/services/core/java/com/android/server/pm/ApexManager.java @@ -66,7 +66,7 @@ import java.util.stream.Collectors; * ApexManager class handles communications with the apex service to perform operation and queries, * as well as providing caching to avoid unnecessary calls to the service. */ -abstract class ApexManager { +public abstract class ApexManager { private static final String TAG = "ApexManager"; @@ -265,6 +265,13 @@ abstract class ApexManager { abstract List<String> getApksInApex(String apexPackageName); /** + * Returns the apex module name for the given package name, if the package is an APEX. Otherwise + * returns {@code null}. + */ + @Nullable + public abstract String getApexModuleNameForPackageName(String apexPackageName); + + /** * Dumps various state information to the provided {@link PrintWriter} object. * * @param pw the {@link PrintWriter} object to send information to. @@ -646,6 +653,15 @@ abstract class ApexManager { } } + @Override + @Nullable + public String getApexModuleNameForPackageName(String apexPackageName) { + populatePackageNameToApexModuleNameIfNeeded(); + synchronized (mLock) { + return mPackageNameToApexModuleName.get(apexPackageName); + } + } + /** * Dump information about the packages contained in a particular cache * @param packagesCache the cache to print information about. @@ -843,6 +859,12 @@ abstract class ApexManager { } @Override + @Nullable + public String getApexModuleNameForPackageName(String apexPackageName) { + return null; + } + + @Override void dump(PrintWriter pw, String packageName) { // No-op } diff --git a/services/core/java/com/android/server/pm/ModuleInfoProvider.java b/services/core/java/com/android/server/pm/ModuleInfoProvider.java index 69510d9e5565..06706cd06e11 100644 --- a/services/core/java/com/android/server/pm/ModuleInfoProvider.java +++ b/services/core/java/com/android/server/pm/ModuleInfoProvider.java @@ -57,9 +57,9 @@ public class ModuleInfoProvider { */ private static final String MODULE_METADATA_KEY = "android.content.pm.MODULE_METADATA"; - private final Context mContext; private final IPackageManager mPackageManager; + private final ApexManager mApexManager; private final Map<String, ModuleInfo> mModuleInfo; // TODO: Move this to an earlier boot phase if anybody requires it then. @@ -69,13 +69,16 @@ public class ModuleInfoProvider { ModuleInfoProvider(Context context, IPackageManager packageManager) { mContext = context; mPackageManager = packageManager; + mApexManager = ApexManager.getInstance(); mModuleInfo = new ArrayMap<>(); } @VisibleForTesting - public ModuleInfoProvider(XmlResourceParser metadata, Resources resources) { + public ModuleInfoProvider( + XmlResourceParser metadata, Resources resources, ApexManager apexManager) { mContext = null; mPackageManager = null; + mApexManager = apexManager; mModuleInfo = new ArrayMap<>(); loadModuleMetadata(metadata, resources); } @@ -150,6 +153,8 @@ public class ModuleInfoProvider { mi.setHidden(isHidden); mi.setPackageName(modulePackageName); mi.setName(moduleName); + mi.setApexModuleName( + mApexManager.getApexModuleNameForPackageName(modulePackageName)); mModuleInfo.put(modulePackageName, mi); } @@ -167,7 +172,7 @@ public class ModuleInfoProvider { * * @param flags Use {@link PackageManager#MATCH_ALL} flag to get all modules. */ - List<ModuleInfo> getInstalledModules(@PackageManager.ModuleInfoFlags int flags) { + List<ModuleInfo> getInstalledModules(@PackageManager.InstalledModulesFlags int flags) { if (!mMetadataLoaded) { throw new IllegalStateException("Call to getInstalledModules before metadata loaded"); } @@ -195,12 +200,19 @@ public class ModuleInfoProvider { return installedModules; } - ModuleInfo getModuleInfo(String packageName, int flags) { + ModuleInfo getModuleInfo(String name, @PackageManager.ModuleInfoFlags int flags) { if (!mMetadataLoaded) { throw new IllegalStateException("Call to getModuleInfo before metadata loaded"); } - - return mModuleInfo.get(packageName); + if ((flags & PackageManager.MODULE_APEX_NAME) != 0) { + for (ModuleInfo moduleInfo : mModuleInfo.values()) { + if (name.equals(moduleInfo.getApexModuleName())) { + return moduleInfo; + } + } + return null; + } + return mModuleInfo.get(name); } String getPackageName() { diff --git a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java index 3852b9fec001..6a9ef8a2b7bd 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/ModuleInfoProviderTest.java @@ -15,6 +15,9 @@ */ package com.android.server.pm; +import static org.mockito.Mockito.when; +import static org.mockito.MockitoAnnotations.initMocks; + import android.content.Context; import android.content.pm.ModuleInfo; import android.content.pm.PackageManager; @@ -22,11 +25,25 @@ import android.test.InstrumentationTestCase; import com.android.frameworks.servicestests.R; +import org.mockito.Mock; + import java.util.Collections; import java.util.List; public class ModuleInfoProviderTest extends InstrumentationTestCase { + + @Mock private ApexManager mApexManager; + + public void setUp() { + initMocks(this); + } + public void testSuccessfulParse() { + when(mApexManager.getApexModuleNameForPackageName("com.android.module1")) + .thenReturn("com.module1.apex"); + when(mApexManager.getApexModuleNameForPackageName("com.android.module2")) + .thenReturn("com.module2.apex"); + ModuleInfoProvider provider = getProvider(R.xml.well_formed_metadata); List<ModuleInfo> mi = provider.getInstalledModules(PackageManager.MATCH_ALL); @@ -40,11 +57,13 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { ModuleInfo mi1 = provider.getModuleInfo("com.android.module1", 0); assertEquals("com.android.module1", mi1.getPackageName()); assertEquals("module_1_name", mi1.getName()); + assertEquals("com.module1.apex", mi1.getApexModuleName()); assertEquals(false, mi1.isHidden()); ModuleInfo mi2 = provider.getModuleInfo("com.android.module2", 0); assertEquals("com.android.module2", mi2.getPackageName()); assertEquals("module_2_name", mi2.getName()); + assertEquals("com.module2.apex", mi2.getApexModuleName()); assertEquals(true, mi2.isHidden()); } @@ -75,6 +94,7 @@ public class ModuleInfoProviderTest extends InstrumentationTestCase { */ private ModuleInfoProvider getProvider(int resourceId) { final Context ctx = getInstrumentation().getContext(); - return new ModuleInfoProvider(ctx.getResources().getXml(resourceId), ctx.getResources()); + return new ModuleInfoProvider( + ctx.getResources().getXml(resourceId), ctx.getResources(), mApexManager); } } |