Loading services/core/java/com/android/server/SystemConfig.java→core/java/com/android/server/SystemConfig.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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( Loading Loading @@ -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; Loading packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +32 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading services/core/java/com/android/server/vr/EnabledComponentsObserver.java +11 −5 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading @@ -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(); Loading services/core/java/com/android/server/vr/VrManagerService.java +264 −41 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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} Loading @@ -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 Loading Loading @@ -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); Loading @@ -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; } } } } Loading @@ -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); Loading Loading
services/core/java/com/android/server/SystemConfig.java→core/java/com/android/server/SystemConfig.java +21 −0 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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( Loading Loading @@ -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; Loading
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +32 −1 Original line number Original line Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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. Loading
services/core/java/com/android/server/vr/EnabledComponentsObserver.java +11 −5 Original line number Original line Diff line number Diff line Loading @@ -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, Loading @@ -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); Loading @@ -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(); Loading
services/core/java/com/android/server/vr/VrManagerService.java +264 −41 Original line number Original line Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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} Loading @@ -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 Loading Loading @@ -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); Loading @@ -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; } } } } Loading @@ -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); Loading