summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Eugene Susla <eugenesusla@google.com> 2018-11-30 23:13:50 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2018-11-30 23:13:50 +0000
commitb9df101c9eac5ce534f274c04913e54ea2c3de1d (patch)
treeba05ef5cbf3dc24195939e439ae6937a4e0612ae
parent5cf6abedcbf035617508175e9f1e08037ac791a6 (diff)
parentabdefbaeeb74c0311c8f3465658c501260290f73 (diff)
Merge "Call roles granting only when packages changed"
-rw-r--r--core/java/android/content/pm/PackageManagerInternal.java20
-rw-r--r--core/java/com/android/internal/util/BitUtils.java9
-rw-r--r--core/java/com/android/internal/util/CollectionUtils.java8
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java55
-rw-r--r--services/core/java/com/android/server/role/RoleManagerService.java57
-rw-r--r--services/core/java/com/android/server/role/RoleUserState.java41
6 files changed, 173 insertions, 17 deletions
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java
index 6f49cc42f6f6..b49c4476e82d 100644
--- a/core/java/android/content/pm/PackageManagerInternal.java
+++ b/core/java/android/content/pm/PackageManagerInternal.java
@@ -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);
}
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
index 17d5a2e36974..61581458f98a 100644
--- a/core/java/com/android/internal/util/BitUtils.java
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -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();
+ }
}
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index 083c0c9736f9..151901be7b5b 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -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;
@@ -190,6 +191,13 @@ public class CollectionUtils {
}
/**
+ * 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}
*/
public static boolean isEmpty(@Nullable Collection<?> cur) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6a6a5be53409..b76eaaffe078 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -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;
@@ -314,8 +313,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;
@@ -374,6 +372,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;
/**
@@ -23207,6 +23206,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")
@@ -23329,6 +23367,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) {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index b390eebf3d7e..b065470fe98c 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -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) {
diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java
index 9c43f4d02ad0..f218d3a5834b 100644
--- a/services/core/java/com/android/server/role/RoleUserState.java
+++ b/services/core/java/com/android/server/role/RoleUserState.java
@@ -31,6 +31,7 @@ import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.function.pooled.PooledLambda;
import libcore.io.IoUtils;
@@ -63,6 +64,7 @@ public class RoleUserState {
private static final String TAG_HOLDER = "holder";
private static final String ATTRIBUTE_VERSION = "version";
private static final String ATTRIBUTE_NAME = "name";
+ private static final String ATTRIBUTE_PACKAGES_HASH = "packagesHash";
@UserIdInt
private final int mUserId;
@@ -70,11 +72,15 @@ public class RoleUserState {
@GuardedBy("RoleManagerService.mLock")
private int mVersion;
+ @GuardedBy("RoleManagerService.mLock")
+ private String mLastGrantPackagesHash = null;
+
/**
* Maps role names to its holders' package names. The values should never be null.
*/
@GuardedBy("RoleManagerService.mLock")
- private ArrayMap<String, ArraySet<String>> mRoles;
+ @Nullable
+ private ArrayMap<String, ArraySet<String>> mRoles = null;
@GuardedBy("RoleManagerService.mLock")
private boolean mDestroyed;
@@ -110,6 +116,23 @@ public class RoleUserState {
}
/**
+ * Get the hash representing the state of packages during the last time initial grants was run
+ */
+ @GuardedBy("RoleManagerService.mLock")
+ public String getLastGrantPackagesHashLocked() {
+ return mLastGrantPackagesHash;
+ }
+
+ /**
+ * Set the hash representing the state of packages during the last time initial grants was run
+ */
+ @GuardedBy("RoleManagerService.mLock")
+ public void setLastGrantPackagesHashLocked(String lastGrantPackagesHash) {
+ mLastGrantPackagesHash = lastGrantPackagesHash;
+ writeAsyncLocked();
+ }
+
+ /**
* Get whether the role is available.
*
* @param roleName the name of the role to get the holders for
@@ -227,11 +250,11 @@ public class RoleUserState {
* Schedule writing the state to file.
*/
@GuardedBy("RoleManagerService.mLock")
- private void writeAsyncLocked() {
+ void writeAsyncLocked() {
throwIfDestroyedLocked();
int version = mVersion;
ArrayMap<String, ArraySet<String>> roles = new ArrayMap<>();
- for (int i = 0, size = mRoles.size(); i < size; ++i) {
+ for (int i = 0, size = CollectionUtils.size(mRoles); i < size; ++i) {
String roleName = mRoles.keyAt(i);
ArraySet<String> roleHolders = mRoles.valueAt(i);
roleHolders = new ArraySet<>(roleHolders);
@@ -240,11 +263,12 @@ public class RoleUserState {
mWriteHandler.removeCallbacksAndMessages(null);
// TODO: Throttle writes.
mWriteHandler.sendMessage(PooledLambda.obtainMessage(
- RoleUserState::writeSync, this, version, roles));
+ RoleUserState::writeSync, this, version, roles, mLastGrantPackagesHash));
}
@WorkerThread
- private void writeSync(int version, @NonNull ArrayMap<String, ArraySet<String>> roles) {
+ private void writeSync(int version, @NonNull ArrayMap<String, ArraySet<String>> roles,
+ String packagesHash) {
AtomicFile atomicFile = new AtomicFile(getFile(mUserId), "roles-" + mUserId);
FileOutputStream out = null;
try {
@@ -256,7 +280,7 @@ public class RoleUserState {
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
serializer.startDocument(null, true);
- serializeRoles(serializer, version, roles);
+ serializeRoles(serializer, version, roles, packagesHash);
serializer.endDocument();
atomicFile.finishWrite(out);
@@ -272,9 +296,11 @@ public class RoleUserState {
@WorkerThread
private void serializeRoles(@NonNull XmlSerializer serializer, int version,
- @NonNull ArrayMap<String, ArraySet<String>> roles) throws IOException {
+ @NonNull ArrayMap<String, ArraySet<String>> roles, String packagesHash)
+ throws IOException {
serializer.startTag(null, TAG_ROLES);
serializer.attribute(null, ATTRIBUTE_VERSION, Integer.toString(version));
+ serializer.attribute(null, ATTRIBUTE_PACKAGES_HASH, packagesHash);
for (int i = 0, size = roles.size(); i < size; ++i) {
String roleName = roles.keyAt(i);
ArraySet<String> roleHolders = roles.valueAt(i);
@@ -341,6 +367,7 @@ public class RoleUserState {
private void parseRolesLocked(@NonNull XmlPullParser parser) throws IOException,
XmlPullParserException {
mVersion = Integer.parseInt(parser.getAttributeValue(null, ATTRIBUTE_VERSION));
+ mLastGrantPackagesHash = parser.getAttributeValue(null, ATTRIBUTE_PACKAGES_HASH);
mRoles = new ArrayMap<>();
int type;