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

Commit 8f7e3815 authored by Ruben Brunk's avatar Ruben Brunk Committed by Android (Google) Code Review
Browse files

Merge "Grant default permissions to preinstalled VrListenerServices." into nyc-dev

parents ae310b46 98576cf9
Loading
Loading
Loading
Loading
+21 −0
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server;
import static com.android.internal.util.ArrayUtils.appendInt;
import static com.android.internal.util.ArrayUtils.appendInt;


import android.app.ActivityManager;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.pm.FeatureInfo;
import android.content.pm.FeatureInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Environment;
@@ -115,6 +116,9 @@ public class SystemConfig {
    // These are the packages that should not run under system user
    // These are the packages that should not run under system user
    final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();
    final ArraySet<String> mSystemUserBlacklistedApps = new ArraySet<>();


    // These are the components that are enabled by default as VR mode listener services.
    final ArraySet<ComponentName> mDefaultVrComponents = new ArraySet<>();

    public static SystemConfig getInstance() {
    public static SystemConfig getInstance() {
        synchronized (SystemConfig.class) {
        synchronized (SystemConfig.class) {
            if (sInstance == null) {
            if (sInstance == null) {
@@ -168,6 +172,10 @@ public class SystemConfig {
        return mSystemUserBlacklistedApps;
        return mSystemUserBlacklistedApps;
    }
    }


    public ArraySet<ComponentName> getDefaultVrComponents() {
        return mDefaultVrComponents;
    }

    SystemConfig() {
    SystemConfig() {
        // Read configuration from system
        // Read configuration from system
        readPermissions(Environment.buildPath(
        readPermissions(Environment.buildPath(
@@ -431,6 +439,19 @@ public class SystemConfig {
                        mSystemUserBlacklistedApps.add(pkgname);
                        mSystemUserBlacklistedApps.add(pkgname);
                    }
                    }
                    XmlUtils.skipCurrentTag(parser);
                    XmlUtils.skipCurrentTag(parser);
                } else if ("default-enabled-vr-app".equals(name) && allowAppConfigs) {
                    String pkgname = parser.getAttributeValue(null, "package");
                    String clsname = parser.getAttributeValue(null, "class");
                    if (pkgname == null) {
                        Slog.w(TAG, "<default-enabled-vr-app without package in " + permFile
                                + " at " + parser.getPositionDescription());
                    } else if (clsname == null) {
                        Slog.w(TAG, "<default-enabled-vr-app without class in " + permFile
                                + " at " + parser.getPositionDescription());
                    } else {
                        mDefaultVrComponents.add(new ComponentName(pkgname, clsname));
                    }
                    XmlUtils.skipCurrentTag(parser);
                } else {
                } else {
                    XmlUtils.skipCurrentTag(parser);
                    XmlUtils.skipCurrentTag(parser);
                    continue;
                    continue;
+32 −1
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.app.ActivityManager;
import android.app.AppGlobals;
import android.app.AppGlobals;
import android.app.backup.BackupManager;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.ContentValues;
import android.content.Context;
import android.content.Context;
@@ -63,6 +64,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.os.BackgroundThread;
import com.android.providers.settings.SettingsState.Setting;
import com.android.providers.settings.SettingsState.Setting;
import com.android.server.SystemConfig;


import java.io.File;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileDescriptor;
@@ -1940,7 +1942,7 @@ public class SettingsProvider extends ContentProvider {
        }
        }


        private final class UpgradeController {
        private final class UpgradeController {
            private static final int SETTINGS_VERSION = 125;
            private static final int SETTINGS_VERSION = 126;


            private final int mUserId;
            private final int mUserId;


@@ -2136,6 +2138,35 @@ public class SettingsProvider extends ContentProvider {
                    currentVersion = 125;
                    currentVersion = 125;
                }
                }


                if (currentVersion == 125) {
                    // Version 125: Allow OEMs to set the default VR service.
                    final SettingsState secureSettings = getSecureSettingsLocked(userId);

                    Setting currentSetting = secureSettings.getSettingLocked(
                            Settings.Secure.ENABLED_VR_LISTENERS);
                    if (currentSetting == null) {
                        ArraySet<ComponentName> l =
                                SystemConfig.getInstance().getDefaultVrComponents();

                        if (l != null && !l.isEmpty()) {
                            StringBuilder b = new StringBuilder();
                            boolean start = true;
                            for (ComponentName c : l) {
                                if (!start) {
                                    b.append(':');
                                }
                                b.append(c.flattenToString());
                                start = false;
                            }
                            secureSettings.insertSettingLocked(
                                    Settings.Secure.ENABLED_VR_LISTENERS, b.toString(),
                                    SettingsState.SYSTEM_PACKAGE_NAME);
                        }

                    }
                    currentVersion = 126;
                }

                // vXXX: Add new settings above this point.
                // vXXX: Add new settings above this point.


                // Return the current version.
                // Return the current version.
+11 −5
Original line number Original line Diff line number Diff line
@@ -227,10 +227,11 @@ public class EnabledComponentsObserver implements SettingChangeListener {
        return userIds;
        return userIds;
    }
    }


    private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
    public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
            String serviceName, String permissionName) {

        ArraySet<ComponentName> installed = new ArraySet<>();
        ArraySet<ComponentName> installed = new ArraySet<>();
        PackageManager pm = mContext.getPackageManager();
        Intent queryIntent = new Intent(serviceName);
        Intent queryIntent = new Intent(mServiceName);
        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
                queryIntent,
                queryIntent,
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
@@ -241,10 +242,10 @@ public class EnabledComponentsObserver implements SettingChangeListener {
                ServiceInfo info = resolveInfo.serviceInfo;
                ServiceInfo info = resolveInfo.serviceInfo;


                ComponentName component = new ComponentName(info.packageName, info.name);
                ComponentName component = new ComponentName(info.packageName, info.name);
                if (!mServicePermission.equals(info.permission)) {
                if (!permissionName.equals(info.permission)) {
                    Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
                    Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
                            + ": it does not require the permission "
                            + ": it does not require the permission "
                            + mServicePermission);
                            + permissionName);
                    continue;
                    continue;
                }
                }
                installed.add(component);
                installed.add(component);
@@ -253,6 +254,11 @@ public class EnabledComponentsObserver implements SettingChangeListener {
        return installed;
        return installed;
    }
    }


    private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
        return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
                mServicePermission);
    }

    private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
    private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
            int userId) {
            int userId) {
        final ContentResolver cr = mContext.getContentResolver();
        final ContentResolver cr = mContext.getContentResolver();
+264 −41
Original line number Original line Diff line number Diff line
@@ -16,16 +16,23 @@
package com.android.server.vr;
package com.android.server.vr;


import android.app.AppOpsManager;
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.annotation.NonNull;
import android.annotation.NonNull;
import android.content.Context;
import android.content.ComponentName;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Binder;
import android.os.Binder;
import android.os.Handler;
import android.os.Handler;
import android.os.IBinder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.IInterface;
import android.os.Looper;
import android.os.Looper;
import android.os.RemoteException;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings;
import android.service.notification.NotificationListenerService;
import android.service.vr.IVrListener;
import android.service.vr.IVrListener;
import android.service.vr.VrListenerService;
import android.service.vr.VrListenerService;
import android.util.ArraySet;
import android.util.ArraySet;
@@ -38,7 +45,9 @@ import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeLis
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService;
import com.android.server.utils.ManagedApplicationService.BinderChecker;
import com.android.server.utils.ManagedApplicationService.BinderChecker;


import java.lang.StringBuilder;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
import java.util.Objects;
import java.util.Set;
import java.util.Set;


@@ -53,8 +62,8 @@ import java.util.Set;
 *  hardware/libhardware/modules/vr
 *  hardware/libhardware/modules/vr
 * <p/>
 * <p/>
 * In general applications may enable or disable VR mode by calling
 * In general applications may enable or disable VR mode by calling
 * {@link android.app.Activity#setVrMode)}.  An application may also implement a service to be run
 * {@link android.app.Activity#setVrModeEnabled)}.  An application may also implement a service to
 * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
 * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}.
 *
 *
 * @see {@link android.service.vr.VrListenerService}
 * @see {@link android.service.vr.VrListenerService}
 * @see {@link com.android.server.vr.VrManagerInternal}
 * @see {@link com.android.server.vr.VrManagerInternal}
@@ -74,13 +83,18 @@ public class VrManagerService extends SystemService implements EnabledComponentC
    private final IBinder mOverlayToken = new Binder();
    private final IBinder mOverlayToken = new Binder();


    // State protected by mLock
    // State protected by mLock
    private boolean mVrModeEnabled = false;
    private boolean mVrModeEnabled;
    private final Set<VrStateListener> mListeners = new ArraySet<>();
    private final Set<VrStateListener> mListeners = new ArraySet<>();
    private EnabledComponentsObserver mComponentObserver;
    private EnabledComponentsObserver mComponentObserver;
    private ManagedApplicationService mCurrentVrService;
    private ManagedApplicationService mCurrentVrService;
    private Context mContext;
    private Context mContext;
    private ComponentName mCurrentVrModeComponent;
    private ComponentName mCurrentVrModeComponent;
    private int mCurrentVrModeUser;
    private int mCurrentVrModeUser;
    private boolean mWasDefaultGranted;
    private boolean mGuard;
    private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>();
    private String mPreviousNotificationPolicyAccessPackage;
    private String mPreviousManageOverlayPackage;


    private static final BinderChecker sBinderChecker = new BinderChecker() {
    private static final BinderChecker sBinderChecker = new BinderChecker() {
        @Override
        @Override
@@ -239,10 +253,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
     *
     *
     * @return {@code true} if the component/user combination specified is valid.
     * @return {@code true} if the component/user combination specified is valid.
     */
     */
    private boolean updateCurrentVrServiceLocked(boolean enabled,
    private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component,
            @NonNull ComponentName component, int userId, ComponentName calling) {
            int userId, ComponentName calling) {


        boolean sendUpdatedCaller = false;
        boolean sendUpdatedCaller = false;
        final long identity = Binder.clearCallingIdentity();
        try {


            boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
            boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
                    EnabledComponentsObserver.NO_ERROR);
                    EnabledComponentsObserver.NO_ERROR);
@@ -256,21 +272,29 @@ public class VrManagerService extends SystemService implements EnabledComponentC
                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
                            mCurrentVrService.getUserId());
                            mCurrentVrService.getUserId());
                    mCurrentVrService.disconnect();
                    mCurrentVrService.disconnect();
                    disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
                            new UserHandle(mCurrentVrService.getUserId()));
                    mCurrentVrService = null;
                    mCurrentVrService = null;
                }
                }
            } else {
            } else {
                if (mCurrentVrService != null) {
                if (mCurrentVrService != null) {
                    // Unbind any running service that doesn't match the component/user selection
                    // Unbind any running service that doesn't match the component/user selection
                    if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
                    if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
                    Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
                        Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() +
                        mCurrentVrService.getUserId());
                                " for user " + mCurrentVrService.getUserId());
                        disableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
                                new UserHandle(mCurrentVrService.getUserId()));
                        createAndConnectService(component, userId);
                        createAndConnectService(component, userId);
                        enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
                                new UserHandle(mCurrentVrService.getUserId()));
                        sendUpdatedCaller = true;
                        sendUpdatedCaller = true;
                    }
                    }
                    // The service with the correct component/user is bound
                    // The service with the correct component/user is bound
                } else {
                } else {
                    // Nothing was previously running, bind a new service
                    // Nothing was previously running, bind a new service
                    createAndConnectService(component, userId);
                    createAndConnectService(component, userId);
                    enableImpliedPermissionsLocked(mCurrentVrService.getComponent(),
                            new UserHandle(mCurrentVrService.getUserId()));
                    sendUpdatedCaller = true;
                    sendUpdatedCaller = true;
                }
                }
            }
            }
@@ -293,7 +317,206 @@ public class VrManagerService extends SystemService implements EnabledComponentC
            }
            }


            return validUserComponent;
            return validUserComponent;
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
     * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
     * component package and user.
     *
     * @param component the component whose package should be enabled.
     * @param userId the user that owns the given component.
     */
    private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
        if (mGuard) {
            // Impossible
            throw new IllegalStateException("Enabling permissions without disabling.");
        }
        mGuard = true;

        PackageManager pm = mContext.getPackageManager();

        String pName = component.getPackageName();
        if (pm == null) {
            Slog.e(TAG, "Couldn't set implied permissions for " + pName +
                ", PackageManager isn't running");
            return;
        }

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

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

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

        mWasDefaultGranted = true;

        grantOverlayAccess(pName, userId);
        grantNotificationPolicyAccess(pName);
        grantNotificationListenerAccess(pName, userId);
    }

    /**
     * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given
     * component package and user.
     *
     * @param component the component whose package should be disabled.
     * @param userId the user that owns the given component.
     */
    private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) {
        if (!mGuard) {
            // Impossible
            throw new IllegalStateException("Disabling permissions without enabling.");
        }
        mGuard = false;

        PackageManager pm = mContext.getPackageManager();

        if (pm == null) {
            Slog.e(TAG, "Couldn't remove implied permissions for " + component +
                ", PackageManager isn't running");
            return;
        }

        String pName = component.getPackageName();
        if (mWasDefaultGranted) {
            revokeOverlayAccess(userId);
            revokeNotificationPolicyAccess(pName);
            revokeNotificiationListenerAccess();
            mWasDefaultGranted = false;
        }

    }

    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 revokeOverlayAccess(UserHandle userId) {
        PackageManager pm = mContext.getPackageManager();
        if (mPreviousManageOverlayPackage != null) {
            pm.revokeRuntimePermission(mPreviousManageOverlayPackage,
                    android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId);
            mPreviousManageOverlayPackage = null;
        }
    }


    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) {
            nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false);
            mPreviousNotificationPolicyAccessPackage = null;
        }
    }

    private void grantNotificationListenerAccess(String pkg, UserHandle userId) {
        PackageManager pm = mContext.getPackageManager();
        ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
                userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE,
                android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
        ContentResolver resolver = mContext.getContentResolver();

        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);
            }
        }

        if (current.size() > 0) {
            String flatSettings = formatSettings(current);
            Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
                    flatSettings);
        }
    }

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

        ContentResolver resolver = mContext.getContentResolver();
        ArraySet<String> current = getCurrentNotifListeners(resolver);

        current.removeAll(mPreviousToggledListenerSettings);
        mPreviousToggledListenerSettings.clear();

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

    private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) {
        String flat = Settings.Secure.getString(resolver,
                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);

        ArraySet<String> current = new ArraySet<>();
        if (flat != null) {
            String[] allowed = flat.split(":");
            for (String s : allowed) {
                current.add(s);
            }
        }
        return current;
    }

    private static String formatSettings(Collection<String> c) {
        if (c == null || c.isEmpty()) {
            return "";
        }

        StringBuilder b = new StringBuilder();
        boolean start = true;
        for (String s : c) {
            if ("".equals(s)) {
                continue;
            }
            if (!start) {
                b.append(':');
            }
            b.append(s);
            start = false;
        }
        return b.toString();
    }




    private void createAndConnectService(@NonNull ComponentName component, int userId) {
    private void createAndConnectService(@NonNull ComponentName component, int userId) {
        mCurrentVrService = VrManagerService.create(mContext, component, userId);
        mCurrentVrService = VrManagerService.create(mContext, component, userId);