Merge "Call roles granting only when packages changed"
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
*/
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
@@ -109,6 +115,23 @@ public class RoleUserState {
|
||||
writeAsyncLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user