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

Commit 0ac141c3 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add global app op restrictions" into sc-dev

parents 69e2f6a7 1d096f20
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -209,4 +209,10 @@ public abstract class AppOpsManagerInternal {
     */
    public abstract void setModeFromPermissionPolicy(int code, int uid, @NonNull String packageName,
            int mode, @Nullable IAppOpsCallback callback);


    /**
     * Sets a global restriction on an op code.
     */
    public abstract void setGlobalRestriction(int code, boolean restricted, IBinder token);
}
+1 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ interface IAppOpsService {

    void setUserRestrictions(in Bundle restrictions, IBinder token, int userHandle);
    void setUserRestriction(int code, boolean restricted, IBinder token, int userHandle, in PackageTagsList excludedPackageTags);

    void removeUser(int userHandle);

    void startWatchingActive(in int[] ops, IAppOpsActiveCallback callback);
+38 −27
Original line number Diff line number Diff line
@@ -28,7 +28,6 @@ import static android.app.AppOpsManager.OP_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_CAMERA;
import static android.app.AppOpsManager.OP_PHONE_CALL_MICROPHONE;
import static android.app.AppOpsManager.OP_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_RECORD_AUDIO_HOTWORD;
import static android.content.Intent.EXTRA_PACKAGE_NAME;
import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -47,6 +46,7 @@ import android.app.ActivityManagerInternal;
import android.app.ActivityOptions;
import android.app.ActivityTaskManager;
import android.app.AppOpsManager;
import android.app.AppOpsManagerInternal;
import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -163,6 +163,7 @@ public final class SensorPrivacyService extends SystemService {
    private final ActivityManagerInternal mActivityManagerInternal;
    private final ActivityTaskManager mActivityTaskManager;
    private final AppOpsManager mAppOpsManager;
    private final AppOpsManagerInternal mAppOpsManagerInternal;
    private final TelephonyManager mTelephonyManager;

    private final IBinder mAppOpsRestrictionToken = new Binder();
@@ -172,16 +173,18 @@ public final class SensorPrivacyService extends SystemService {
    private EmergencyCallHelper mEmergencyCallHelper;
    private KeyguardManager mKeyguardManager;

    private int mCurrentUser = -1;

    public SensorPrivacyService(Context context) {
        super(context);
        mContext = context;
        mAppOpsManager = context.getSystemService(AppOpsManager.class);
        mAppOpsManagerInternal = getLocalService(AppOpsManagerInternal.class);
        mUserManagerInternal = getLocalService(UserManagerInternal.class);
        mActivityManager = context.getSystemService(ActivityManager.class);
        mActivityManagerInternal = getLocalService(ActivityManagerInternal.class);
        mActivityTaskManager = context.getSystemService(ActivityTaskManager.class);
        mTelephonyManager = context.getSystemService(TelephonyManager.class);

        mSensorPrivacyServiceImpl = new SensorPrivacyServiceImpl();
    }

@@ -201,6 +204,20 @@ public final class SensorPrivacyService extends SystemService {
        }
    }

    @Override
    public void onUserStarting(TargetUser user) {
        if (mCurrentUser == -1) {
            mCurrentUser = user.getUserIdentifier();
            setGlobalRestriction();
        }
    }

    @Override
    public void onUserSwitching(TargetUser from, TargetUser to) {
        mCurrentUser = to.getUserIdentifier();
        setGlobalRestriction();
    }

    class SensorPrivacyServiceImpl extends ISensorPrivacyManager.Stub implements
            AppOpsManager.OnOpNotedListener, AppOpsManager.OnOpStartedListener,
            IBinder.DeathRecipient, UserManagerInternal.UserRestrictionsListener {
@@ -262,17 +279,6 @@ public final class SensorPrivacyService extends SystemService {
                if (readPersistedSensorPrivacyStateLocked()) {
                    persistSensorPrivacyStateLocked();
                }

                for (int i = 0; i < mIndividualEnabled.size(); i++) {
                    int userId = mIndividualEnabled.keyAt(i);
                    SparseBooleanArray userIndividualEnabled =
                            mIndividualEnabled.valueAt(i);
                    for (int j = 0; j < userIndividualEnabled.size(); j++) {
                        int sensor = userIndividualEnabled.keyAt(j);
                        boolean enabled = userIndividualEnabled.valueAt(j);
                        setUserRestriction(userId, sensor, enabled);
                    }
                }
            }

            int[] micAndCameraOps = new int[]{OP_RECORD_AUDIO, OP_PHONE_CALL_MICROPHONE,
@@ -1379,7 +1385,10 @@ public final class SensorPrivacyService extends SystemService {
            SparseArray<RemoteCallbackList<ISensorPrivacyListener>> listenersForUser =
                    mIndividualSensorListeners.get(userId);

            setUserRestriction(userId, sensor, enabled);
            setGlobalRestriction();
            if (userId == mCurrentUser) {
                setGlobalRestriction();
            }

            if (listenersForUser == null) {
                return;
@@ -1408,16 +1417,18 @@ public final class SensorPrivacyService extends SystemService {
        }
    }

    private void setUserRestriction(int userId, int sensor, boolean enabled) {
        if (sensor == CAMERA) {
            mAppOpsManager.setUserRestrictionForUser(OP_CAMERA, enabled,
                    mAppOpsRestrictionToken, null, userId);
        } else if (sensor == MICROPHONE) {
            mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO, enabled,
                    mAppOpsRestrictionToken, null, userId);
            mAppOpsManager.setUserRestrictionForUser(OP_RECORD_AUDIO_HOTWORD, enabled,
                    mAppOpsRestrictionToken, null, userId);
        }
    private void setGlobalRestriction() {
        boolean camState =
                mSensorPrivacyServiceImpl
                        .isIndividualSensorPrivacyEnabled(mCurrentUser, CAMERA);
        boolean micState =
                mSensorPrivacyServiceImpl
                        .isIndividualSensorPrivacyEnabled(mCurrentUser, MICROPHONE);

        mAppOpsManagerInternal
                .setGlobalRestriction(OP_CAMERA, camState, mAppOpsRestrictionToken);
        mAppOpsManagerInternal
                .setGlobalRestriction(OP_RECORD_AUDIO, micState, mAppOpsRestrictionToken);
    }

    private final class DeathRecipient implements IBinder.DeathRecipient {
@@ -1535,7 +1546,7 @@ public final class SensorPrivacyService extends SystemService {
    }

    private class EmergencyCallHelper {
        private OutogingEmergencyStateCallback mEmergencyStateCallback;
        private OutgoingEmergencyStateCallback mEmergencyStateCallback;
        private CallStateCallback mCallStateCallback;

        private boolean mIsInEmergencyCall;
@@ -1544,7 +1555,7 @@ public final class SensorPrivacyService extends SystemService {
        private Object mEmergencyStateLock = new Object();

        EmergencyCallHelper() {
            mEmergencyStateCallback = new OutogingEmergencyStateCallback();
            mEmergencyStateCallback = new OutgoingEmergencyStateCallback();
            mCallStateCallback = new CallStateCallback();

            mTelephonyManager.registerTelephonyCallback(FgThread.getExecutor(),
@@ -1559,7 +1570,7 @@ public final class SensorPrivacyService extends SystemService {
            }
        }

        private class OutogingEmergencyStateCallback extends TelephonyCallback implements
        private class OutgoingEmergencyStateCallback extends TelephonyCallback implements
                TelephonyCallback.OutgoingEmergencyCallListener {
            @Override
            public void onOutgoingEmergencyCall(EmergencyNumber placedEmergencyNumber,
+119 −9
Original line number Diff line number Diff line
@@ -338,7 +338,14 @@ public class AppOpsService extends IAppOpsService.Stub {
    /*
     * These are app op restrictions imposed per user from various parties.
     */
    private final ArrayMap<IBinder, ClientRestrictionState> mOpUserRestrictions = new ArrayMap<>();
    private final ArrayMap<IBinder, ClientUserRestrictionState> mOpUserRestrictions =
            new ArrayMap<>();

    /*
     * These are app op restrictions imposed globally from various parties within the system.
     */
    private final ArrayMap<IBinder, ClientGlobalRestrictionState> mOpGlobalRestrictions =
            new ArrayMap<>();

    SparseIntArray mProfileOwners;

@@ -4722,13 +4729,22 @@ public class AppOpsService extends IAppOpsService.Stub {

    private boolean isOpRestrictedLocked(int uid, int code, String packageName,
            String attributionTag, @Nullable RestrictionBypass appBypass) {
        int restrictionSetCount = mOpGlobalRestrictions.size();

        for (int i = 0; i < restrictionSetCount; i++) {
            ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
            if (restrictionState.hasRestriction(code)) {
                return true;
            }
        }

        int userHandle = UserHandle.getUserId(uid);
        final int restrictionSetCount = mOpUserRestrictions.size();
        restrictionSetCount = mOpUserRestrictions.size();

        for (int i = 0; i < restrictionSetCount; i++) {
            // For each client, check that the given op is not restricted, or that the given
            // package is exempt from the restriction.
            ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
            ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
            if (restrictionState.hasRestriction(code, packageName, attributionTag, userHandle)) {
                RestrictionBypass opBypass = opAllowSystemBypassRestriction(code);
                if (opBypass != null) {
@@ -6295,10 +6311,31 @@ public class AppOpsService extends IAppOpsService.Stub {
                pw.println();
            }

            final int globalRestrictionCount = mOpGlobalRestrictions.size();
            for (int i = 0; i < globalRestrictionCount; i++) {
                IBinder token = mOpGlobalRestrictions.keyAt(i);
                ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.valueAt(i);
                ArraySet<Integer> restrictedOps = restrictionState.mRestrictedOps;

                pw.println("  Global restrictions for token " + token + ":");
                StringBuilder restrictedOpsValue = new StringBuilder();
                restrictedOpsValue.append("[");
                final int restrictedOpCount = restrictedOps.size();
                for (int j = 0; j < restrictedOpCount; j++) {
                    if (restrictedOpsValue.length() > 1) {
                        restrictedOpsValue.append(", ");
                    }
                    restrictedOpsValue.append(AppOpsManager.opToName(restrictedOps.valueAt(j)));
                }
                restrictedOpsValue.append("]");
                pw.println("      Restricted ops: " + restrictedOpsValue);

            }

            final int userRestrictionCount = mOpUserRestrictions.size();
            for (int i = 0; i < userRestrictionCount; i++) {
                IBinder token = mOpUserRestrictions.keyAt(i);
                ClientRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
                ClientUserRestrictionState restrictionState = mOpUserRestrictions.valueAt(i);
                boolean printedTokenHeader = false;

                if (dumpMode >= 0 || dumpWatchers || dumpHistory) {
@@ -6444,11 +6481,11 @@ public class AppOpsService extends IAppOpsService.Stub {
    private void setUserRestrictionNoCheck(int code, boolean restricted, IBinder token,
            int userHandle, PackageTagsList excludedPackageTags) {
        synchronized (AppOpsService.this) {
            ClientRestrictionState restrictionState = mOpUserRestrictions.get(token);
            ClientUserRestrictionState restrictionState = mOpUserRestrictions.get(token);

            if (restrictionState == null) {
                try {
                    restrictionState = new ClientRestrictionState(token);
                    restrictionState = new ClientUserRestrictionState(token);
                } catch (RemoteException e) {
                    return;
                }
@@ -6528,7 +6565,7 @@ public class AppOpsService extends IAppOpsService.Stub {
        synchronized (AppOpsService.this) {
            final int tokenCount = mOpUserRestrictions.size();
            for (int i = tokenCount - 1; i >= 0; i--) {
                ClientRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
                ClientUserRestrictionState opRestrictions = mOpUserRestrictions.valueAt(i);
                opRestrictions.removeUser(userHandle);
            }
            removeUidsForUserLocked(userHandle);
@@ -6986,12 +7023,12 @@ public class AppOpsService extends IAppOpsService.Stub {
        return packageNames;
    }

    private final class ClientRestrictionState implements DeathRecipient {
    private final class ClientUserRestrictionState implements DeathRecipient {
        private final IBinder token;
        SparseArray<boolean[]> perUserRestrictions;
        SparseArray<PackageTagsList> perUserExcludedPackageTags;

        public ClientRestrictionState(IBinder token)
        ClientUserRestrictionState(IBinder token)
                throws RemoteException {
            token.linkToDeath(this, 0);
            this.token = token;
@@ -7082,6 +7119,7 @@ public class AppOpsService extends IAppOpsService.Stub {
            if (perUserExclusions == null) {
                return true;
            }

            return !perUserExclusions.contains(packageName, attributionTag);
        }

@@ -7143,6 +7181,42 @@ public class AppOpsService extends IAppOpsService.Stub {
        }
    }

    private final class ClientGlobalRestrictionState implements DeathRecipient {
        final IBinder mToken;
        final ArraySet<Integer> mRestrictedOps = new ArraySet<>();

        ClientGlobalRestrictionState(IBinder token)
                throws RemoteException {
            token.linkToDeath(this, 0);
            this.mToken = token;
        }

        boolean setRestriction(int code, boolean restricted) {
            if (restricted) {
                return mRestrictedOps.add(code);
            } else {
                return mRestrictedOps.remove(code);
            }
        }

        boolean hasRestriction(int code) {
            return mRestrictedOps.contains(code);
        }

        boolean isDefault() {
            return mRestrictedOps.isEmpty();
        }

        @Override
        public void binderDied() {
            destroy();
        }

        void destroy() {
            mToken.unlinkToDeath(this, 0);
        }
    }

    private final class AppOpsManagerInternalImpl extends AppOpsManagerInternal {
        @Override public void setDeviceAndProfileOwners(SparseIntArray owners) {
            synchronized (AppOpsService.this) {
@@ -7167,6 +7241,42 @@ public class AppOpsService extends IAppOpsService.Stub {
                int mode, @Nullable IAppOpsCallback callback) {
            setMode(code, uid, packageName, mode, callback);
        }


        @Override
        public void setGlobalRestriction(int code, boolean restricted, IBinder token) {
            if (Binder.getCallingPid() != Process.myPid()) {
                // TODO instead of this enforcement put in AppOpsManagerInternal
                throw new SecurityException("Only the system can set global restrictions");
            }

            synchronized (AppOpsService.this) {
                ClientGlobalRestrictionState restrictionState = mOpGlobalRestrictions.get(token);

                if (restrictionState == null) {
                    try {
                        restrictionState = new ClientGlobalRestrictionState(token);
                    } catch (RemoteException  e) {
                        return;
                    }
                    mOpGlobalRestrictions.put(token, restrictionState);
                }

                if (restrictionState.setRestriction(code, restricted)) {
                    mHandler.sendMessage(PooledLambda.obtainMessage(
                            AppOpsService::notifyWatchersOfChange, AppOpsService.this, code,
                            UID_ANY));
                    mHandler.sendMessage(PooledLambda.obtainMessage(
                            AppOpsService::updateStartedOpModeForUser, AppOpsService.this,
                            code, restricted, UserHandle.USER_ALL));
                }

                if (restrictionState.isDefault()) {
                    mOpGlobalRestrictions.remove(token);
                    restrictionState.destroy();
                }
            }
        }
    }

    /**