VrManagerService.java revision c7be3beced4ade05466a4a77c003ea81c2429f74
1/** 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.server.vr; 17 18import android.Manifest; 19import android.app.AppOpsManager; 20import android.app.NotificationManager; 21import android.annotation.NonNull; 22import android.content.ComponentName; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.pm.ApplicationInfo; 26import android.content.pm.PackageManager; 27import android.content.pm.PackageManager.NameNotFoundException; 28import android.os.Binder; 29import android.os.Handler; 30import android.os.IBinder; 31import android.os.IInterface; 32import android.os.Looper; 33import android.os.Message; 34import android.os.RemoteCallbackList; 35import android.os.RemoteException; 36import android.os.UserHandle; 37import android.provider.Settings; 38import android.service.notification.NotificationListenerService; 39import android.service.vr.IVrListener; 40import android.service.vr.IVrManager; 41import android.service.vr.IVrStateCallbacks; 42import android.service.vr.VrListenerService; 43import android.util.ArraySet; 44import android.util.Slog; 45 46import com.android.internal.R; 47import com.android.server.SystemService; 48import com.android.server.utils.ManagedApplicationService.PendingEvent; 49import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener; 50import com.android.server.utils.ManagedApplicationService; 51import com.android.server.utils.ManagedApplicationService.BinderChecker; 52 53import java.lang.StringBuilder; 54import java.lang.ref.WeakReference; 55import java.util.ArrayList; 56import java.util.Collection; 57import java.util.Objects; 58import java.util.Set; 59 60/** 61 * Service tracking whether VR mode is active, and notifying listening services of state changes. 62 * <p/> 63 * Services running in system server may modify the state of VrManagerService via the interface in 64 * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the 65 * interface given in VrStateListener. 66 * <p/> 67 * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.: 68 * hardware/libhardware/modules/vr 69 * <p/> 70 * In general applications may enable or disable VR mode by calling 71 * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to 72 * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}. 73 * 74 * @see {@link android.service.vr.VrListenerService} 75 * @see {@link com.android.server.vr.VrManagerInternal} 76 * @see {@link com.android.server.vr.VrStateListener} 77 * 78 * @hide 79 */ 80public class VrManagerService extends SystemService implements EnabledComponentChangeListener{ 81 82 public static final String TAG = "VrManagerService"; 83 84 public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager"; 85 86 private static native void initializeNative(); 87 private static native void setVrModeNative(boolean enabled); 88 89 private final Object mLock = new Object(); 90 91 private final IBinder mOverlayToken = new Binder(); 92 93 // State protected by mLock 94 private boolean mVrModeEnabled; 95 private EnabledComponentsObserver mComponentObserver; 96 private ManagedApplicationService mCurrentVrService; 97 private Context mContext; 98 private ComponentName mCurrentVrModeComponent; 99 private int mCurrentVrModeUser; 100 private boolean mWasDefaultGranted; 101 private boolean mGuard; 102 private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks = 103 new RemoteCallbackList<>(); 104 private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>(); 105 private String mPreviousNotificationPolicyAccessPackage; 106 private String mPreviousManageOverlayPackage; 107 108 private static final int MSG_VR_STATE_CHANGE = 0; 109 110 private final Handler mHandler = new Handler() { 111 @Override 112 public void handleMessage(Message msg) { 113 switch(msg.what) { 114 case MSG_VR_STATE_CHANGE : { 115 boolean state = (msg.arg1 == 1); 116 int i = mRemoteCallbacks.beginBroadcast(); 117 while (i > 0) { 118 i--; 119 try { 120 mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state); 121 } catch (RemoteException e) { 122 // Noop 123 } 124 } 125 mRemoteCallbacks.finishBroadcast(); 126 } break; 127 default : 128 throw new IllegalStateException("Unknown message type: " + msg.what); 129 } 130 } 131 }; 132 133 private static final BinderChecker sBinderChecker = new BinderChecker() { 134 @Override 135 public IInterface asInterface(IBinder binder) { 136 return IVrListener.Stub.asInterface(binder); 137 } 138 139 @Override 140 public boolean checkType(IInterface service) { 141 return service instanceof IVrListener; 142 } 143 }; 144 145 /** 146 * Called when a user, package, or setting changes that could affect whether or not the 147 * currently bound VrListenerService is changed. 148 */ 149 @Override 150 public void onEnabledComponentChanged() { 151 synchronized (mLock) { 152 if (mCurrentVrService == null) { 153 return; // No active services 154 } 155 156 // There is an active service, update it if needed 157 updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(), 158 mCurrentVrService.getUserId(), null); 159 } 160 } 161 162 private final IVrManager mVrManager = new IVrManager.Stub() { 163 164 @Override 165 public void registerListener(IVrStateCallbacks cb) { 166 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); 167 if (cb == null) { 168 throw new IllegalArgumentException("Callback binder object is null."); 169 } 170 171 VrManagerService.this.addStateCallback(cb); 172 } 173 174 @Override 175 public void unregisterListener(IVrStateCallbacks cb) { 176 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); 177 if (cb == null) { 178 throw new IllegalArgumentException("Callback binder object is null."); 179 } 180 181 VrManagerService.this.removeStateCallback(cb); 182 } 183 184 @Override 185 public boolean getVrModeState() { 186 return VrManagerService.this.getVrMode(); 187 } 188 189 }; 190 191 private void enforceCallerPermission(String permission) { 192 if (mContext.checkCallingOrSelfPermission(permission) 193 != PackageManager.PERMISSION_GRANTED) { 194 throw new SecurityException("Caller does not hold the permission " + permission); 195 } 196 } 197 198 /** 199 * Implementation of VrManagerInternal. Callable only from system services. 200 */ 201 private final class LocalService extends VrManagerInternal { 202 @Override 203 public void setVrMode(boolean enabled, ComponentName packageName, int userId, 204 ComponentName callingPackage) { 205 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage); 206 } 207 208 @Override 209 public boolean isCurrentVrListener(String packageName, int userId) { 210 return VrManagerService.this.isCurrentVrListener(packageName, userId); 211 } 212 213 @Override 214 public int hasVrPackage(ComponentName packageName, int userId) { 215 return VrManagerService.this.hasVrPackage(packageName, userId); 216 } 217 } 218 219 public VrManagerService(Context context) { 220 super(context); 221 } 222 223 @Override 224 public void onStart() { 225 synchronized(mLock) { 226 initializeNative(); 227 mContext = getContext(); 228 } 229 230 publishLocalService(VrManagerInternal.class, new LocalService()); 231 publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder()); 232 } 233 234 @Override 235 public void onBootPhase(int phase) { 236 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 237 synchronized (mLock) { 238 Looper looper = Looper.getMainLooper(); 239 Handler handler = new Handler(looper); 240 ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>(); 241 listeners.add(this); 242 mComponentObserver = EnabledComponentsObserver.build(mContext, handler, 243 Settings.Secure.ENABLED_VR_LISTENERS, looper, 244 android.Manifest.permission.BIND_VR_LISTENER_SERVICE, 245 VrListenerService.SERVICE_INTERFACE, mLock, listeners); 246 247 mComponentObserver.rebuildAll(); 248 } 249 } 250 } 251 252 @Override 253 public void onStartUser(int userHandle) { 254 synchronized (mLock) { 255 mComponentObserver.onUsersChanged(); 256 } 257 } 258 259 @Override 260 public void onSwitchUser(int userHandle) { 261 synchronized (mLock) { 262 mComponentObserver.onUsersChanged(); 263 } 264 265 } 266 267 @Override 268 public void onStopUser(int userHandle) { 269 synchronized (mLock) { 270 mComponentObserver.onUsersChanged(); 271 } 272 273 } 274 275 @Override 276 public void onCleanupUser(int userHandle) { 277 synchronized (mLock) { 278 mComponentObserver.onUsersChanged(); 279 } 280 } 281 282 private void updateOverlayStateLocked(ComponentName exemptedComponent) { 283 final long identity = Binder.clearCallingIdentity(); 284 try { 285 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 286 if (appOpsManager != null) { 287 String[] exemptions = (exemptedComponent == null) ? new String[0] : 288 new String[] { exemptedComponent.getPackageName() }; 289 290 appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, 291 mVrModeEnabled, mOverlayToken, exemptions); 292 } 293 } finally { 294 Binder.restoreCallingIdentity(identity); 295 } 296 } 297 298 /** 299 * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of 300 * the currently selected VR listener service. If the component selected for the VR listener 301 * service has changed, unbind the previous listener and bind the new listener (if enabled). 302 * <p/> 303 * Note: Must be called while holding {@code mLock}. 304 * 305 * @param enabled new state for VR mode. 306 * @param component new component to be bound as a VR listener. 307 * @param userId user owning the component to be bound. 308 * @param calling the component currently using VR mode, or null to leave unchanged. 309 * 310 * @return {@code true} if the component/user combination specified is valid. 311 */ 312 private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component, 313 int userId, ComponentName calling) { 314 315 boolean sendUpdatedCaller = false; 316 final long identity = Binder.clearCallingIdentity(); 317 try { 318 319 boolean validUserComponent = (mComponentObserver.isValid(component, userId) == 320 EnabledComponentsObserver.NO_ERROR); 321 322 // Always send mode change events. 323 changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null); 324 325 if (!enabled || !validUserComponent) { 326 // Unbind whatever is running 327 if (mCurrentVrService != null) { 328 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " + 329 mCurrentVrService.getUserId()); 330 mCurrentVrService.disconnect(); 331 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 332 new UserHandle(mCurrentVrService.getUserId())); 333 mCurrentVrService = null; 334 } 335 } else { 336 if (mCurrentVrService != null) { 337 // Unbind any running service that doesn't match the component/user selection 338 if (mCurrentVrService.disconnectIfNotMatching(component, userId)) { 339 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + 340 " for user " + mCurrentVrService.getUserId()); 341 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 342 new UserHandle(mCurrentVrService.getUserId())); 343 createAndConnectService(component, userId); 344 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 345 new UserHandle(mCurrentVrService.getUserId())); 346 sendUpdatedCaller = true; 347 } 348 // The service with the correct component/user is bound 349 } else { 350 // Nothing was previously running, bind a new service 351 createAndConnectService(component, userId); 352 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 353 new UserHandle(mCurrentVrService.getUserId())); 354 sendUpdatedCaller = true; 355 } 356 } 357 358 if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) { 359 mCurrentVrModeComponent = calling; 360 mCurrentVrModeUser = userId; 361 sendUpdatedCaller = true; 362 } 363 364 if (mCurrentVrService != null && sendUpdatedCaller) { 365 final ComponentName c = mCurrentVrModeComponent; 366 mCurrentVrService.sendEvent(new PendingEvent() { 367 @Override 368 public void runEvent(IInterface service) throws RemoteException { 369 IVrListener l = (IVrListener) service; 370 l.focusedActivityChanged(c); 371 } 372 }); 373 } 374 375 return validUserComponent; 376 } finally { 377 Binder.restoreCallingIdentity(identity); 378 } 379 } 380 381 /** 382 * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given 383 * component package and user. 384 * 385 * @param component the component whose package should be enabled. 386 * @param userId the user that owns the given component. 387 */ 388 private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) { 389 if (mGuard) { 390 // Impossible 391 throw new IllegalStateException("Enabling permissions without disabling."); 392 } 393 mGuard = true; 394 395 PackageManager pm = mContext.getPackageManager(); 396 397 String pName = component.getPackageName(); 398 if (pm == null) { 399 Slog.e(TAG, "Couldn't set implied permissions for " + pName + 400 ", PackageManager isn't running"); 401 return; 402 } 403 404 ApplicationInfo info = null; 405 try { 406 info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA); 407 } catch (NameNotFoundException e) { 408 } 409 410 if (info == null) { 411 Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package."); 412 return; 413 } 414 415 if (!(info.isSystemApp() || info.isUpdatedSystemApp())) { 416 return; // Application is not pre-installed, avoid setting implied permissions 417 } 418 419 mWasDefaultGranted = true; 420 421 grantOverlayAccess(pName, userId); 422 grantNotificationPolicyAccess(pName); 423 grantNotificationListenerAccess(pName, userId); 424 } 425 426 /** 427 * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given 428 * component package and user. 429 * 430 * @param component the component whose package should be disabled. 431 * @param userId the user that owns the given component. 432 */ 433 private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) { 434 if (!mGuard) { 435 // Impossible 436 throw new IllegalStateException("Disabling permissions without enabling."); 437 } 438 mGuard = false; 439 440 PackageManager pm = mContext.getPackageManager(); 441 442 if (pm == null) { 443 Slog.e(TAG, "Couldn't remove implied permissions for " + component + 444 ", PackageManager isn't running"); 445 return; 446 } 447 448 String pName = component.getPackageName(); 449 if (mWasDefaultGranted) { 450 revokeOverlayAccess(userId); 451 revokeNotificationPolicyAccess(pName); 452 revokeNotificiationListenerAccess(); 453 mWasDefaultGranted = false; 454 } 455 456 } 457 458 private void grantOverlayAccess(String pkg, UserHandle userId) { 459 PackageManager pm = mContext.getPackageManager(); 460 boolean prev = (PackageManager.PERMISSION_GRANTED == 461 pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg)); 462 mPreviousManageOverlayPackage = null; 463 if (!prev) { 464 pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW, 465 userId); 466 mPreviousManageOverlayPackage = pkg; 467 } 468 } 469 470 private void revokeOverlayAccess(UserHandle userId) { 471 PackageManager pm = mContext.getPackageManager(); 472 if (mPreviousManageOverlayPackage != null) { 473 pm.revokeRuntimePermission(mPreviousManageOverlayPackage, 474 android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId); 475 mPreviousManageOverlayPackage = null; 476 } 477 } 478 479 480 private void grantNotificationPolicyAccess(String pkg) { 481 NotificationManager nm = mContext.getSystemService(NotificationManager.class); 482 boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg); 483 mPreviousNotificationPolicyAccessPackage = null; 484 if (!prev) { 485 mPreviousNotificationPolicyAccessPackage = pkg; 486 nm.setNotificationPolicyAccessGranted(pkg, true); 487 } 488 } 489 490 private void revokeNotificationPolicyAccess(String pkg) { 491 NotificationManager nm = mContext.getSystemService(NotificationManager.class); 492 if (mPreviousNotificationPolicyAccessPackage != null) { 493 nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false); 494 mPreviousNotificationPolicyAccessPackage = null; 495 } 496 } 497 498 private void grantNotificationListenerAccess(String pkg, UserHandle userId) { 499 PackageManager pm = mContext.getPackageManager(); 500 ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm, 501 userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE, 502 android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); 503 ContentResolver resolver = mContext.getContentResolver(); 504 505 ArraySet<String> current = getCurrentNotifListeners(resolver); 506 507 mPreviousToggledListenerSettings.clear(); 508 509 for (ComponentName c : possibleServices) { 510 String flatName = c.flattenToString(); 511 if (Objects.equals(c.getPackageName(), pkg) 512 && !current.contains(flatName)) { 513 mPreviousToggledListenerSettings.add(flatName); 514 current.add(flatName); 515 } 516 } 517 518 if (current.size() > 0) { 519 String flatSettings = formatSettings(current); 520 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 521 flatSettings); 522 } 523 } 524 525 private void revokeNotificiationListenerAccess() { 526 if (mPreviousToggledListenerSettings.isEmpty()) { 527 return; 528 } 529 530 ContentResolver resolver = mContext.getContentResolver(); 531 ArraySet<String> current = getCurrentNotifListeners(resolver); 532 533 current.removeAll(mPreviousToggledListenerSettings); 534 mPreviousToggledListenerSettings.clear(); 535 536 String flatSettings = formatSettings(current); 537 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 538 flatSettings); 539 } 540 541 private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) { 542 String flat = Settings.Secure.getString(resolver, 543 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 544 545 ArraySet<String> current = new ArraySet<>(); 546 if (flat != null) { 547 String[] allowed = flat.split(":"); 548 for (String s : allowed) { 549 current.add(s); 550 } 551 } 552 return current; 553 } 554 555 private static String formatSettings(Collection<String> c) { 556 if (c == null || c.isEmpty()) { 557 return ""; 558 } 559 560 StringBuilder b = new StringBuilder(); 561 boolean start = true; 562 for (String s : c) { 563 if ("".equals(s)) { 564 continue; 565 } 566 if (!start) { 567 b.append(':'); 568 } 569 b.append(s); 570 start = false; 571 } 572 return b.toString(); 573 } 574 575 576 577 private void createAndConnectService(@NonNull ComponentName component, int userId) { 578 mCurrentVrService = VrManagerService.create(mContext, component, userId); 579 mCurrentVrService.connect(); 580 Slog.i(TAG, "Connecting " + component + " for user " + userId); 581 } 582 583 /** 584 * Send VR mode change callbacks to HAL and system services if mode has actually changed. 585 * <p/> 586 * Note: Must be called while holding {@code mLock}. 587 * 588 * @param enabled new state of the VR mode. 589 * @param exemptedComponent a component to exempt from AppOps restrictions for overlays. 590 */ 591 private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) { 592 if (mVrModeEnabled != enabled) { 593 mVrModeEnabled = enabled; 594 595 // Log mode change event. 596 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); 597 setVrModeNative(mVrModeEnabled); 598 599 updateOverlayStateLocked(exemptedComponent); 600 onVrModeChangedLocked(); 601 } 602 } 603 604 /** 605 * Notify system services of VR mode change. 606 * <p/> 607 * Note: Must be called while holding {@code mLock}. 608 */ 609 private void onVrModeChangedLocked() { 610 mHandler.sendMessage(mHandler.obtainMessage(MSG_VR_STATE_CHANGE, 611 (mVrModeEnabled) ? 1 : 0, 0)); 612 } 613 614 /** 615 * Helper function for making ManagedApplicationService instances. 616 */ 617 private static ManagedApplicationService create(@NonNull Context context, 618 @NonNull ComponentName component, int userId) { 619 return ManagedApplicationService.build(context, component, userId, 620 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS, 621 sBinderChecker); 622 } 623 624 /* 625 * Implementation of VrManagerInternal calls. These are callable from system services. 626 */ 627 628 private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName, 629 int userId, @NonNull ComponentName callingPackage) { 630 synchronized (mLock) { 631 return updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage); 632 } 633 } 634 635 private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) { 636 synchronized (mLock) { 637 return mComponentObserver.isValid(targetPackageName, userId); 638 } 639 } 640 641 private boolean isCurrentVrListener(String packageName, int userId) { 642 synchronized (mLock) { 643 if (mCurrentVrService == null) { 644 return false; 645 } 646 return mCurrentVrService.getComponent().getPackageName().equals(packageName) && 647 userId == mCurrentVrService.getUserId(); 648 } 649 } 650 651 /* 652 * Implementation of IVrManager calls. 653 */ 654 655 private void addStateCallback(IVrStateCallbacks cb) { 656 mRemoteCallbacks.register(cb); 657 } 658 659 private void removeStateCallback(IVrStateCallbacks cb) { 660 mRemoteCallbacks.unregister(cb); 661 } 662 663 private boolean getVrMode() { 664 synchronized (mLock) { 665 return mVrModeEnabled; 666 } 667 } 668} 669