Merge "Fix permissions update for VrListenerService on user changes." into nyc-dev

This commit is contained in:
Ruben Brunk
2016-06-13 19:58:30 +00:00
committed by Android (Google) Code Review
2 changed files with 114 additions and 49 deletions

View File

@@ -1340,9 +1340,14 @@ public class AppOpsManager {
/** @hide */ /** @hide */
public void setUserRestriction(int code, boolean restricted, IBinder token, public void setUserRestriction(int code, boolean restricted, IBinder token,
String[] exceptionPackages) { String[] exceptionPackages) {
setUserRestrictionForUser(code, restricted, token, exceptionPackages, mContext.getUserId());
}
/** @hide */
public void setUserRestrictionForUser(int code, boolean restricted, IBinder token,
String[] exceptionPackages, int userId) {
try { try {
mService.setUserRestriction(code, restricted, token, mContext.getUserId(), mService.setUserRestriction(code, restricted, token, userId, exceptionPackages);
exceptionPackages);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -46,11 +46,12 @@ import android.service.vr.IVrListener;
import android.service.vr.IVrManager; import android.service.vr.IVrManager;
import android.service.vr.IVrStateCallbacks; import android.service.vr.IVrStateCallbacks;
import android.service.vr.VrListenerService; import android.service.vr.VrListenerService;
import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Slog; import android.util.Slog;
import android.util.SparseArray; import android.util.SparseArray;
import com.android.internal.R; import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.SystemConfig; import com.android.server.SystemConfig;
import com.android.server.SystemService; import com.android.server.SystemService;
import com.android.server.utils.ManagedApplicationService.PendingEvent; import com.android.server.utils.ManagedApplicationService.PendingEvent;
@@ -67,6 +68,7 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
/** /**
@@ -197,29 +199,44 @@ public class VrManagerService extends SystemService implements EnabledComponentC
private final class NotificationAccessManager { private final class NotificationAccessManager {
private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>(); private final SparseArray<ArraySet<String>> mAllowedPackages = new SparseArray<>();
private final ArrayMap<String, Integer> mNotificationAccessPackageToUserId =
new ArrayMap<>();
public void update(Collection<String> packageNames) { public void update(Collection<String> packageNames) {
int currentUserId = ActivityManager.getCurrentUser(); int currentUserId = ActivityManager.getCurrentUser();
UserHandle currentUserHandle = new UserHandle(currentUserId);
ArraySet<String> allowed = mAllowedPackages.get(currentUserId); ArraySet<String> allowed = mAllowedPackages.get(currentUserId);
if (allowed == null) { if (allowed == null) {
allowed = new ArraySet<>(); allowed = new ArraySet<>();
} }
// Make sure we revoke notification access for listeners in other users
final int listenerCount = mNotificationAccessPackageToUserId.size();
for (int i = listenerCount - 1; i >= 0; i--) {
final int grantUserId = mNotificationAccessPackageToUserId.valueAt(i);
if (grantUserId != currentUserId) {
String packageName = mNotificationAccessPackageToUserId.keyAt(i);
revokeNotificationListenerAccess(packageName, grantUserId);
revokeNotificationPolicyAccess(packageName);
revokeCoarseLocationPermissionIfNeeded(packageName, grantUserId);
mNotificationAccessPackageToUserId.removeAt(i);
}
}
for (String pkg : allowed) { for (String pkg : allowed) {
if (!packageNames.contains(pkg)) { if (!packageNames.contains(pkg)) {
revokeNotificationListenerAccess(pkg); revokeNotificationListenerAccess(pkg, currentUserId);
revokeNotificationPolicyAccess(pkg); revokeNotificationPolicyAccess(pkg);
revokeCoarseLocationAccess(pkg, currentUserHandle); revokeCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.remove(pkg);
} }
} }
for (String pkg : packageNames) { for (String pkg : packageNames) {
if (!allowed.contains(pkg)) { if (!allowed.contains(pkg)) {
grantNotificationPolicyAccess(pkg); grantNotificationPolicyAccess(pkg);
grantNotificationListenerAccess(pkg, currentUserHandle); grantNotificationListenerAccess(pkg, currentUserId);
grantCoarseLocationAccess(pkg, currentUserHandle); grantCoarseLocationPermissionIfNeeded(pkg, currentUserId);
mNotificationAccessPackageToUserId.put(pkg, currentUserId);
} }
} }
@@ -229,7 +246,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} }
} }
/** /**
* Called when a user, package, or setting changes that could affect whether or not the * Called when a user, package, or setting changes that could affect whether or not the
* currently bound VrListenerService is changed. * currently bound VrListenerService is changed.
@@ -535,17 +551,33 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} }
} }
private void updateOverlayStateLocked(ComponentName exemptedComponent) { private void updateOverlayStateLocked(String exemptedPackage, int newUserId, int oldUserId) {
AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
// If user changed drop restrictions for the old user.
if (oldUserId != newUserId) {
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
false, mOverlayToken, null, oldUserId);
}
// Apply the restrictions for the current user based on vr state
String[] exemptions = (exemptedPackage == null) ? new String[0] :
new String[] { exemptedPackage };
appOpsManager.setUserRestrictionForUser(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
mVrModeEnabled, mOverlayToken, exemptions, newUserId);
}
private void updateDependentAppOpsLocked(String newVrServicePackage, int newUserId,
String oldVrServicePackage, int oldUserId) {
// If VR state changed and we also have a VR service change.
if (Objects.equals(newVrServicePackage, oldVrServicePackage)) {
return;
}
final long identity = Binder.clearCallingIdentity(); final long identity = Binder.clearCallingIdentity();
try { try {
AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); // Set overlay exception state based on VR enabled and current service
if (appOpsManager != null) { updateOverlayStateLocked(newVrServicePackage, newUserId, oldUserId);
String[] exemptions = (exemptedComponent == null) ? new String[0] :
new String[] { exemptedComponent.getPackageName() };
appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
mVrModeEnabled, mOverlayToken, exemptions);
}
} finally { } finally {
Binder.restoreCallingIdentity(identity); Binder.restoreCallingIdentity(identity);
} }
@@ -578,8 +610,12 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return validUserComponent; // Disabled -> Disabled transition does nothing. return validUserComponent; // Disabled -> Disabled transition does nothing.
} }
String oldVrServicePackage = mCurrentVrService != null
? mCurrentVrService.getComponent().getPackageName() : null;
final int oldUserId = mCurrentVrModeUser;
// Always send mode change events. // Always send mode change events.
changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null); changeVrModeLocked(enabled);
if (!enabled || !validUserComponent) { if (!enabled || !validUserComponent) {
// Unbind whatever is running // Unbind whatever is running
@@ -606,12 +642,25 @@ public class VrManagerService extends SystemService implements EnabledComponentC
} }
} }
if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) { if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
mCurrentVrModeComponent = calling; mCurrentVrModeComponent = calling;
sendUpdatedCaller = true;
}
if (mCurrentVrModeUser != userId) {
mCurrentVrModeUser = userId; mCurrentVrModeUser = userId;
sendUpdatedCaller = true; sendUpdatedCaller = true;
} }
String newVrServicePackage = mCurrentVrService != null
? mCurrentVrService.getComponent().getPackageName() : null;
final int newUserId = mCurrentVrModeUser;
// Update AppOps settings that change state when entering/exiting VR mode, or changing
// the current VrListenerService.
updateDependentAppOpsLocked(newVrServicePackage, newUserId,
oldVrServicePackage, oldUserId);
if (mCurrentVrService != null && sendUpdatedCaller) { if (mCurrentVrService != null && sendUpdatedCaller) {
final ComponentName c = mCurrentVrModeComponent; final ComponentName c = mCurrentVrModeComponent;
mCurrentVrService.sendEvent(new PendingEvent() { mCurrentVrService.sendEvent(new PendingEvent() {
@@ -645,18 +694,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
return true; return true;
} }
private void grantCoarseLocationAccess(String pkg, UserHandle userId) {
PackageManager pm = mContext.getPackageManager();
pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION,
userId);
}
private void revokeCoarseLocationAccess(String pkg, UserHandle userId) {
PackageManager pm = mContext.getPackageManager();
pm.revokeRuntimePermission(pkg,
android.Manifest.permission.ACCESS_COARSE_LOCATION, userId);
}
private void grantNotificationPolicyAccess(String pkg) { private void grantNotificationPolicyAccess(String pkg) {
NotificationManager nm = mContext.getSystemService(NotificationManager.class); NotificationManager nm = mContext.getSystemService(NotificationManager.class);
nm.setNotificationPolicyAccessGranted(pkg, true); nm.setNotificationPolicyAccessGranted(pkg, true);
@@ -670,14 +707,14 @@ public class VrManagerService extends SystemService implements EnabledComponentC
nm.setNotificationPolicyAccessGranted(pkg, false); nm.setNotificationPolicyAccessGranted(pkg, false);
} }
private void grantNotificationListenerAccess(String pkg, UserHandle userId) { private void grantNotificationListenerAccess(String pkg, int userId) {
PackageManager pm = mContext.getPackageManager(); PackageManager pm = mContext.getPackageManager();
ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm, ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm,
userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE, userId, NotificationListenerService.SERVICE_INTERFACE,
android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE);
ContentResolver resolver = mContext.getContentResolver(); ContentResolver resolver = mContext.getContentResolver();
ArraySet<String> current = getCurrentNotifListeners(resolver); ArraySet<String> current = getNotificationListeners(resolver, userId);
for (ComponentName c : possibleServices) { for (ComponentName c : possibleServices) {
String flatName = c.flattenToString(); String flatName = c.flattenToString();
@@ -689,14 +726,16 @@ public class VrManagerService extends SystemService implements EnabledComponentC
if (current.size() > 0) { if (current.size() > 0) {
String flatSettings = formatSettings(current); String flatSettings = formatSettings(current);
Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, Settings.Secure.putStringForUser(resolver,
flatSettings); Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
flatSettings, userId);
} }
} }
private void revokeNotificationListenerAccess(String pkg) { private void revokeNotificationListenerAccess(String pkg, int userId) {
ContentResolver resolver = mContext.getContentResolver(); ContentResolver resolver = mContext.getContentResolver();
ArraySet<String> current = getCurrentNotifListeners(resolver);
ArraySet<String> current = getNotificationListeners(resolver, userId);
ArrayList<String> toRemove = new ArrayList<>(); ArrayList<String> toRemove = new ArrayList<>();
@@ -710,14 +749,37 @@ public class VrManagerService extends SystemService implements EnabledComponentC
current.removeAll(toRemove); current.removeAll(toRemove);
String flatSettings = formatSettings(current); String flatSettings = formatSettings(current);
Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, Settings.Secure.putStringForUser(resolver,
flatSettings); Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
flatSettings, userId);
} }
private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) { private void grantCoarseLocationPermissionIfNeeded(String pkg, int userId) {
String flat = Settings.Secure.getString(resolver, // Don't clobber the user if permission set in current state explicitly
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
mContext.getPackageManager().grantRuntimePermission(pkg,
Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
}
}
private void revokeCoarseLocationPermissionIfNeeded(String pkg, int userId) {
// Don't clobber the user if permission set in current state explicitly
if (!isPermissionUserUpdated(Manifest.permission.ACCESS_COARSE_LOCATION, pkg, userId)) {
mContext.getPackageManager().revokeRuntimePermission(pkg,
Manifest.permission.ACCESS_COARSE_LOCATION, new UserHandle(userId));
}
}
private boolean isPermissionUserUpdated(String permission, String pkg, int userId) {
final int flags = mContext.getPackageManager().getPermissionFlags(
permission, pkg, new UserHandle(userId));
return (flags & (PackageManager.FLAG_PERMISSION_USER_SET
| PackageManager.FLAG_PERMISSION_USER_FIXED)) != 0;
}
private ArraySet<String> getNotificationListeners(ContentResolver resolver, int userId) {
String flat = Settings.Secure.getStringForUser(resolver,
Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, userId);
ArraySet<String> current = new ArraySet<>(); ArraySet<String> current = new ArraySet<>();
if (flat != null) { if (flat != null) {
@@ -763,9 +825,8 @@ public class VrManagerService extends SystemService implements EnabledComponentC
* Note: Must be called while holding {@code mLock}. * Note: Must be called while holding {@code mLock}.
* *
* @param enabled new state of the VR mode. * @param enabled new state of the VR mode.
* @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
*/ */
private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) { private void changeVrModeLocked(boolean enabled) {
if (mVrModeEnabled != enabled) { if (mVrModeEnabled != enabled) {
mVrModeEnabled = enabled; mVrModeEnabled = enabled;
@@ -773,7 +834,6 @@ public class VrManagerService extends SystemService implements EnabledComponentC
Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
setVrModeNative(mVrModeEnabled); setVrModeNative(mVrModeEnabled);
updateOverlayStateLocked(exemptedComponent);
onVrModeChangedLocked(); onVrModeChangedLocked();
} }
} }