diff options
8 files changed, 312 insertions, 33 deletions
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index a7eecd7f4306..abcf77b64b87 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -44,6 +44,7 @@ import android.content.pm.PermissionGroupInfo; 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; @@ -772,4 +773,6 @@ interface IPackageManager { void setRuntimePermissionsVersion(int version, int userId); void notifyPackagesReplacedReceived(in String[] packages); + + List<SplitPermissionInfoParcelable> getSplitPermissions(); } diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 643cb3e2b059..f682ebb001bc 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -57,6 +57,7 @@ import android.content.Intent; 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; @@ -103,6 +104,7 @@ import com.android.internal.annotations.VisibleForTesting; 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; @@ -2482,11 +2484,10 @@ public class PackageParser { 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; @@ -2540,6 +2541,23 @@ public class PackageParser { 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)) { diff --git a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.aidl b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.aidl new file mode 100644 index 000000000000..d84454ce744b --- /dev/null +++ b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.aidl @@ -0,0 +1,19 @@ +/** + * 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 diff --git a/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java new file mode 100644 index 000000000000..6537fbc37398 --- /dev/null +++ b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java @@ -0,0 +1,178 @@ +/* + * 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); + } + }; +} diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index a2ab0c15b150..3c45b0ce55de 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -26,14 +26,15 @@ import android.annotation.SystemService; 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. @@ -44,18 +45,14 @@ import java.util.Objects; @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. * @@ -123,7 +120,48 @@ public final class PermissionManager { * @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; } /** @@ -132,44 +170,40 @@ public final class PermissionManager { */ @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(@Nullable 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(); } /** @@ -183,9 +217,11 @@ public final class PermissionManager { */ 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; } } } diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index 9fc79cb606e6..510b321e8070 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -53,6 +53,8 @@ import java.util.Map; /** * 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"; @@ -209,6 +211,11 @@ public class 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(); @@ -1154,4 +1161,8 @@ public class SystemConfig { mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk)); } } + + private static boolean isSystemProcess() { + return Process.myUid() == Process.SYSTEM_UID; + } } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 1388e5f29e77..c7cc8b1c251b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -198,6 +198,7 @@ import android.content.pm.VersionedPackage; 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; @@ -238,6 +239,7 @@ import android.os.storage.StorageManager; 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; @@ -2121,6 +2123,12 @@ public class PackageManagerService extends IPackageManager.Stub } } + @Override + public List<SplitPermissionInfoParcelable> getSplitPermissions() { + return PermissionManager.splitPermissionInfoListToParcelableList( + SystemConfig.getInstance().getSplitPermissions()); + } + private void notifyInstallObserver(String packageName) { Pair<PackageInstalledInfo, IPackageInstallObserver2> pair = mNoKillInstallObservers.remove(packageName); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index a9d211837f8f..4c33bec71a14 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -967,10 +967,12 @@ public class PermissionManagerService { // 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)) { @@ -1537,10 +1539,10 @@ public class PermissionManagerService { 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(); @@ -1608,6 +1610,10 @@ public class PermissionManagerService { 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; |