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

Commit d1224a90 authored by Jing Ji's avatar Jing Ji Committed by Android (Google) Code Review
Browse files

Merge changes from topics "presubmit-am-cd22d6400493475a97208d8e6980896b",...

Merge changes from topics "presubmit-am-cd22d6400493475a97208d8e6980896b", "presubmit-am-d70f1b45fe9f4623abc8ce60634bd0c9" into tm-dev

* changes:
  Add exemptions for the apps with the camera/mic permissions granted
  Add bg exemption tracks for foreground only permissions
parents 6d26abc3 92663599
Loading
Loading
Loading
Loading
+319 −43
Original line number Diff line number Diff line
@@ -17,6 +17,14 @@
package com.android.server.am;

import static android.Manifest.permission.ACCESS_FINE_LOCATION;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.RECORD_AUDIO;
import static android.app.AppOpsManager.OPSTR_CAMERA;
import static android.app.AppOpsManager.OPSTR_FINE_LOCATION;
import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO;
import static android.app.AppOpsManager.OP_NONE;
import static android.app.AppOpsManager.opToPublicName;
import static android.app.AppOpsManager.strOpToOp;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.os.Process.SYSTEM_UID;

@@ -27,28 +35,37 @@ import static com.android.server.am.AppRestrictionController.DEVICE_CONFIG_SUBNA
import static com.android.server.am.BaseAppStateTracker.STATE_TYPE_PERMISSION;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager.OnPermissionsChangedListener;
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.Message;
import android.os.RemoteException;
import android.os.SystemClock;
import android.os.UserHandle;
import android.permission.PermissionManager;
import android.provider.DeviceConfig;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.app.IAppOpsCallback;
import com.android.internal.app.IAppOpsService;
import com.android.server.am.AppPermissionTracker.AppPermissionPolicy;
import com.android.server.pm.permission.PermissionManagerServiceInternal;

import java.io.PrintWriter;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * The tracker for monitoring selected permission state of apps.
@@ -61,8 +78,17 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy

    private final MyHandler mHandler;

    /**
     * Keep a new instance of callback for each appop we're monitoring,
     * as the AppOpsService doesn't support monitoring multiple appops with single callback
     * instance (except the ALL_OPS case).
     */
    @GuardedBy("mAppOpsCallbacks")
    private final SparseArray<MyAppOpsCallback> mAppOpsCallbacks = new SparseArray<>();

    @GuardedBy("mLock")
    private SparseArray<ArraySet<String>> mUidGrantedPermissionsInMonitor = new SparseArray<>();
    private SparseArray<ArraySet<UidGrantedPermissionState>> mUidGrantedPermissionsInMonitor =
            new SparseArray<>();

    private volatile boolean mLockedBootCompleted = false;

@@ -82,12 +108,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
        mHandler.obtainMessage(MyHandler.MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
    }

    private void handleAppOpsInit() {
        final ArrayList<Integer> ops = new ArrayList<>();
        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        for (int i = 0; i < permissions.length; i++) {
            final Pair<String, Integer> pair = permissions[i];
            if (pair.second != OP_NONE) {
                ops.add(pair.second);
            }
        }
        startWatchingMode(ops.toArray(new Integer[ops.size()]));
    }

    private void handlePermissionsInit() {
        final int[] allUsers = mInjector.getUserManagerInternal().getUserIds();
        final PackageManagerInternal pmi = mInjector.getPackageManagerInternal();
        final PermissionManagerServiceInternal pm = mInjector.getPermissionManagerServiceInternal();
        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
                mUidGrantedPermissionsInMonitor;
        for (int userId : allUsers) {
            final List<ApplicationInfo> apps = pmi.getInstalledApplications(0, userId, SYSTEM_UID);
            if (apps == null) {
@@ -96,33 +135,44 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
            final long now = SystemClock.elapsedRealtime();
            for (int i = 0, size = apps.size(); i < size; i++) {
                final ApplicationInfo ai = apps.get(i);
                for (String permission : permissions) {
                    if (pm.checkUidPermission(ai.uid, permission) != PERMISSION_GRANTED) {
                for (Pair<String, Integer> permission : permissions) {
                    final UidGrantedPermissionState state = new UidGrantedPermissionState(
                            ai.uid, permission.first, permission.second);
                    if (!state.isGranted()) {
                        // No need to track it.
                        continue;
                    }
                    synchronized (mLock) {
                        ArraySet<String> grantedPermissions = uidPerms.get(ai.uid);
                        ArraySet<UidGrantedPermissionState> grantedPermissions =
                                uidPerms.get(ai.uid);
                        if (grantedPermissions == null) {
                            grantedPermissions = new ArraySet<String>();
                            grantedPermissions = new ArraySet<UidGrantedPermissionState>();
                            uidPerms.put(ai.uid, grantedPermissions);
                        }
                        grantedPermissions.add(permission);
                            // This UID has at least one active permission-in-interest now,
                            // let the listeners know.
                            notifyListenersOnStateChange(ai.uid, DEFAULT_NAME, true, now,
                                    STATE_TYPE_PERMISSION);
                        }
                        grantedPermissions.add(state);
                    }
                }
            }
        }
    }

    private void handleAppOpsDestroy() {
        stopWatchingMode();
    }

    private void handlePermissionsDestroy() {
        synchronized (mLock) {
            final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
            final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
                    mUidGrantedPermissionsInMonitor;
            final long now = SystemClock.elapsedRealtime();
            for (int i = 0, size = uidPerms.size(); i < size; i++) {
                final int uid = uidPerms.keyAt(i);
                final ArraySet<String> grantedPermissions = uidPerms.valueAt(i);
                for (int j = 0, numOfPerms = grantedPermissions.size(); j < numOfPerms; j++) {
                final ArraySet<UidGrantedPermissionState> grantedPermissions = uidPerms.valueAt(i);
                if (grantedPermissions.size() > 0) {
                    notifyListenersOnStateChange(uid, DEFAULT_NAME, false, now,
                            STATE_TYPE_PERMISSION);
                }
@@ -131,44 +181,78 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
        }
    }

    private void handleOpChanged(int op, int uid, String packageName) {
        if (DEBUG_PERMISSION_TRACKER) {
            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
            try {
                final int mode = appOpsService.checkOperation(op, uid, packageName);
                Slog.i(TAG, "onOpChanged: " + opToPublicName(op)
                        + " " + UserHandle.formatUid(uid)
                        + " " + packageName + " " + mode);
            } catch (RemoteException e) {
                // Intra-process call, should never happen.
            }
        }
        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        if (permissions != null && permissions.length > 0) {
            for (int i = 0; i < permissions.length; i++) {
                final Pair<String, Integer> pair = permissions[i];
                if (pair.second != op) {
                    continue;
                }
                final UidGrantedPermissionState state =
                        new UidGrantedPermissionState(uid, pair.first, op);
                synchronized (mLock) {
                    handlePermissionsChangedLocked(uid, new UidGrantedPermissionState[] {state});
                }
                break;
            }
        }
    }

    private void handlePermissionsChanged(int uid) {
        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        if (DEBUG_PERMISSION_TRACKER) {
            Slog.i(TAG, "handlePermissionsChanged " + UserHandle.formatUid(uid));
        }
        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        if (permissions != null && permissions.length > 0) {
            final PermissionManagerServiceInternal pm =
                    mInjector.getPermissionManagerServiceInternal();
            final boolean[] states = new boolean[permissions.length];
            final UidGrantedPermissionState[] states =
                    new UidGrantedPermissionState[permissions.length];
            for (int i = 0; i < permissions.length; i++) {
                states[i] = pm.checkUidPermission(uid, permissions[i]) == PERMISSION_GRANTED;
                final Pair<String, Integer> pair = permissions[i];
                states[i] = new UidGrantedPermissionState(uid, pair.first, pair.second);
                if (DEBUG_PERMISSION_TRACKER) {
                    Slog.i(TAG, UserHandle.formatUid(uid) + " " + permissions[i] + "=" + states[i]);
                    Slog.i(TAG, states[i].toString());
                }
            }
            synchronized (mLock) {
                handlePermissionsChangedLocked(uid, permissions, states);
                handlePermissionsChangedLocked(uid, states);
            }
        }
    }

    @GuardedBy("mLock")
    private void handlePermissionsChangedLocked(int uid, String[] permissions, boolean[] states) {
    private void handlePermissionsChangedLocked(int uid, UidGrantedPermissionState[] states) {
        final int index = mUidGrantedPermissionsInMonitor.indexOfKey(uid);
        ArraySet<String> grantedPermissions = index >= 0
        ArraySet<UidGrantedPermissionState> grantedPermissions = index >= 0
                ? mUidGrantedPermissionsInMonitor.valueAt(index) : null;
        final long now = SystemClock.elapsedRealtime();
        for (int i = 0; i < permissions.length; i++) {
            final String permission = permissions[i];
            final boolean granted = states[i];
        for (int i = 0; i < states.length; i++) {
            final boolean granted = states[i].isGranted();
            boolean changed = false;
            if (granted) {
                if (grantedPermissions == null) {
                    grantedPermissions = new ArraySet<>();
                    mUidGrantedPermissionsInMonitor.put(uid, grantedPermissions);
                    changed = true;
                }
                changed = grantedPermissions.add(permission);
            } else if (grantedPermissions != null) {
                changed = grantedPermissions.remove(permission);
                if (grantedPermissions.isEmpty()) {
                grantedPermissions.add(states[i]);
            } else if (grantedPermissions != null && !grantedPermissions.isEmpty()) {
                if (grantedPermissions.remove(states[i]) && grantedPermissions.isEmpty()) {
                    mUidGrantedPermissionsInMonitor.removeAt(index);
                    changed = true;
                }
            }
            if (changed) {
@@ -178,10 +262,141 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
        }
    }

    /**
     * Represents the grant state of a permission + appop of the given UID.
     */
    private class UidGrantedPermissionState {
        final int mUid;
        final @Nullable String mPermission;
        final int mAppOp;

        private boolean mPermissionGranted;
        private boolean mAppOpAllowed;

        UidGrantedPermissionState(int uid, @Nullable String permission, int appOp) {
            mUid = uid;
            mPermission = permission;
            mAppOp = appOp;
            updatePermissionState();
            updateAppOps();
        }

        void updatePermissionState() {
            if (TextUtils.isEmpty(mPermission)) {
                mPermissionGranted = true;
                return;
            }
            mPermissionGranted = mInjector.getPermissionManagerServiceInternal()
                    .checkUidPermission(mUid, mPermission) == PERMISSION_GRANTED;
        }

        void updateAppOps() {
            if (mAppOp == OP_NONE) {
                mAppOpAllowed = true;
                return;
            }
            final String[] packages = mInjector.getPackageManager().getPackagesForUid(mUid);
            if (packages != null) {
                final IAppOpsService appOpsService = mInjector.getIAppOpsService();
                for (String pkg : packages) {
                    try {
                        final int mode = appOpsService.checkOperation(mAppOp, mUid, pkg);
                        if (mode == AppOpsManager.MODE_ALLOWED) {
                            mAppOpAllowed = true;
                            return;
                        }
                    } catch (RemoteException e) {
                        // Intra-process call, should never happen.
                    }
                }
            }
            mAppOpAllowed = false;
        }

        boolean isGranted() {
            return mPermissionGranted && mAppOpAllowed;
        }

        @Override
        public boolean equals(Object other) {
            if (other == null || !(other instanceof UidGrantedPermissionState)) {
                return false;
            }
            final UidGrantedPermissionState otherState = (UidGrantedPermissionState) other;
            return mUid == otherState.mUid && mAppOp == otherState.mAppOp
                    && Objects.equals(mPermission, otherState.mPermission);
        }

        @Override
        public int hashCode() {
            return (Integer.hashCode(mUid) * 31 + Integer.hashCode(mAppOp)) * 31
                    + (mPermission == null ? 0 : mPermission.hashCode());
        }

        @Override
        public String toString() {
            String s = "UidGrantedPermissionState{"
                    + System.identityHashCode(this) + " "
                    + UserHandle.formatUid(mUid) + ": ";
            final boolean emptyPermissionName = TextUtils.isEmpty(mPermission);
            if (!emptyPermissionName) {
                s += mPermission + "=" + mPermissionGranted;
            }
            if (mAppOp != OP_NONE) {
                if (!emptyPermissionName) {
                    s += ",";
                }
                s += opToPublicName(mAppOp) + "=" + mAppOpAllowed;
            }
            s += "}";
            return s;
        }
    }

    private void startWatchingMode(@NonNull Integer[] ops) {
        synchronized (mAppOpsCallbacks) {
            stopWatchingMode();
            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
            try {
                for (int op: ops) {
                    final MyAppOpsCallback cb = new MyAppOpsCallback();
                    mAppOpsCallbacks.put(op, cb);
                    appOpsService.startWatchingModeWithFlags(op, null,
                            AppOpsManager.WATCH_FOREGROUND_CHANGES, cb);
                }
            } catch (RemoteException e) {
                // Intra-process call, should never happen.
            }
        }
    }

    private void stopWatchingMode() {
        synchronized (mAppOpsCallbacks) {
            final IAppOpsService appOpsService = mInjector.getIAppOpsService();
            for (int i = mAppOpsCallbacks.size() - 1; i >= 0; i--) {
                try {
                    appOpsService.stopWatchingMode(mAppOpsCallbacks.valueAt(i));
                } catch (RemoteException e) {
                    // Intra-process call, should never happen.
                }
            }
            mAppOpsCallbacks.clear();
        }
    }

    private class MyAppOpsCallback extends IAppOpsCallback.Stub {
        @Override
        public void opChanged(int op, int uid, String packageName) {
            mHandler.obtainMessage(MyHandler.MSG_APPOPS_CHANGED, op, uid, packageName)
                    .sendToTarget();
        }
    }

    private static class MyHandler extends Handler {
        static final int MSG_PERMISSIONS_INIT = 0;
        static final int MSG_PERMISSIONS_DESTROY = 1;
        static final int MSG_PERMISSIONS_CHANGED = 2;
        static final int MSG_APPOPS_CHANGED = 3;

        private @NonNull AppPermissionTracker mTracker;

@@ -194,14 +409,19 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_PERMISSIONS_INIT:
                    mTracker.handleAppOpsInit();
                    mTracker.handlePermissionsInit();
                    break;
                case MSG_PERMISSIONS_DESTROY:
                    mTracker.handlePermissionsDestroy();
                    mTracker.handleAppOpsDestroy();
                    break;
                case MSG_PERMISSIONS_CHANGED:
                    mTracker.handlePermissionsChanged(msg.arg1);
                    break;
                case MSG_APPOPS_CHANGED:
                    mTracker.handleOpChanged(msg.arg1, msg.arg2, (String) msg.obj);
                    break;
            }
        }
    }
@@ -231,25 +451,41 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
    void dump(PrintWriter pw, String prefix) {
        pw.print(prefix);
        pw.println("APP PERMISSIONS TRACKER:");
        final String[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        final Pair[] permissions = mInjector.getPolicy().getBgPermissionsInMonitor();
        final String prefixMore = "  " + prefix;
        final String prefixMoreMore = "  " + prefixMore;
        for (String permission : permissions) {
        for (Pair<String, Integer> permission : permissions) {
            pw.print(prefixMore);
            pw.print(permission);
            final boolean emptyPermissionName = TextUtils.isEmpty(permission.first);
            if (!emptyPermissionName) {
                pw.print(permission.first);
            }
            if (permission.second != OP_NONE) {
                if (!emptyPermissionName) {
                    pw.print('+');
                }
                pw.print(opToPublicName(permission.second));
            }
            pw.println(':');
            synchronized (mLock) {
                final SparseArray<ArraySet<String>> uidPerms = mUidGrantedPermissionsInMonitor;
                final SparseArray<ArraySet<UidGrantedPermissionState>> uidPerms =
                        mUidGrantedPermissionsInMonitor;
                pw.print(prefixMoreMore);
                pw.print('[');
                boolean needDelimiter = false;
                for (int i = 0, size = uidPerms.size(); i < size; i++) {
                    if (uidPerms.valueAt(i).contains(permission)) {
                    final ArraySet<UidGrantedPermissionState> uidPerm = uidPerms.valueAt(i);
                    for (int j = uidPerm.size() - 1; j >= 0; j--) {
                        final UidGrantedPermissionState state = uidPerm.valueAt(j);
                        if (state.mAppOp == permission.second
                                && TextUtils.equals(state.mPermission, permission.first)) {
                            if (needDelimiter) {
                                pw.print(',');
                            }
                            needDelimiter = true;
                        pw.print(UserHandle.formatUid(uidPerms.keyAt(i)));
                            pw.print(UserHandle.formatUid(state.mUid));
                            break;
                        }
                    }
                }
                pw.println(']');
@@ -277,20 +513,25 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
        static final boolean DEFAULT_BG_PERMISSION_MONITOR_ENABLED = true;

        /**
         * Default value to {@link #mBgPermissionsInMonitor}.
         * Default value to {@link #mBgPermissionsInMonitor}, it comes in pair;
         * the first string strings in the pair is the permission name, and the second string
         * is the appops name, if they are associated.
         */
        static final String[] DEFAULT_BG_PERMISSIONS_IN_MONITOR = new String[] {
            ACCESS_FINE_LOCATION,
            ACCESS_FINE_LOCATION, OPSTR_FINE_LOCATION,
            CAMERA, OPSTR_CAMERA,
            RECORD_AUDIO, OPSTR_RECORD_AUDIO,
        };

        /**
         * @see #KEY_BG_PERMISSIONS_IN_MONITOR.
         */
        volatile String[] mBgPermissionsInMonitor = DEFAULT_BG_PERMISSIONS_IN_MONITOR;
        volatile @NonNull Pair[] mBgPermissionsInMonitor;

        AppPermissionPolicy(@NonNull Injector injector, @NonNull AppPermissionTracker tracker) {
            super(injector, tracker, KEY_BG_PERMISSION_MONITOR_ENABLED,
                    DEFAULT_BG_PERMISSION_MONITOR_ENABLED);
            mBgPermissionsInMonitor = parsePermissionConfig(DEFAULT_BG_PERMISSIONS_IN_MONITOR);
        }

        @Override
@@ -311,17 +552,38 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
            }
        }

        String[] getBgPermissionsInMonitor() {
        Pair[] getBgPermissionsInMonitor() {
            return mBgPermissionsInMonitor;
        }

        private @NonNull Pair[] parsePermissionConfig(@NonNull String[] perms) {
            final Pair[] result = new Pair[perms.length / 2];
            for (int i = 0, j = 0; i < perms.length; i += 2, j++) {
                try {
                    result[j] = Pair.create(TextUtils.isEmpty(perms[i]) ? null : perms[i],
                            TextUtils.isEmpty(perms[i + 1]) ? OP_NONE : strOpToOp(perms[i + 1]));
                } catch (Exception e) {
                    // Ignore.
                }
            }
            return result;
        }

        private void updateBgPermissionsInMonitor() {
            final String config = DeviceConfig.getString(
                    DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                    KEY_BG_PERMISSIONS_IN_MONITOR,
                    null);
            mBgPermissionsInMonitor = config != null
                    ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR;
            final Pair[] newPermsInMonitor = parsePermissionConfig(
                    config != null ? config.split(",") : DEFAULT_BG_PERMISSIONS_IN_MONITOR);
            if (!Arrays.equals(mBgPermissionsInMonitor, newPermsInMonitor)) {
                mBgPermissionsInMonitor = newPermsInMonitor;
                if (isEnabled()) {
                    // Trigger a reload.
                    onTrackerEnabled(false);
                    onTrackerEnabled(true);
                }
            }
        }

        @Override
@@ -338,7 +600,21 @@ final class AppPermissionTracker extends BaseAppStateTracker<AppPermissionPolicy
            pw.print(prefix);
            pw.print(KEY_BG_PERMISSIONS_IN_MONITOR);
            pw.print('=');
            pw.println(Arrays.toString(mBgPermissionsInMonitor));
            pw.print('[');
            for (int i = 0; i < mBgPermissionsInMonitor.length; i++) {
                if (i > 0) {
                    pw.print(',');
                }
                final Pair<String, Integer> pair = mBgPermissionsInMonitor[i];
                if (pair.first != null) {
                    pw.print(pair.first);
                }
                pw.print(',');
                if (pair.second != OP_NONE) {
                    pw.print(opToPublicName(pair.second));
                }
            }
            pw.println(']');
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -33,10 +33,12 @@ import android.media.session.MediaSessionManager;
import android.os.BatteryManagerInternal;
import android.os.BatteryStatsInternal;
import android.os.Handler;
import android.os.ServiceManager;
import android.permission.PermissionManager;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.app.IAppOpsService;
import com.android.server.DeviceIdleInternal;
import com.android.server.LocalServices;
import com.android.server.notification.NotificationManagerInternal;
@@ -270,6 +272,7 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
        MediaSessionManager mMediaSessionManager;
        RoleManager mRoleManager;
        NotificationManagerInternal mNotificationManagerInternal;
        IAppOpsService mIAppOpsService;

        void setPolicy(T policy) {
            mAppStatePolicy = policy;
@@ -292,6 +295,8 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
            mRoleManager = context.getSystemService(RoleManager.class);
            mNotificationManagerInternal = LocalServices.getService(
                    NotificationManagerInternal.class);
            mIAppOpsService = IAppOpsService.Stub.asInterface(
                    ServiceManager.getService(Context.APP_OPS_SERVICE));

            getPolicy().onSystemReady();
        }
@@ -362,5 +367,9 @@ public abstract class BaseAppStateTracker<T extends BaseAppStatePolicy> {
        NotificationManagerInternal getNotificationManagerInternal() {
            return mNotificationManagerInternal;
        }

        IAppOpsService getIAppOpsService() {
            return mIAppOpsService;
        }
    }
}
+7 −0

File changed.

Preview size limit exceeded, changes collapsed.