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

Commit abdefbae authored by Eugene Susla's avatar Eugene Susla
Browse files

Call roles granting only when packages changed

This computes and stores a hash of significant (for PermissionController)
packages state for the time when granting last ran.

Test: - enable DEBUG flag
- using logcat ensure roles granted on first bootloader
- adb reboot
- ensure roles granting skipped
- disable a package
- adb reboot
- ensure roles granting ran on boot

Change-Id: Idaea40c0ea34feaedfbe357627201f85e66876d5
parent 4df6418f
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ import android.content.pm.PackageManager.PackageInfoFlags;
import android.content.pm.PackageManager.ResolveInfoFlags;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.util.ArraySet;
import android.util.SparseArray;

import com.android.internal.util.function.TriFunction;
@@ -37,6 +38,7 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;

/**
 * Package manager local system service interface.
@@ -735,4 +737,22 @@ public abstract class PackageManagerInternal {

    /** Returns {@code true} if the given user requires extra badging for icons. */
    public abstract boolean userNeedsBadging(int userId);

    /**
     * Perform the given action for each package.
     * Note that packages lock will be held while performin the actions.
     *
     * @param actionLocked action to be performed
     */
    public abstract void forEachPackage(Consumer<PackageParser.Package> actionLocked);

    /** Returns the list of enabled components */
    public abstract ArraySet<String> getEnabledComponents(String packageName, int userId);

    /** Returns the list of disabled components */
    public abstract ArraySet<String> getDisabledComponents(String packageName, int userId);

    /** Returns whether the given package is enabled for the given user */
    public abstract @PackageManager.EnabledState int getApplicationEnabledState(
            String packageName, int userId);
}
+8 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ import java.util.function.IntFunction;

/**
 * A utility class for handling unsigned integers and unsigned arithmetics, as well as syntactic
 * sugar methods for ByteBuffer. Useful for networking and packet manipulations.
 * sugar methods for {@link ByteBuffer}. Useful for networking and packet manipulations.
 * {@hide}
 */
public final class BitUtils {
@@ -151,4 +151,11 @@ public final class BitUtils {
        TextUtils.wrap(builder, "[", "]");
        return builder.toString();
    }

    /**
     * Converts long to byte array
     */
    public static byte[] toBytes(long l) {
        return ByteBuffer.allocate(8).putLong(l).array();
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -189,6 +190,13 @@ public class CollectionUtils {
        return cur != null ? cur.size() : 0;
    }

    /**
     * Returns the size of the given map, or 0 if null
     */
    public static int size(@Nullable Map<?, ?> cur) {
        return cur != null ? cur.size() : 0;
    }

    /**
     * Returns whether the given collection {@link Collection#isEmpty is empty} or {@code null}
     */
+51 −4
Original line number Diff line number Diff line
@@ -116,8 +116,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.permission.PermissionsState
        .PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
import android.Manifest;
import android.annotation.IntDef;
@@ -313,8 +312,7 @@ import com.android.server.pm.dex.DexoptOptions;
import com.android.server.pm.dex.PackageDexUsage;
import com.android.server.pm.permission.BasePermission;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy
        .DefaultPermissionGrantedCallback;
import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback;
import com.android.server.pm.permission.PermissionManagerInternal;
import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionManagerService;
@@ -373,6 +371,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Predicate;
/**
@@ -23185,6 +23184,45 @@ public class PackageManagerService extends IPackageManager.Stub
                throws IOException {
            PackageManagerService.this.freeStorage(volumeUuid, bytes, storageFlags);
        }
        @Override
        public void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
            PackageManagerService.this.forEachPackage(actionLocked);
        }
        @Override
        public ArraySet<String> getEnabledComponents(String packageName, int userId) {
            synchronized (mPackages) {
                PackageSetting setting = mSettings.getPackageLPr(packageName);
                if (setting == null) {
                    return new ArraySet<>();
                }
                return setting.getEnabledComponents(userId);
            }
        }
        @Override
        public ArraySet<String> getDisabledComponents(String packageName, int userId) {
            synchronized (mPackages) {
                PackageSetting setting = mSettings.getPackageLPr(packageName);
                if (setting == null) {
                    return new ArraySet<>();
                }
                return setting.getDisabledComponents(userId);
            }
        }
        @Override
        public @PackageManager.EnabledState int getApplicationEnabledState(
                String packageName, int userId) {
            synchronized (mPackages) {
                PackageSetting setting = mSettings.getPackageLPr(packageName);
                if (setting == null) {
                    return COMPONENT_ENABLED_STATE_DEFAULT;
                }
                return setting.getEnabled(userId);
            }
        }
    }
    @GuardedBy("mPackages")
@@ -23307,6 +23345,15 @@ public class PackageManagerService extends IPackageManager.Stub
        }
    }
    void forEachPackage(Consumer<PackageParser.Package> actionLocked) {
        synchronized (mPackages) {
            int numPackages = mPackages.size();
            for (int i = 0; i < numPackages; i++) {
                actionLocked.accept(mPackages.valueAt(i));
            }
        }
    }
    private static void enforceSystemOrPhoneCaller(String tag) {
        int callingUid = Binder.getCallingUid();
        if (callingUid != Process.PHONE_UID && callingUid != Process.SYSTEM_UID) {
+52 −5
Original line number Diff line number Diff line
@@ -30,20 +30,27 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManagerInternal;
import android.content.pm.Signature;
import android.os.ResultReceiver;
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.PackageUtils;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.BitUtils;
import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FunctionalUtils;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;

import java.io.ByteArrayOutputStream;
import java.io.FileDescriptor;
import java.util.ArrayList;
import java.util.Collections;
@@ -117,13 +124,18 @@ public class RoleManagerService extends SystemService {

    @Override
    public void onStartUser(@UserIdInt int userId) {
        RoleUserState userState;
        synchronized (mLock) {
            //TODO only call into PermissionController if it or system upgreaded (for boot time)
            getUserStateLocked(userId);
            userState = getUserStateLocked(userId);
        }
        //TODO consider calling grants only when certain conditions are met
        // such as OS or PermissionController upgrade
        if (RemoteRoleControllerService.DEBUG) {
        String packagesHash = computeComponentStateHash(userId);
        boolean needGrant;
        synchronized (mLock) {
            needGrant = !packagesHash.equals(userState.getLastGrantPackagesHashLocked());
        }
        if (needGrant) {
            // Some vital packages state has changed since last role grant
            // Run grants again
            Slog.i(LOG_TAG, "Granting default permissions...");
            CompletableFuture<Void> result = new CompletableFuture<>();
            getControllerService(userId).onGrantDefaultRoles(
@@ -140,12 +152,47 @@ public class RoleManagerService extends SystemService {
                    });
            try {
                result.get(5, TimeUnit.SECONDS);
                synchronized (mLock) {
                    userState.setLastGrantPackagesHashLocked(packagesHash);
                }
            } catch (InterruptedException | ExecutionException | TimeoutException e) {
                Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
            }
        } else if (RemoteRoleControllerService.DEBUG) {
            Slog.i(LOG_TAG, "Already ran grants for package state " + packagesHash);
        }
    }

    private String computeComponentStateHash(int userId) {
        PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        pm.forEachPackage(FunctionalUtils.uncheckExceptions(pkg -> {
            out.write(pkg.packageName.getBytes());
            out.write(BitUtils.toBytes(pkg.getLongVersionCode()));
            out.write(pm.getApplicationEnabledState(pkg.packageName, userId));

            ArraySet<String> enabledComponents =
                    pm.getEnabledComponents(pkg.packageName, userId);
            int numComponents = CollectionUtils.size(enabledComponents);
            for (int i = 0; i < numComponents; i++) {
                out.write(enabledComponents.valueAt(i).getBytes());
            }

            ArraySet<String> disabledComponents =
                    pm.getDisabledComponents(pkg.packageName, userId);
            numComponents = CollectionUtils.size(disabledComponents);
            for (int i = 0; i < numComponents; i++) {
                out.write(disabledComponents.valueAt(i).getBytes());
            }
            for (Signature signature : pkg.mSigningDetails.signatures) {
                out.write(signature.toByteArray());
            }
        }));

        return PackageUtils.computeSha256Digest(out.toByteArray());
    }

    @GuardedBy("mLock")
    @NonNull
    private RoleUserState getUserStateLocked(@UserIdInt int userId) {
Loading