Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5634105e authored by Philip P. Moltmann's avatar Philip P. Moltmann Committed by android-build-merger
Browse files

Merge changes from topic "SoftHardStoragePerm" into qt-dev am: 7a9a83f6

am: 30274777

Change-Id: I134cf5d8ffa352e47b0dacfca4dd65ccd22d69ab
parents b1058e6e 30274777
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -97,6 +97,7 @@ import com.android.server.pm.SharedUserSetting;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.UserManagerService;
import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionManagerServiceInternal.PermissionCallback;
import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.pm.permission.PermissionsState.PermissionState;
import com.android.server.policy.SoftRestrictedPermissionPolicy;


import libcore.util.EmptyArray;
import libcore.util.EmptyArray;


@@ -2121,11 +2122,18 @@ public class PermissionManagerService {


        if (bp.isHardRestricted()
        if (bp.isHardRestricted()
                && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
                && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
            Log.e(TAG, "Cannot grant restricted non-exempt permission "
            Log.e(TAG, "Cannot grant hard restricted non-exempt permission "
                    + permName + " for package " + packageName);
                    + permName + " for package " + packageName);
            return;
            return;
        }
        }


        if (bp.isSoftRestricted() && !SoftRestrictedPermissionPolicy.forPermission(mContext,
                pkg.applicationInfo, permName).canBeGranted()) {
            Log.e(TAG, "Cannot grant soft restricted permission " + permName + " for package "
                    + packageName);
            return;
        }

        if (bp.isDevelopment()) {
        if (bp.isDevelopment()) {
            // Development permissions must be handled specially, since they are not
            // Development permissions must be handled specially, since they are not
            // normal runtime permissions.  For now they apply to all users.
            // normal runtime permissions.  For now they apply to all users.
+36 −18
Original line number Original line Diff line number Diff line
@@ -16,10 +16,14 @@


package com.android.server.policy;
package com.android.server.policy;


import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_ERRORED;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.GET_PERMISSIONS;


import android.Manifest;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.annotation.UserIdInt;
@@ -426,20 +430,34 @@ public final class PermissionPolicyService extends SystemService {
                    mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                    mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                }
                }
            } else if (permissionInfo.isSoftRestricted()) {
            } else if (permissionInfo.isSoftRestricted()) {
                // Storage uses a special app op to decide the mount state and
                final SoftRestrictedPermissionPolicy policy =
                // supports soft restriction where the restricted state allows
                        SoftRestrictedPermissionPolicy.forPermission(mContext, pkg.applicationInfo,
                // the permission but only for accessing the medial collections.
                                permission);
                if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)

                        || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
                final int op = policy.getAppOp();
                    if (applyRestriction) {
                if (op != OP_NONE) {
                        mOpsToDefault.add(new OpToRestrict(uid,
                    switch (policy.getAppOpMode()) {
                                AppOpsManager.OP_LEGACY_STORAGE));
                        case MODE_DEFAULT:
                    } else if (pkg.applicationInfo.hasRequestedLegacyExternalStorage()) {
                            mOpsToDefault.add(new OpToRestrict(uid, op));
                        mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName,
                            break;
                                AppOpsManager.OP_LEGACY_STORAGE));
                        case MODE_ALLOWED:
                            if (policy.shouldSetAppOpIfNotDefault()) {
                                mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, op));
                            } else {
                                mOpsToAllowIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                        op));
                            }
                            break;
                        case MODE_IGNORED:
                            if (policy.shouldSetAppOpIfNotDefault()) {
                                Slog.wtf(LOG_TAG, "Always ignoring appops is not implemented");
                            } else {
                            } else {
                                mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                mOpsToIgnoreIfDefault.add(new OpToUnrestrict(uid, pkg.packageName,
                                AppOpsManager.OP_LEGACY_STORAGE));
                                        op));
                            }
                            break;
                        case MODE_ERRORED:
                            Slog.wtf(LOG_TAG, "Setting appop to errored is not implemented");
                    }
                    }
                }
                }
            }
            }
@@ -483,7 +501,7 @@ public final class PermissionPolicyService extends SystemService {


            for (String permission : pkg.requestedPermissions) {
            for (String permission : pkg.requestedPermissions) {
                final int opCode = AppOpsManager.permissionToOpCode(permission);
                final int opCode = AppOpsManager.permissionToOpCode(permission);
                if (opCode == AppOpsManager.OP_NONE) {
                if (opCode == OP_NONE) {
                    continue;
                    continue;
                }
                }


@@ -515,13 +533,13 @@ public final class PermissionPolicyService extends SystemService {
                @NonNull String packageName) {
                @NonNull String packageName) {
            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
            final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                    .opToPublicName(opCode), uid, packageName);
                    .opToPublicName(opCode), uid, packageName);
            if (currentMode == AppOpsManager.MODE_DEFAULT) {
            if (currentMode == MODE_DEFAULT) {
                mAppOpsManager.setUidMode(opCode, uid, mode);
                mAppOpsManager.setUidMode(opCode, uid, mode);
            }
            }
        }
        }


        private void setUidModeDefault(int opCode, int uid) {
        private void setUidModeDefault(int opCode, int uid) {
            mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_DEFAULT);
            mAppOpsManager.setUidMode(opCode, uid, MODE_DEFAULT);
        }
        }


        private class OpToRestrict {
        private class OpToRestrict {
+165 −0
Original line number Original line Diff line number Diff line
/*
 * 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 com.android.server.policy;

import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
import static android.app.AppOpsManager.MODE_ALLOWED;
import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.app.AppOpsManager.MODE_IGNORED;
import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
import static android.app.AppOpsManager.OP_NONE;
import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT;
import static android.content.pm.PackageManager.FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;

import android.annotation.NonNull;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.os.Build;
import android.util.Log;

/**
 * The behavior of soft restricted permissions is different for each permission. This class collects
 * the policies in one place.
 *
 * This is the twin of
 * {@link com.android.packageinstaller.permission.utils.SoftRestrictedPermissionPolicy}
 */
public abstract class SoftRestrictedPermissionPolicy {
    private static final String LOG_TAG = SoftRestrictedPermissionPolicy.class.getSimpleName();

    private static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT =
            FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT
                    | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT
                    | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT;

    private static final SoftRestrictedPermissionPolicy DUMMY_POLICY =
            new SoftRestrictedPermissionPolicy() {
                @Override
                public int getAppOp() {
                    return OP_NONE;
                }

                @Override
                public int getAppOpMode() {
                    return MODE_DEFAULT;
                }

                @Override
                public boolean shouldSetAppOpIfNotDefault() {
                    return false;
                }

                @Override
                public boolean canBeGranted() {
                    return true;
                }
            };

    /**
     * Get the policy for a soft restricted permission.
     *
     * @param context A context to use
     * @param appInfo The application the permission belongs to
     * @param permission The name of the permission
     *
     * @return The policy for this permission
     */
    public static @NonNull SoftRestrictedPermissionPolicy forPermission(@NonNull Context context,
            @NonNull ApplicationInfo appInfo, @NonNull String permission) {
        switch (permission) {
            // Storage uses a special app op to decide the mount state and supports soft restriction
            // where the restricted state allows the permission but only for accessing the medial
            // collections.
            case READ_EXTERNAL_STORAGE:
            case WRITE_EXTERNAL_STORAGE: {
                int flags = context.getPackageManager().getPermissionFlags(
                        permission, appInfo.packageName, context.getUser());
                boolean applyRestriction = (flags & FLAG_PERMISSION_APPLY_RESTRICTION) != 0;
                boolean isWhiteListed = (flags & FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) != 0;
                boolean hasRequestedLegacyExternalStorage =
                        appInfo.hasRequestedLegacyExternalStorage();
                int targetSDK = appInfo.targetSdkVersion;

                return new SoftRestrictedPermissionPolicy() {
                    @Override
                    public int getAppOp() {
                        return OP_LEGACY_STORAGE;
                    }

                    @Override
                    public int getAppOpMode() {
                        if (applyRestriction) {
                            return MODE_DEFAULT;
                        } else if (hasRequestedLegacyExternalStorage) {
                            return MODE_ALLOWED;
                        } else {
                            return MODE_IGNORED;
                        }
                    }

                    @Override
                    public boolean shouldSetAppOpIfNotDefault() {
                        // Do not switch from allowed -> ignored as this would mean to retroactively
                        // turn on isolated storage. This will make the app loose all its files.
                        return getAppOpMode() != MODE_IGNORED;
                    }

                    @Override
                    public boolean canBeGranted() {
                        if (isWhiteListed || targetSDK >= Build.VERSION_CODES.Q) {
                            return true;
                        } else {
                            Log.w(LOG_TAG, permission + " for " + appInfo.packageName
                                    + " is not whitelisted and targetSDK " + targetSDK + "<"
                                    + Build.VERSION_CODES.Q);

                            return false;
                        }
                    }
                };
            }
            default:
                return DUMMY_POLICY;
        }
    }

    /**
     * @return An app op to be changed based on the state of the permission or
     * {@link AppOpsManager#OP_NONE} if not app-op should be set.
     */
    public abstract int getAppOp();

    /**
     * @return The mode the {@link #getAppOp() app op} should be in.
     */
    public abstract @AppOpsManager.Mode int getAppOpMode();

    /**
     * @return If the {@link #getAppOp() app op} should be set even if the app-op is currently not
     * {@link AppOpsManager#MODE_DEFAULT}.
     */
    public abstract boolean shouldSetAppOpIfNotDefault();

    /**
     * @return If the permission can be granted
     */
    public abstract boolean canBeGranted();
}
+8 −0
Original line number Original line Diff line number Diff line
@@ -27,6 +27,14 @@
          "exclude-annotation": "androidx.test.filters.FlakyTest"
          "exclude-annotation": "androidx.test.filters.FlakyTest"
        }
        }
      ]
      ]
    },
    {
      "name": "CtsPermission2TestCases",
      "options": [
        {
          "include-filter": "android.permission2.cts.RestrictedPermissionsTest"
        }
      ]
    }
    }
  ],
  ],
  "postsubmit": [
  "postsubmit": [