import android.content.pm.PermissionInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.SuspendDialogInfo;
import android.content.pm.UserInfo;
import android.content.pm.VerifierDeviceIdentity;
void setRuntimePermissionsVersion(int version, int userId);
void notifyPackagesReplacedReceived(in String[] packages);
+
+ List<SplitPermissionInfoParcelable> getSplitPermissions();
}
import android.content.IntentFilter;
import android.content.pm.PackageParserCacheHelper.ReadHelper;
import android.content.pm.PackageParserCacheHelper.WriteHelper;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.pm.split.DefaultSplitAssetLoader;
import android.content.pm.split.SplitAssetDependencyLoader;
import android.content.pm.split.SplitAssetLoader;
import com.android.internal.os.ClassLoaderFactory;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.XmlUtils;
+import com.android.server.SystemConfig;
import libcore.io.IoUtils;
import libcore.util.EmptyArray;
Slog.i(TAG, newPermsMsg.toString());
}
-
- final int NS = PermissionManager.SPLIT_PERMISSIONS.size();
- for (int is=0; is<NS; is++) {
- final PermissionManager.SplitPermissionInfo spi =
- PermissionManager.SPLIT_PERMISSIONS.get(is);
+ List<SplitPermissionInfoParcelable> splitPermissions = getSplitPermissions();
+ final int listSize = splitPermissions.size();
+ for (int is = 0; is < listSize; is++) {
+ final SplitPermissionInfoParcelable spi = splitPermissions.get(is);
if (pkg.applicationInfo.targetSdkVersion >= spi.getTargetSdk()
|| !pkg.requestedPermissions.contains(spi.getSplitPermission())) {
continue;
return pkg;
}
+ private List<SplitPermissionInfoParcelable> getSplitPermissions() {
+ // PackageManager runs this code during initialization prior to registering with
+ // ServiceManager, so we can't use the PackageManager API. Instead, just read from
+ // SystemConfig directly when in any SystemProcess and only use PackageManager when not in
+ // one.
+ if (ActivityThread.isSystem()) {
+ return PermissionManager.splitPermissionInfoListToParcelableList(
+ SystemConfig.getInstance().getSplitPermissions());
+ } else {
+ try {
+ return ActivityThread.getPackageManager().getSplitPermissions();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+
private boolean checkOverlayRequiredSystemProperty(String propName, String propValue) {
if (TextUtils.isEmpty(propName) || TextUtils.isEmpty(propValue)) {
--- /dev/null
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ package android.content.pm.permission;
+
+ parcelable SplitPermissionInfoParcelable;
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.permission;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Parcelable version of {@link android.permission.PermissionManager.SplitPermissionInfo}
+ * @hide
+ */
+public class SplitPermissionInfoParcelable implements Parcelable {
+
+ /**
+ * The permission that is split.
+ */
+ @NonNull
+ private final String mSplitPermission;
+
+ /**
+ * The permissions that are added.
+ */
+ @NonNull
+ private final List<String> mNewPermissions;
+
+ /**
+ * The target API level when the permission was split.
+ */
+ @IntRange(from = 0)
+ private final int mTargetSdk;
+
+ private void onConstructed() {
+ Preconditions.checkCollectionElementsNotNull(mNewPermissions, "newPermissions");
+ }
+
+
+
+ // Code below generated by codegen v1.0.0.
+ //
+ // DO NOT MODIFY!
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/content/pm/SplitPermissionInfoParcelable.java
+ //
+ // CHECKSTYLE:OFF Generated code
+
+ /**
+ * Creates a new SplitPermissionInfoParcelable.
+ *
+ * @param splitPermission
+ * The permission that is split.
+ * @param newPermissions
+ * The permissions that are added.
+ * @param targetSdk
+ * The target API level when the permission was split.
+ */
+ public SplitPermissionInfoParcelable(
+ @NonNull String splitPermission,
+ @NonNull List<String> newPermissions,
+ @IntRange(from = 0) int targetSdk) {
+ this.mSplitPermission = splitPermission;
+ Preconditions.checkNotNull(mSplitPermission);
+ this.mNewPermissions = newPermissions;
+ Preconditions.checkNotNull(mNewPermissions);
+ this.mTargetSdk = targetSdk;
+ Preconditions.checkArgumentNonnegative(mTargetSdk);
+
+ onConstructed();
+ }
+
+ /**
+ * The permission that is split.
+ */
+ public @NonNull String getSplitPermission() {
+ return mSplitPermission;
+ }
+
+ /**
+ * The permissions that are added.
+ */
+ public @NonNull List<String> getNewPermissions() {
+ return mNewPermissions;
+ }
+
+ /**
+ * The target API level when the permission was split.
+ */
+ public @IntRange(from = 0) int getTargetSdk() {
+ return mTargetSdk;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ // You can override field equality logic by defining either of the methods like:
+ // boolean fieldNameEquals(SplitPermissionInfoParcelable other) { ... }
+ // boolean fieldNameEquals(FieldType otherValue) { ... }
+
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ @SuppressWarnings("unchecked")
+ SplitPermissionInfoParcelable that = (SplitPermissionInfoParcelable) o;
+ //noinspection PointlessBooleanExpression
+ return true
+ && Objects.equals(mSplitPermission, that.mSplitPermission)
+ && Objects.equals(mNewPermissions, that.mNewPermissions)
+ && mTargetSdk == that.mTargetSdk;
+ }
+
+ @Override
+ public int hashCode() {
+ // You can override field hashCode logic by defining methods like:
+ // int fieldNameHashCode() { ... }
+
+ int _hash = 1;
+ _hash = 31 * _hash + Objects.hashCode(mSplitPermission);
+ _hash = 31 * _hash + Objects.hashCode(mNewPermissions);
+ _hash = 31 * _hash + mTargetSdk;
+ return _hash;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeString(mSplitPermission);
+ dest.writeStringList(mNewPermissions);
+ dest.writeInt(mTargetSdk);
+ }
+
+ @Override
+ public int describeContents() { return 0; }
+
+ public static final @NonNull Parcelable.Creator<SplitPermissionInfoParcelable> CREATOR
+ = new Parcelable.Creator<SplitPermissionInfoParcelable>() {
+ @Override
+ public SplitPermissionInfoParcelable[] newArray(int size) {
+ return new SplitPermissionInfoParcelable[size];
+ }
+
+ @Override
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ public SplitPermissionInfoParcelable createFromParcel(Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ String splitPermission = in.readString();
+ List<String> newPermissions = new java.util.ArrayList<>();
+ in.readStringList(newPermissions);
+ int targetSdk = in.readInt();
+ return new SplitPermissionInfoParcelable(
+ splitPermission,
+ newPermissions,
+ targetSdk);
+ }
+ };
+}
import android.annotation.TestApi;
import android.content.Context;
import android.content.pm.IPackageManager;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.os.RemoteException;
+import android.util.Log;
import com.android.internal.annotations.Immutable;
-import com.android.server.SystemConfig;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
-import java.util.Objects;
/**
* System level service for accessing the permission capabilities of the platform.
@SystemApi
@SystemService(Context.PERMISSION_SERVICE)
public final class PermissionManager {
- /**
- * {@link android.content.pm.PackageParser} needs access without having a {@link Context}.
- *
- * @hide
- */
- public static final ArrayList<SplitPermissionInfo> SPLIT_PERMISSIONS =
- SystemConfig.getInstance().getSplitPermissions();
+ private static final String TAG = PermissionManager.class.getName();
private final @NonNull Context mContext;
private final IPackageManager mPackageManager;
+ private List<SplitPermissionInfo> mSplitPermissionInfos;
+
/**
* Creates a new instance.
*
* @return All permissions that are split.
*/
public @NonNull List<SplitPermissionInfo> getSplitPermissions() {
- return SPLIT_PERMISSIONS;
+ if (mSplitPermissionInfos != null) {
+ return mSplitPermissionInfos;
+ }
+
+ List<SplitPermissionInfoParcelable> parcelableList;
+ try {
+ parcelableList = mPackageManager.getSplitPermissions();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error getting split permissions", e);
+ return Collections.emptyList();
+ }
+
+ mSplitPermissionInfos = splitPermissionInfoListToNonParcelableList(parcelableList);
+
+ return mSplitPermissionInfos;
+ }
+
+ private List<SplitPermissionInfo> splitPermissionInfoListToNonParcelableList(
+ List<SplitPermissionInfoParcelable> parcelableList) {
+ final int size = parcelableList.size();
+ List<SplitPermissionInfo> list = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ list.add(new SplitPermissionInfo(parcelableList.get(i)));
+ }
+ return list;
+ }
+
+ /**
+ * Converts a {@link List} of {@link SplitPermissionInfo} into a List of
+ * {@link SplitPermissionInfoParcelable} and returns it.
+ * @hide
+ */
+ public static List<SplitPermissionInfoParcelable> splitPermissionInfoListToParcelableList(
+ List<SplitPermissionInfo> splitPermissionsList) {
+ final int size = splitPermissionsList.size();
+ List<SplitPermissionInfoParcelable> outList = new ArrayList<>(size);
+ for (int i = 0; i < size; i++) {
+ SplitPermissionInfo info = splitPermissionsList.get(i);
+ outList.add(new SplitPermissionInfoParcelable(
+ info.getSplitPermission(), info.getNewPermissions(), info.getTargetSdk()));
+ }
+ return outList;
}
/**
*/
@Immutable
public static final class SplitPermissionInfo {
- private final @NonNull String mSplitPerm;
- private final @NonNull List<String> mNewPerms;
- private final int mTargetSdk;
+ private @NonNull final SplitPermissionInfoParcelable mSplitPermissionInfoParcelable;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SplitPermissionInfo that = (SplitPermissionInfo) o;
- return mTargetSdk == that.mTargetSdk
- && mSplitPerm.equals(that.mSplitPerm)
- && mNewPerms.equals(that.mNewPerms);
+ return mSplitPermissionInfoParcelable.equals(that.mSplitPermissionInfoParcelable);
}
@Override
public int hashCode() {
- return Objects.hash(mSplitPerm, mNewPerms, mTargetSdk);
+ return mSplitPermissionInfoParcelable.hashCode();
}
/**
* Get the permission that is split.
*/
public @NonNull String getSplitPermission() {
- return mSplitPerm;
+ return mSplitPermissionInfoParcelable.getSplitPermission();
}
/**
* Get the permissions that are added.
*/
public @NonNull List<String> getNewPermissions() {
- return mNewPerms;
+ return mSplitPermissionInfoParcelable.getNewPermissions();
}
/**
* Get the target API level when the permission was split.
*/
public int getTargetSdk() {
- return mTargetSdk;
+ return mSplitPermissionInfoParcelable.getTargetSdk();
}
/**
*/
public SplitPermissionInfo(@NonNull String splitPerm, @NonNull List<String> newPerms,
int targetSdk) {
- mSplitPerm = splitPerm;
- mNewPerms = newPerms;
- mTargetSdk = targetSdk;
+ this(new SplitPermissionInfoParcelable(splitPerm, newPerms, targetSdk));
+ }
+
+ private SplitPermissionInfo(@NonNull SplitPermissionInfoParcelable parcelable) {
+ mSplitPermissionInfoParcelable = parcelable;
}
}
}
/**
* Loads global system configuration info.
+ * Note: Initializing this class hits the disk and is slow. This class should generally only be
+ * accessed by the system_server process.
*/
public class SystemConfig {
static final String TAG = "SystemConfig";
private final ArraySet<String> mBugreportWhitelistedPackages = new ArraySet<>();
public static SystemConfig getInstance() {
+ if (!isSystemProcess()) {
+ Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
+ + "system_server.");
+ }
+
synchronized (SystemConfig.class) {
if (sInstance == null) {
sInstance = new SystemConfig();
mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk));
}
}
+
+ private static boolean isSystemProcess() {
+ return Process.myUid() == Process.SYSTEM_UID;
+ }
}
import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.content.pm.dex.IArtManager;
+import android.content.pm.permission.SplitPermissionInfoParcelable;
import android.content.res.Resources;
import android.content.rollback.IRollbackManager;
import android.database.ContentObserver;
import android.os.storage.StorageManagerInternal;
import android.os.storage.VolumeInfo;
import android.os.storage.VolumeRecord;
+import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.provider.MediaStore;
import android.provider.Settings.Global;
}
}
+ @Override
+ public List<SplitPermissionInfoParcelable> getSplitPermissions() {
+ return PermissionManager.splitPermissionInfoListToParcelableList(
+ SystemConfig.getInstance().getSplitPermissions());
+ }
+
private void notifyInstallObserver(String packageName) {
Pair<PackageInstalledInfo, IPackageInstallObserver2> pair =
mNoKillInstallObservers.remove(packageName);
// or has updated its target SDK and AR is no longer implicit to it.
// This is a compatibility workaround for apps when AR permission was
// split in Q.
- int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ final List<PermissionManager.SplitPermissionInfo> permissionList =
+ getSplitPermissions();
+ int numSplitPerms = permissionList.size();
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
PermissionManager.SplitPermissionInfo sp =
- PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+ permissionList.get(splitPermNum);
String splitPermName = sp.getSplitPermission();
if (sp.getNewPermissions().contains(permName)
&& origPermissions.hasInstallPermission(splitPermName)) {
String pkgName = pkg.packageName;
ArrayMap<String, ArraySet<String>> newToSplitPerms = new ArrayMap<>();
- int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size();
+ final List<PermissionManager.SplitPermissionInfo> permissionList = getSplitPermissions();
+ int numSplitPerms = permissionList.size();
for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) {
- PermissionManager.SplitPermissionInfo spi =
- PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum);
+ PermissionManager.SplitPermissionInfo spi = permissionList.get(splitPermNum);
List<String> newPerms = spi.getNewPermissions();
int numNewPerms = newPerms.size();
return updatedUserIds;
}
+ private List<PermissionManager.SplitPermissionInfo> getSplitPermissions() {
+ return SystemConfig.getInstance().getSplitPermissions();
+ }
+
private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) {
boolean allowed = false;
final int NP = PackageParser.NEW_PERMISSIONS.length;