From d066c7c93383693dcf2225db66d78b598a725d84 Mon Sep 17 00:00:00 2001 From: Hai Zhang Date: Fri, 15 Jan 2021 14:35:10 -0800 Subject: [PATCH] Move computePackageStateHash() implementation into platform. The computePackageStateHash() implementation needs PackageManagerInternal.forEachInstalledPackage(), getApplicationEnabledState(), getEnabledComponents() and getDisabledComponents() to work, for which we don't have good alternatives in API. Even if we added those APIs, generating and iterating over PackageInfo for all packages in the system would surely drive up CPU and memory usage and regress our performance, and the new AndroidPackage system APIs isn't ready in S yet. So we can move computePackageStateHash() implementation into platform. Once we move role logic into system server, granting default roles may be fast enough and we may consider the deprecation/removal of this. This way we can also remove the final dependency we have on PackageManagerInternal and be ready for modularization. Bug: 158736025 Test: presubmit Change-Id: I14119f2e95c861ee3539108748a4912b051b4462 --- ...ava => RoleServicePlatformHelperImpl.java} | 55 ++++++++++++++++-- .../server/role/RoleManagerService.java | 58 ++----------------- ...er.java => RoleServicePlatformHelper.java} | 19 ++++-- .../android/server/role/RoleUserState.java | 12 ++-- .../java/com/android/server/SystemServer.java | 4 +- 5 files changed, 77 insertions(+), 71 deletions(-) rename services/core/java/com/android/server/policy/role/{LegacyRoleStateProviderImpl.java => RoleServicePlatformHelperImpl.java} (80%) rename services/core/java/com/android/server/role/{LegacyRoleStateProvider.java => RoleServicePlatformHelper.java} (68%) diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java similarity index 80% rename from services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java rename to services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java index 097f332a2637e..c2596c74146a1 100644 --- a/services/core/java/com/android/server/policy/role/LegacyRoleStateProviderImpl.java +++ b/services/core/java/com/android/server/policy/role/RoleServicePlatformHelperImpl.java @@ -27,22 +27,27 @@ import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; +import android.content.pm.Signature; import android.os.Environment; import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; +import android.util.PackageUtils; import android.util.Slog; import android.util.Xml; import com.android.internal.R; +import com.android.internal.util.CollectionUtils; import com.android.server.LocalServices; -import com.android.server.role.LegacyRoleStateProvider; +import com.android.server.role.RoleServicePlatformHelper; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -53,10 +58,10 @@ import java.util.Objects; import java.util.Set; /** - * Implementation to provide legacy role state. + * Implementation of {@link RoleServicePlatformHelper}. */ -public class LegacyRoleStateProviderImpl implements LegacyRoleStateProvider { - private static final String LOG_TAG = "LegacyRoleState"; +public class RoleServicePlatformHelperImpl implements RoleServicePlatformHelper { + private static final String LOG_TAG = RoleServicePlatformHelperImpl.class.getSimpleName(); private static final String ROLES_FILE_NAME = "roles.xml"; @@ -68,7 +73,7 @@ public class LegacyRoleStateProviderImpl implements LegacyRoleStateProvider { @NonNull private final Context mContext; - public LegacyRoleStateProviderImpl(@NonNull Context context) { + public RoleServicePlatformHelperImpl(@NonNull Context context) { mContext = context; } @@ -288,4 +293,44 @@ public class LegacyRoleStateProviderImpl implements LegacyRoleStateProvider { } return Objects.equals(packageName, resolveInfo.activityInfo.packageName); } + + @NonNull + @Override + public String computePackageStateHash(@UserIdInt int userId) { + PackageManagerInternal packageManagerInternal = LocalServices.getService( + PackageManagerInternal.class); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); + packageManagerInternal.forEachInstalledPackage(pkg -> { + try { + dataOutputStream.writeUTF(pkg.getPackageName()); + dataOutputStream.writeLong(pkg.getLongVersionCode()); + dataOutputStream.writeInt(packageManagerInternal.getApplicationEnabledState( + pkg.getPackageName(), userId)); + + final ArraySet enabledComponents = + packageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId); + final int enabledComponentsSize = CollectionUtils.size(enabledComponents); + dataOutputStream.writeInt(enabledComponentsSize); + for (int i = 0; i < enabledComponentsSize; i++) { + dataOutputStream.writeUTF(enabledComponents.valueAt(i)); + } + + final ArraySet disabledComponents = + packageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId); + final int disabledComponentsSize = CollectionUtils.size(disabledComponents); + for (int i = 0; i < disabledComponentsSize; i++) { + dataOutputStream.writeUTF(disabledComponents.valueAt(i)); + } + + for (final Signature signature : pkg.getSigningDetails().signatures) { + dataOutputStream.write(signature.toByteArray()); + } + } catch (IOException e) { + // Never happens for ByteArrayOutputStream and DataOutputStream. + throw new AssertionError(e); + } + }, userId); + return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray()); + } } diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java index bc5ddd3aae953..0fff996c9d6f1 100644 --- a/services/core/java/com/android/server/role/RoleManagerService.java +++ b/services/core/java/com/android/server/role/RoleManagerService.java @@ -33,8 +33,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; -import android.content.pm.PackageManagerInternal; -import android.content.pm.Signature; import android.os.Binder; import android.os.Handler; import android.os.ParcelFileDescriptor; @@ -48,7 +46,6 @@ import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.IndentingPrintWriter; -import android.util.PackageUtils; import android.util.Slog; import android.util.SparseArray; import android.util.proto.ProtoOutputStream; @@ -66,11 +63,8 @@ import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.UserManagerInternal; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; -import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; @@ -95,15 +89,13 @@ public class RoleManagerService extends SystemService implements RoleUserState.C @NonNull private final AppOpsManager mAppOpsManager; @NonNull - private final PackageManagerInternal mPackageManagerInternal; - @NonNull private final UserManagerInternal mUserManagerInternal; @NonNull private final Object mLock = new Object(); @NonNull - private final LegacyRoleStateProvider mLegacyRoleStateProvider; + private final RoleServicePlatformHelper mPlatformHelper; /** * Maps user id to its state. @@ -139,15 +131,14 @@ public class RoleManagerService extends SystemService implements RoleUserState.C new SparseArray<>(); public RoleManagerService(@NonNull Context context, - @NonNull LegacyRoleStateProvider legacyRoleStateProvider) { + @NonNull RoleServicePlatformHelper platformHelper) { super(context); - mLegacyRoleStateProvider = legacyRoleStateProvider; + mPlatformHelper = platformHelper; RoleControllerManager.initializeRemoteServiceComponentName(context); mAppOpsManager = context.getSystemService(AppOpsManager.class); - mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); LocalServices.addService(RoleManagerInternal.class, new Internal()); @@ -232,7 +223,7 @@ public class RoleManagerService extends SystemService implements RoleUserState.C private AndroidFuture maybeGrantDefaultRolesInternal(@UserIdInt int userId) { RoleUserState userState = getOrCreateUserState(userId); String oldPackagesHash = userState.getPackagesHash(); - String newPackagesHash = computePackageStateHash(userId); + String newPackagesHash = mPlatformHelper.computePackageStateHash(userId); if (Objects.equals(oldPackagesHash, newPackagesHash)) { if (DEBUG) { Slog.i(LOG_TAG, "Already granted default roles for packages hash " @@ -256,51 +247,12 @@ public class RoleManagerService extends SystemService implements RoleUserState.C return future; } - @Nullable - private String computePackageStateHash(@UserIdInt int userId) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream); - - mPackageManagerInternal.forEachInstalledPackage(pkg -> { - try { - dataOutputStream.writeUTF(pkg.getPackageName()); - dataOutputStream.writeLong(pkg.getLongVersionCode()); - dataOutputStream.writeInt(mPackageManagerInternal.getApplicationEnabledState( - pkg.getPackageName(), userId)); - - ArraySet enabledComponents = - mPackageManagerInternal.getEnabledComponents(pkg.getPackageName(), userId); - int numComponents = CollectionUtils.size(enabledComponents); - dataOutputStream.writeInt(numComponents); - for (int i = 0; i < numComponents; i++) { - dataOutputStream.writeUTF(enabledComponents.valueAt(i)); - } - - ArraySet disabledComponents = - mPackageManagerInternal.getDisabledComponents(pkg.getPackageName(), userId); - numComponents = CollectionUtils.size(disabledComponents); - for (int i = 0; i < numComponents; i++) { - dataOutputStream.writeUTF(disabledComponents.valueAt(i)); - } - - for (Signature signature : pkg.getSigningDetails().signatures) { - dataOutputStream.write(signature.toByteArray()); - } - } catch (IOException e) { - // Never happens for ByteArrayOutputStream and DataOutputStream. - throw new AssertionError(e); - } - }, userId); - - return PackageUtils.computeSha256Digest(byteArrayOutputStream.toByteArray()); - } - @NonNull private RoleUserState getOrCreateUserState(@UserIdInt int userId) { synchronized (mLock) { RoleUserState userState = mUserStates.get(userId); if (userState == null) { - userState = new RoleUserState(userId, mLegacyRoleStateProvider, this); + userState = new RoleUserState(userId, mPlatformHelper, this); mUserStates.put(userId, userState); } return userState; diff --git a/services/core/java/com/android/server/role/LegacyRoleStateProvider.java b/services/core/java/com/android/server/role/RoleServicePlatformHelper.java similarity index 68% rename from services/core/java/com/android/server/role/LegacyRoleStateProvider.java rename to services/core/java/com/android/server/role/RoleServicePlatformHelper.java index ec4cfc176a8d7..d804d130fc6b8 100644 --- a/services/core/java/com/android/server/role/LegacyRoleStateProvider.java +++ b/services/core/java/com/android/server/role/RoleServicePlatformHelper.java @@ -23,21 +23,30 @@ import java.util.Map; import java.util.Set; /** - * Provider for legacy role state. - *

- * The role state may come from two sources, either the different pre-role default app settings, or - * the pre-modularization roles.xml file stored in platform. + * Helper inside the platform for role service. * * @hide */ //@SystemApi(client = SystemApi.Client.SYSTEM_SERVER) -public interface LegacyRoleStateProvider { +public interface RoleServicePlatformHelper { /** * Get the legacy role state stored in the platform. + *

+ * The role state may come from two sources, either the different pre-role default app settings, + * or the pre-modularization roles.xml file stored in platform. * * @param userId the user ID * @return a mapping of role name to its set of holders */ @NonNull Map> getLegacyRoleState(@UserIdInt int userId); + + /** + * Compute a hash for the current package state in the system. + * + * @param userId the user ID + * @return the computed hash + */ + @NonNull + String computePackageStateHash(@UserIdInt int userId); } diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index f5a79eabaf5ae..838fd9046c156 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -57,7 +57,7 @@ class RoleUserState { private final int mUserId; @NonNull - private final LegacyRoleStateProvider mLegacyStateProvider; + private final RoleServicePlatformHelper mPlatformHelper; @NonNull private final Callback mCallback; @@ -92,13 +92,13 @@ class RoleUserState { * Create a new user state, and read its state from disk if previously persisted. * * @param userId the user id for this user state - * @param legacyStateProvider the provider for legacy role state + * @param platformHelper the platform helper * @param callback the callback for this user state */ - public RoleUserState(@UserIdInt int userId, - @NonNull LegacyRoleStateProvider legacyStateProvider, @NonNull Callback callback) { + public RoleUserState(@UserIdInt int userId, @NonNull RoleServicePlatformHelper platformHelper, + @NonNull Callback callback) { mUserId = userId; - mLegacyStateProvider = legacyStateProvider; + mPlatformHelper = platformHelper; mCallback = callback; readFile(); @@ -363,7 +363,7 @@ class RoleUserState { mPackagesHash = roleState.getPackagesHash(); roles = roleState.getRoles(); } else { - roles = mLegacyStateProvider.getLegacyRoleState(mUserId); + roles = mPlatformHelper.getLegacyRoleState(mUserId); } mRoles.clear(); for (Map.Entry> entry : roles.entrySet()) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index c613dfb22c777..f81ec7802f12e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -160,7 +160,7 @@ import com.android.server.pm.UserManagerService; import com.android.server.pm.dex.SystemServerDexLoadReporter; import com.android.server.policy.PermissionPolicyService; import com.android.server.policy.PhoneWindowManager; -import com.android.server.policy.role.LegacyRoleStateProviderImpl; +import com.android.server.policy.role.RoleServicePlatformHelperImpl; import com.android.server.power.PowerManagerService; import com.android.server.power.ShutdownThread; import com.android.server.power.ThermalManagerService; @@ -2033,7 +2033,7 @@ public final class SystemServer implements Dumpable { // Grants default permissions and defines roles t.traceBegin("StartRoleManagerService"); mSystemServiceManager.startService(new RoleManagerService( - mSystemContext, new LegacyRoleStateProviderImpl(mSystemContext))); + mSystemContext, new RoleServicePlatformHelperImpl(mSystemContext))); t.traceEnd(); // We need to always start this service, regardless of whether the