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

Commit 7891b3de authored by Ruben Brunk's avatar Ruben Brunk Committed by android-build-merger
Browse files

Merge "Set notification listener defaults for system VrListeners." into nyc-dev

am: aaabcce6

* commit 'aaabcce6':
  Set notification listener defaults for system VrListeners.

Change-Id: Ibf5fba963d1b5aa21af016544ee9bb6aebccac1e
parents 5c0c8a6b aaabcce6
Loading
Loading
Loading
Loading
+132 −75
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
package com.android.server.vr;

import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
@@ -47,6 +48,7 @@ import android.service.vr.IVrStateCallbacks;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;

import com.android.internal.R;
import com.android.server.SystemConfig;
@@ -95,6 +97,7 @@ public class VrManagerService extends SystemService implements EnabledComponentC

    private static final int PENDING_STATE_DELAY_MS = 300;
    private static final int EVENT_LOG_SIZE = 32;
    private static final int INVALID_APPOPS_MODE = -1;

    private static native void initializeNative();
    private static native void setVrModeNative(boolean enabled);
@@ -114,12 +117,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC
    private boolean mGuard;
    private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks =
            new RemoteCallbackList<>();
    private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
    private String mPreviousNotificationPolicyAccessPackage;
    private String mPreviousCoarseLocationPackage;
    private String mPreviousManageOverlayPackage;
    private int mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
    private int mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
    private VrState mPendingState;
    private final ArrayDeque<VrState> mLoggingDeque = new ArrayDeque<>(EVENT_LOG_SIZE);
    private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();

    private static final int MSG_VR_STATE_CHANGE = 0;
    private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
@@ -193,6 +195,39 @@ public class VrManagerService extends SystemService implements EnabledComponentC
        }
    };

    private final class NotificationAccessManager {
        private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>();

        public void update(Collection<String> packageNames) {
            int currentUserId = ActivityManager.getCurrentUser();

            UserHandle currentUserHandle = new UserHandle(currentUserId);

            ArraySet<String> allowed = mAllowedPackages.get(currentUserId);
            if (allowed == null) {
                allowed = new ArraySet<>();
            }

            for (String pkg : allowed) {
                if (!packageNames.contains(pkg)) {
                    revokeNotificationListenerAccess(pkg);
                    revokeNotificationPolicyAccess(pkg);
                }
            }
            for (String pkg : packageNames) {
                if (!allowed.contains(pkg)) {
                    grantNotificationPolicyAccess(pkg);
                    grantNotificationListenerAccess(pkg, currentUserHandle);
                }
            }

            allowed.clear();
            allowed.addAll(packageNames);
            mAllowedPackages.put(currentUserId, allowed);
        }
    }


    /**
     * Called when a user, package, or setting changes that could affect whether or not the
     * currently bound VrListenerService is changed.
@@ -200,6 +235,20 @@ public class VrManagerService extends SystemService implements EnabledComponentC
    @Override
    public void onEnabledComponentChanged() {
        synchronized (mLock) {
            int currentUser = ActivityManager.getCurrentUser();

            // Update listeners
            ArraySet<ComponentName> enabledListeners = mComponentObserver.getEnabled(currentUser);

            ArraySet<String> enabledPackages = new ArraySet<>();
            for (ComponentName n : enabledListeners) {
                String pkg = n.getPackageName();
                if (isDefaultAllowed(pkg)) {
                    enabledPackages.add(n.getPackageName());
                }
            }
            mNotifAccessManager.update(enabledPackages);

            if (mCurrentVrService == null) {
                return; // No active services
            }
@@ -616,21 +665,18 @@ public class VrManagerService extends SystemService implements EnabledComponentC
        } catch (NameNotFoundException e) {
        }

        if (info == null) {
            Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package.");
        if (info == null || !(info.isSystemApp() || info.isUpdatedSystemApp())) {
            return;
        }

        if (!(info.isSystemApp() || info.isUpdatedSystemApp())) {
            return; // Application is not pre-installed, avoid setting implied permissions
        }

        mWasDefaultGranted = true;

        grantCoarseLocationAccess(pName, userId);
        grantOverlayAccess(pName, userId);
        grantNotificationPolicyAccess(pName);
        grantNotificationListenerAccess(pName, userId);
        AppOpsManager mgr = mContext.getSystemService(AppOpsManager.class);
        if (mgr == null) {
            Slog.e(TAG, "No AppOpsManager, failed to set permissions for: " + pName);
            return;
        }
        grantCoarseLocationAccess(mgr, pName, info.uid);
        grantOverlayAccess(mgr, pName, info.uid);
    }

    /**
@@ -657,80 +703,89 @@ public class VrManagerService extends SystemService implements EnabledComponentC

        String pName = component.getPackageName();
        if (mWasDefaultGranted) {
            revokeCoarseLocationAccess(userId);
            revokeOverlayAccess(userId);
            revokeNotificationPolicyAccess(pName);
            revokeNotificiationListenerAccess();
            ApplicationInfo info = null;
            try {
                info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA);
            } catch (NameNotFoundException e) {
            }

            if (info != null) {
                AppOpsManager mgr = mContext.getSystemService(AppOpsManager.class);
                if (mgr == null) {
                    Slog.e(TAG, "No AppOpsManager, failed to set permissions for: " + pName);
                    return;
                }
                revokeCoarseLocationAccess(mgr, pName, info.uid);
                revokeOverlayAccess(mgr, pName, info.uid);
            }
            mWasDefaultGranted = false;
        }

    }

    private void grantCoarseLocationAccess(String pkg, UserHandle userId) {
    private boolean isDefaultAllowed(String packageName) {
        PackageManager pm = mContext.getPackageManager();
        boolean prev = (PackageManager.PERMISSION_GRANTED ==
                pm.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, pkg));
        mPreviousCoarseLocationPackage = null;
        if (!prev) {
            pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION,
                    userId);
            mPreviousCoarseLocationPackage = pkg;

        ApplicationInfo info = null;
        try {
            info = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
        } catch (NameNotFoundException e) {
        }

        if (info == null || !(info.isSystemApp() || info.isUpdatedSystemApp())) {
            return false;
        }
        return true;
    }

    private void revokeCoarseLocationAccess(UserHandle userId) {
        PackageManager pm = mContext.getPackageManager();
        if (mPreviousCoarseLocationPackage != null) {
            pm.revokeRuntimePermission(mPreviousCoarseLocationPackage,
                    android.Manifest.permission.ACCESS_COARSE_LOCATION, userId);
            mPreviousCoarseLocationPackage = null;
    private void grantCoarseLocationAccess(AppOpsManager mgr, String packageName, int uid) {
        mPreviousCoarseLocationMode = mgr.checkOpNoThrow(AppOpsManager.OP_COARSE_LOCATION, uid,
                packageName);

        if (mPreviousCoarseLocationMode != AppOpsManager.MODE_ALLOWED) {
            mgr.setMode(AppOpsManager.OP_COARSE_LOCATION, uid, packageName,
                    AppOpsManager.MODE_ALLOWED);
        }
    }

    private void grantOverlayAccess(String pkg, UserHandle userId) {
        PackageManager pm = mContext.getPackageManager();
        boolean prev = (PackageManager.PERMISSION_GRANTED ==
                pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg));
        mPreviousManageOverlayPackage = null;
        if (!prev) {
            pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW,
                    userId);
            mPreviousManageOverlayPackage = pkg;
    private void revokeCoarseLocationAccess(AppOpsManager mgr, String packageName, int uid) {
        if (mPreviousCoarseLocationMode != AppOpsManager.MODE_ALLOWED) {
            mgr.setMode(AppOpsManager.OP_COARSE_LOCATION, uid, packageName,
                    mPreviousCoarseLocationMode);
            mPreviousCoarseLocationMode = INVALID_APPOPS_MODE;
        }
    }

    private void revokeOverlayAccess(UserHandle userId) {
        PackageManager pm = mContext.getPackageManager();
        if (mPreviousManageOverlayPackage != null) {
            pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
                    android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
            mPreviousManageOverlayPackage = null;
    private void grantOverlayAccess(AppOpsManager mgr, String packageName, int uid) {

        mPreviousManageOverlayMode = mgr.checkOpNoThrow(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid,
                packageName);

        if (mPreviousManageOverlayMode != AppOpsManager.MODE_ALLOWED) {
            mgr.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,
                    AppOpsManager.MODE_ALLOWED);
        }
    }

    private void revokeOverlayAccess(AppOpsManager mgr, String packageName, int uid) {
        if (mPreviousManageOverlayMode != AppOpsManager.MODE_ALLOWED) {
            mgr.setMode(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, uid, packageName,
                    mPreviousManageOverlayMode);
            mPreviousManageOverlayMode = INVALID_APPOPS_MODE;
        }
    }

    private void grantNotificationPolicyAccess(String pkg) {
        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
        boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg);
        mPreviousNotificationPolicyAccessPackage = null;
        if (!prev) {
            mPreviousNotificationPolicyAccessPackage = pkg;
        nm.setNotificationPolicyAccessGranted(pkg, true);
    }
    }

    private void revokeNotificationPolicyAccess(String pkg) {
        NotificationManager nm = mContext.getSystemService(NotificationManager.class);
        if (mPreviousNotificationPolicyAccessPackage != null) {
            if (mPreviousNotificationPolicyAccessPackage.equals(pkg)) {
        // Remove any DND zen rules possibly created by the package.
                nm.removeAutomaticZenRules(mPreviousNotificationPolicyAccessPackage);
        nm.removeAutomaticZenRules(pkg);
        // Remove Notification Policy Access.
                nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
                mPreviousNotificationPolicyAccessPackage = null;
            } else {
                Slog.e(TAG, "Couldn't remove Notification Policy Access for package: " + pkg);
            }
        }
        nm.setNotificationPolicyAccessGranted(pkg, false);
    }

    private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
@@ -742,13 +797,10 @@ public class VrManagerService extends SystemService implements EnabledComponentC

        ArraySet<String> current = getCurrentNotifListeners(resolver);

        mPreviousToggledListenerSettings.clear();

        for (ComponentName c : possibleServices) {
            String flatName = c.flattenToString();
            if (Objects.equals(c.getPackageName(), pkg)
                    && !current.contains(flatName)) {
                mPreviousToggledListenerSettings.add(flatName);
                current.add(flatName);
            }
        }
@@ -760,20 +812,25 @@ public class VrManagerService extends SystemService implements EnabledComponentC
        }
    }

    private void revokeNotificiationListenerAccess() {
        if (mPreviousToggledListenerSettings.isEmpty()) {
            return;
        }

    private void revokeNotificationListenerAccess(String pkg) {
        ContentResolver resolver = mContext.getContentResolver();
        ArraySet<String> current = getCurrentNotifListeners(resolver);

        current.removeAll(mPreviousToggledListenerSettings);
        mPreviousToggledListenerSettings.clear();
        ArrayList<String> toRemove = new ArrayList<>();

        for (String c : current) {
            ComponentName component = ComponentName.unflattenFromString(c);
            if (component.getPackageName().equals(pkg)) {
                toRemove.add(c);
            }
        }

        current.removeAll(toRemove);

        String flatSettings = formatSettings(current);
        Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                flatSettings);

    }

    private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {