diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ef08bf53f5b0c..4c970da36f459 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; @@ -79,7 +80,6 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.os.storage.StorageManager; -import android.permission.PermissionManager; import android.system.ErrnoException; import android.system.OsConstants; import android.system.StructStat; @@ -2528,11 +2528,17 @@ public class PackageParser { Slog.i(TAG, newPermsMsg.toString()); } + List splitPermissions; - final int NS = PermissionManager.SPLIT_PERMISSIONS.size(); - for (int is=0; is= spi.getTargetSdk() || !pkg.requestedPermissions.contains(spi.getSplitPermission())) { continue; @@ -8501,5 +8507,4 @@ public class PackageParser { this.error = error; } } - } 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 0000000000000..d84454ce744b1 --- /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 0000000000000..421ae492ba6ff --- /dev/null +++ b/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java @@ -0,0 +1,202 @@ +/* + * 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.DataClass; +import com.android.internal.util.Preconditions; + +import java.util.List; +import java.util.Objects; + +/** + * Parcelable version of {@link android.permission.PermissionManager.SplitPermissionInfo} + * @hide + */ +@DataClass(genEqualsHashCode = true) +public class SplitPermissionInfoParcelable implements Parcelable { + + /** + * The permission that is split. + */ + @NonNull + private final String mSplitPermission; + + /** + * The permissions that are added. + */ + @NonNull + private final List 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/permission/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. + */ + @DataClass.Generated.Member + public SplitPermissionInfoParcelable( + @NonNull String splitPermission, + @NonNull List newPermissions, + @IntRange(from = 0) int targetSdk) { + this.mSplitPermission = splitPermission; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mSplitPermission); + this.mNewPermissions = newPermissions; + com.android.internal.util.AnnotationValidations.validate( + NonNull.class, null, mNewPermissions); + this.mTargetSdk = targetSdk; + com.android.internal.util.AnnotationValidations.validate( + IntRange.class, null, mTargetSdk, + "from", 0); + + onConstructed(); + } + + /** + * The permission that is split. + */ + @DataClass.Generated.Member + public @NonNull String getSplitPermission() { + return mSplitPermission; + } + + /** + * The permissions that are added. + */ + @DataClass.Generated.Member + public @NonNull List getNewPermissions() { + return mNewPermissions; + } + + /** + * The target API level when the permission was split. + */ + @DataClass.Generated.Member + public @IntRange(from = 0) int getTargetSdk() { + return mTargetSdk; + } + + @Override + @DataClass.Generated.Member + 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 + @DataClass.Generated.Member + 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 + @DataClass.Generated.Member + 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 + @DataClass.Generated.Member + public int describeContents() { return 0; } + + @DataClass.Generated.Member + public static final @NonNull Parcelable.Creator CREATOR + = new Parcelable.Creator() { + @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 newPermissions = new java.util.ArrayList<>(); + in.readStringList(newPermissions); + int targetSdk = in.readInt(); + return new SplitPermissionInfoParcelable( + splitPermission, + newPermissions, + targetSdk); + } + }; + + @DataClass.Generated( + time = 1567634390477L, + codegenVersion = "1.0.0", + sourceFile = "frameworks/base/core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java", + inputSignatures = "private final @android.annotation.NonNull java.lang.String mSplitPermission\nprivate final @android.annotation.NonNull java.util.List mNewPermissions\nprivate final @android.annotation.IntRange(from=0L) int mTargetSdk\nprivate void onConstructed()\nclass SplitPermissionInfoParcelable extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genEqualsHashCode=true)") + @Deprecated + private void __metadata() {} + +} diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index 9fa5f16474311..60c88116f8048 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -19,6 +19,7 @@ package android.permission; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.permission.SplitPermissionInfoParcelable; import android.permission.IOnPermissionsChangeListener; /** @@ -97,4 +98,6 @@ interface IPermissionManager { String packageName, int userId); boolean isPermissionRevokedByPolicy(String permName, String packageName, int userId); + + List getSplitPermissions(); } diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index 5e359589dfc25..6c4ee016033dc 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -24,16 +24,18 @@ import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; +import android.app.ActivityThread; import android.content.Context; import android.content.pm.IPackageManager; +import android.content.pm.permission.SplitPermissionInfoParcelable; import android.os.RemoteException; +import android.util.Slog; 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,6 +46,8 @@ import java.util.Objects; @SystemApi @SystemService(Context.PERMISSION_SERVICE) public final class PermissionManager { + private static final String TAG = PermissionManager.class.getName(); + /** @hide */ public static final String KILL_APP_REASON_PERMISSIONS_REVOKED = "permissions revoked"; @@ -51,19 +55,12 @@ public final class PermissionManager { public static final String KILL_APP_REASON_GIDS_CHANGED = "permission grant or revoke changed gids"; - - /** - * {@link android.content.pm.PackageParser} needs access without having a {@link Context}. - * - * @hide - */ - public static final ArrayList SPLIT_PERMISSIONS = - SystemConfig.getInstance().getSplitPermissions(); - private final @NonNull Context mContext; private final IPackageManager mPackageManager; + private List mSplitPermissionInfos; + /** * Creates a new instance. * @@ -131,7 +128,48 @@ public final class PermissionManager { * @return All permissions that are split. */ public @NonNull List getSplitPermissions() { - return SPLIT_PERMISSIONS; + if (mSplitPermissionInfos != null) { + return mSplitPermissionInfos; + } + + List parcelableList; + try { + parcelableList = ActivityThread.getPermissionManager().getSplitPermissions(); + } catch (RemoteException e) { + Slog.e(TAG, "Error getting split permissions", e); + return Collections.emptyList(); + } + + mSplitPermissionInfos = splitPermissionInfoListToNonParcelableList(parcelableList); + + return mSplitPermissionInfos; + } + + private List splitPermissionInfoListToNonParcelableList( + List parcelableList) { + final int size = parcelableList.size(); + List 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 splitPermissionInfoListToParcelableList( + List splitPermissionsList) { + final int size = splitPermissionsList.size(); + List 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; } /** @@ -140,44 +178,40 @@ public final class PermissionManager { */ @Immutable public static final class SplitPermissionInfo { - private final @NonNull String mSplitPerm; - private final @NonNull List 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 getNewPermissions() { - return mNewPerms; + return mSplitPermissionInfoParcelable.getNewPermissions(); } /** * Get the target API level when the permission was split. */ public int getTargetSdk() { - return mTargetSdk; + return mSplitPermissionInfoParcelable.getTargetSdk(); } /** @@ -191,9 +225,11 @@ public final class PermissionManager { */ public SplitPermissionInfo(@NonNull String splitPerm, @NonNull List 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 364278d1a09e0..7cd3e95c6499c 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"; @@ -208,6 +210,11 @@ public class SystemConfig { private final ArraySet 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(); @@ -1161,4 +1168,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/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 72c8b22f77e7d..83aa07d446e89 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -67,6 +67,7 @@ import android.content.pm.PackageParser.Package; import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; +import android.content.pm.permission.SplitPermissionInfoParcelable; import android.metrics.LogMaker; import android.os.Binder; import android.os.Build; @@ -2348,10 +2349,11 @@ public class PermissionManagerService extends IPermissionManager.Stub { // 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 permissionList = + getSplitPermissions(); + int numSplitPerms = permissionList.size(); for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - PermissionManager.SplitPermissionInfo sp = - PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); + SplitPermissionInfoParcelable sp = permissionList.get(splitPermNum); String splitPermName = sp.getSplitPermission(); if (sp.getNewPermissions().contains(permName) && origPermissions.hasInstallPermission(splitPermName)) { @@ -2920,10 +2922,10 @@ public class PermissionManagerService extends IPermissionManager.Stub { String pkgName = pkg.packageName; ArrayMap> newToSplitPerms = new ArrayMap<>(); - int numSplitPerms = PermissionManager.SPLIT_PERMISSIONS.size(); + final List permissionList = getSplitPermissions(); + int numSplitPerms = permissionList.size(); for (int splitPermNum = 0; splitPermNum < numSplitPerms; splitPermNum++) { - PermissionManager.SplitPermissionInfo spi = - PermissionManager.SPLIT_PERMISSIONS.get(splitPermNum); + SplitPermissionInfoParcelable spi = permissionList.get(splitPermNum); List newPerms = spi.getNewPermissions(); int numNewPerms = newPerms.size(); @@ -2991,6 +2993,12 @@ public class PermissionManagerService extends IPermissionManager.Stub { return updatedUserIds; } + @Override + public List getSplitPermissions() { + return PermissionManager.splitPermissionInfoListToParcelableList( + SystemConfig.getInstance().getSplitPermissions()); + } + private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { boolean allowed = false; final int NP = PackageParser.NEW_PERMISSIONS.length;