Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d066c7c9 authored by Hai Zhang's avatar Hai Zhang
Browse files

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
parent 91464139
Loading
Loading
Loading
Loading
+50 −5
Original line number Diff line number Diff line
@@ -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<String> 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<String> 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());
    }
}
+5 −53
Original line number Diff line number Diff line
@@ -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<Void> 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<String> 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<String> 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;
+14 −5
Original line number Diff line number Diff line
@@ -23,21 +23,30 @@ import java.util.Map;
import java.util.Set;

/**
 * Provider for legacy role state.
 * <p>
 * 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.
     * <p>
     * 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<String, Set<String>> 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);
}
+6 −6
Original line number Diff line number Diff line
@@ -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<String, Set<String>> entry : roles.entrySet()) {
+2 −2
Original line number Diff line number Diff line
@@ -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