VrManagerService.java revision b56b72a8461dcc1a9dccd4c7019e2ecbf191fc1c
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.io.FileDescriptor; 54import java.io.PrintWriter; 55import java.lang.StringBuilder; 56import java.lang.ref.WeakReference; 57import java.util.ArrayList; 58import java.util.Collection; 59import java.util.Objects; 60import java.util.Set; 61 62/** 63 * Service tracking whether VR mode is active, and notifying listening services of state changes. 64 * <p/> 65 * Services running in system server may modify the state of VrManagerService via the interface in 66 * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the 67 * interface given in VrStateListener. 68 * <p/> 69 * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.: 70 * hardware/libhardware/modules/vr 71 * <p/> 72 * In general applications may enable or disable VR mode by calling 73 * {@link android.app.Activity#setVrModeEnabled)}. An application may also implement a service to 74 * be run while in VR mode by implementing {@link android.service.vr.VrListenerService}. 75 * 76 * @see {@link android.service.vr.VrListenerService} 77 * @see {@link com.android.server.vr.VrManagerInternal} 78 * @see {@link com.android.server.vr.VrStateListener} 79 * 80 * @hide 81 */ 82public class VrManagerService extends SystemService implements EnabledComponentChangeListener{ 83 84 public static final String TAG = "VrManagerService"; 85 86 public static final String VR_MANAGER_BINDER_SERVICE = "vrmanager"; 87 88 private static final int PENDING_STATE_DELAY_MS = 300; 89 90 private static native void initializeNative(); 91 private static native void setVrModeNative(boolean enabled); 92 93 private final Object mLock = new Object(); 94 95 private final IBinder mOverlayToken = new Binder(); 96 97 // State protected by mLock 98 private boolean mVrModeEnabled; 99 private EnabledComponentsObserver mComponentObserver; 100 private ManagedApplicationService mCurrentVrService; 101 private Context mContext; 102 private ComponentName mCurrentVrModeComponent; 103 private int mCurrentVrModeUser; 104 private boolean mWasDefaultGranted; 105 private boolean mGuard; 106 private final RemoteCallbackList<IVrStateCallbacks> mRemoteCallbacks = 107 new RemoteCallbackList<>(); 108 private final ArraySet<String> mPreviousToggledListenerSettings = new ArraySet<>(); 109 private String mPreviousNotificationPolicyAccessPackage; 110 private String mPreviousCoarseLocationPackage; 111 private String mPreviousManageOverlayPackage; 112 private VrState mPendingState; 113 114 private static final int MSG_VR_STATE_CHANGE = 0; 115 private static final int MSG_PENDING_VR_STATE_CHANGE = 1; 116 117 private final Handler mHandler = new Handler() { 118 @Override 119 public void handleMessage(Message msg) { 120 switch(msg.what) { 121 case MSG_VR_STATE_CHANGE : { 122 boolean state = (msg.arg1 == 1); 123 int i = mRemoteCallbacks.beginBroadcast(); 124 while (i > 0) { 125 i--; 126 try { 127 mRemoteCallbacks.getBroadcastItem(i).onVrStateChanged(state); 128 } catch (RemoteException e) { 129 // Noop 130 } 131 } 132 mRemoteCallbacks.finishBroadcast(); 133 } break; 134 case MSG_PENDING_VR_STATE_CHANGE : { 135 synchronized(mLock) { 136 VrManagerService.this.consumeAndApplyPendingStateLocked(); 137 } 138 } break; 139 default : 140 throw new IllegalStateException("Unknown message type: " + msg.what); 141 } 142 } 143 }; 144 145 private static class VrState { 146 final boolean enabled; 147 final int userId; 148 final ComponentName targetPackageName; 149 final ComponentName callingPackage; 150 151 VrState(boolean enabled, ComponentName targetPackageName, int userId, 152 ComponentName callingPackage) { 153 this.enabled = enabled; 154 this.userId = userId; 155 this.targetPackageName = targetPackageName; 156 this.callingPackage = callingPackage; 157 } 158 }; 159 160 private static final BinderChecker sBinderChecker = new BinderChecker() { 161 @Override 162 public IInterface asInterface(IBinder binder) { 163 return IVrListener.Stub.asInterface(binder); 164 } 165 166 @Override 167 public boolean checkType(IInterface service) { 168 return service instanceof IVrListener; 169 } 170 }; 171 172 /** 173 * Called when a user, package, or setting changes that could affect whether or not the 174 * currently bound VrListenerService is changed. 175 */ 176 @Override 177 public void onEnabledComponentChanged() { 178 synchronized (mLock) { 179 if (mCurrentVrService == null) { 180 return; // No active services 181 } 182 183 // If there is a pending state change, we'd better deal with that first 184 consumeAndApplyPendingStateLocked(); 185 186 if (mCurrentVrService == null) { 187 return; // No active services 188 } 189 190 // There is an active service, update it if needed 191 updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(), 192 mCurrentVrService.getUserId(), null); 193 } 194 } 195 196 private final IVrManager mVrManager = new IVrManager.Stub() { 197 198 @Override 199 public void registerListener(IVrStateCallbacks cb) { 200 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); 201 if (cb == null) { 202 throw new IllegalArgumentException("Callback binder object is null."); 203 } 204 205 VrManagerService.this.addStateCallback(cb); 206 } 207 208 @Override 209 public void unregisterListener(IVrStateCallbacks cb) { 210 enforceCallerPermission(Manifest.permission.ACCESS_VR_MANAGER); 211 if (cb == null) { 212 throw new IllegalArgumentException("Callback binder object is null."); 213 } 214 215 VrManagerService.this.removeStateCallback(cb); 216 } 217 218 @Override 219 public boolean getVrModeState() { 220 return VrManagerService.this.getVrMode(); 221 } 222 223 @Override 224 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 225 if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP) 226 != PackageManager.PERMISSION_GRANTED) { 227 pw.println("permission denied: can't dump VrManagerService from pid=" 228 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()); 229 return; 230 } 231 pw.print("mVrModeEnabled="); 232 pw.println(mVrModeEnabled); 233 pw.print("mCurrentVrModeUser="); 234 pw.println(mCurrentVrModeUser); 235 pw.print("mRemoteCallbacks="); 236 int i=mRemoteCallbacks.beginBroadcast(); // create the broadcast item array 237 while(i-->0) { 238 pw.print(mRemoteCallbacks.getBroadcastItem(i)); 239 if (i>0) pw.print(", "); 240 } 241 mRemoteCallbacks.finishBroadcast(); 242 pw.println(); 243 pw.print("mCurrentVrService="); 244 pw.println(mCurrentVrService != null ? mCurrentVrService.getComponent() : "(none)"); 245 pw.print("mCurrentVrModeComponent="); 246 pw.println(mCurrentVrModeComponent); 247 } 248 249 }; 250 251 private void enforceCallerPermission(String permission) { 252 if (mContext.checkCallingOrSelfPermission(permission) 253 != PackageManager.PERMISSION_GRANTED) { 254 throw new SecurityException("Caller does not hold the permission " + permission); 255 } 256 } 257 258 /** 259 * Implementation of VrManagerInternal. Callable only from system services. 260 */ 261 private final class LocalService extends VrManagerInternal { 262 @Override 263 public void setVrMode(boolean enabled, ComponentName packageName, int userId, 264 ComponentName callingPackage) { 265 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage); 266 } 267 268 @Override 269 public boolean isCurrentVrListener(String packageName, int userId) { 270 return VrManagerService.this.isCurrentVrListener(packageName, userId); 271 } 272 273 @Override 274 public int hasVrPackage(ComponentName packageName, int userId) { 275 return VrManagerService.this.hasVrPackage(packageName, userId); 276 } 277 } 278 279 public VrManagerService(Context context) { 280 super(context); 281 } 282 283 @Override 284 public void onStart() { 285 synchronized(mLock) { 286 initializeNative(); 287 mContext = getContext(); 288 } 289 290 publishLocalService(VrManagerInternal.class, new LocalService()); 291 publishBinderService(VR_MANAGER_BINDER_SERVICE, mVrManager.asBinder()); 292 } 293 294 @Override 295 public void onBootPhase(int phase) { 296 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { 297 synchronized (mLock) { 298 Looper looper = Looper.getMainLooper(); 299 Handler handler = new Handler(looper); 300 ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>(); 301 listeners.add(this); 302 mComponentObserver = EnabledComponentsObserver.build(mContext, handler, 303 Settings.Secure.ENABLED_VR_LISTENERS, looper, 304 android.Manifest.permission.BIND_VR_LISTENER_SERVICE, 305 VrListenerService.SERVICE_INTERFACE, mLock, listeners); 306 307 mComponentObserver.rebuildAll(); 308 } 309 } 310 } 311 312 @Override 313 public void onStartUser(int userHandle) { 314 synchronized (mLock) { 315 mComponentObserver.onUsersChanged(); 316 } 317 } 318 319 @Override 320 public void onSwitchUser(int userHandle) { 321 synchronized (mLock) { 322 mComponentObserver.onUsersChanged(); 323 } 324 325 } 326 327 @Override 328 public void onStopUser(int userHandle) { 329 synchronized (mLock) { 330 mComponentObserver.onUsersChanged(); 331 } 332 333 } 334 335 @Override 336 public void onCleanupUser(int userHandle) { 337 synchronized (mLock) { 338 mComponentObserver.onUsersChanged(); 339 } 340 } 341 342 private void updateOverlayStateLocked(ComponentName exemptedComponent) { 343 final long identity = Binder.clearCallingIdentity(); 344 try { 345 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class); 346 if (appOpsManager != null) { 347 String[] exemptions = (exemptedComponent == null) ? new String[0] : 348 new String[] { exemptedComponent.getPackageName() }; 349 350 appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW, 351 mVrModeEnabled, mOverlayToken, exemptions); 352 } 353 } finally { 354 Binder.restoreCallingIdentity(identity); 355 } 356 } 357 358 /** 359 * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of 360 * the currently selected VR listener service. If the component selected for the VR listener 361 * service has changed, unbind the previous listener and bind the new listener (if enabled). 362 * <p/> 363 * Note: Must be called while holding {@code mLock}. 364 * 365 * @param enabled new state for VR mode. 366 * @param component new component to be bound as a VR listener. 367 * @param userId user owning the component to be bound. 368 * @param calling the component currently using VR mode, or null to leave unchanged. 369 * 370 * @return {@code true} if the component/user combination specified is valid. 371 */ 372 private boolean updateCurrentVrServiceLocked(boolean enabled, @NonNull ComponentName component, 373 int userId, ComponentName calling) { 374 375 boolean sendUpdatedCaller = false; 376 final long identity = Binder.clearCallingIdentity(); 377 try { 378 379 boolean validUserComponent = (mComponentObserver.isValid(component, userId) == 380 EnabledComponentsObserver.NO_ERROR); 381 382 // Always send mode change events. 383 changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null); 384 385 if (!enabled || !validUserComponent) { 386 // Unbind whatever is running 387 if (mCurrentVrService != null) { 388 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " + 389 mCurrentVrService.getUserId()); 390 mCurrentVrService.disconnect(); 391 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 392 new UserHandle(mCurrentVrService.getUserId())); 393 mCurrentVrService = null; 394 } 395 } else { 396 if (mCurrentVrService != null) { 397 // Unbind any running service that doesn't match the component/user selection 398 if (mCurrentVrService.disconnectIfNotMatching(component, userId)) { 399 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + 400 " for user " + mCurrentVrService.getUserId()); 401 disableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 402 new UserHandle(mCurrentVrService.getUserId())); 403 createAndConnectService(component, userId); 404 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 405 new UserHandle(mCurrentVrService.getUserId())); 406 sendUpdatedCaller = true; 407 } 408 // The service with the correct component/user is bound 409 } else { 410 // Nothing was previously running, bind a new service 411 createAndConnectService(component, userId); 412 enableImpliedPermissionsLocked(mCurrentVrService.getComponent(), 413 new UserHandle(mCurrentVrService.getUserId())); 414 sendUpdatedCaller = true; 415 } 416 } 417 418 if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) { 419 mCurrentVrModeComponent = calling; 420 mCurrentVrModeUser = userId; 421 sendUpdatedCaller = true; 422 } 423 424 if (mCurrentVrService != null && sendUpdatedCaller) { 425 final ComponentName c = mCurrentVrModeComponent; 426 mCurrentVrService.sendEvent(new PendingEvent() { 427 @Override 428 public void runEvent(IInterface service) throws RemoteException { 429 IVrListener l = (IVrListener) service; 430 l.focusedActivityChanged(c); 431 } 432 }); 433 } 434 435 return validUserComponent; 436 } finally { 437 Binder.restoreCallingIdentity(identity); 438 } 439 } 440 441 /** 442 * Enable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given 443 * component package and user. 444 * 445 * @param component the component whose package should be enabled. 446 * @param userId the user that owns the given component. 447 */ 448 private void enableImpliedPermissionsLocked(ComponentName component, UserHandle userId) { 449 if (mGuard) { 450 // Impossible 451 throw new IllegalStateException("Enabling permissions without disabling."); 452 } 453 mGuard = true; 454 455 PackageManager pm = mContext.getPackageManager(); 456 457 String pName = component.getPackageName(); 458 if (pm == null) { 459 Slog.e(TAG, "Couldn't set implied permissions for " + pName + 460 ", PackageManager isn't running"); 461 return; 462 } 463 464 ApplicationInfo info = null; 465 try { 466 info = pm.getApplicationInfo(pName, PackageManager.GET_META_DATA); 467 } catch (NameNotFoundException e) { 468 } 469 470 if (info == null) { 471 Slog.e(TAG, "Couldn't set implied permissions for " + pName + ", no such package."); 472 return; 473 } 474 475 if (!(info.isSystemApp() || info.isUpdatedSystemApp())) { 476 return; // Application is not pre-installed, avoid setting implied permissions 477 } 478 479 mWasDefaultGranted = true; 480 481 grantCoarseLocationAccess(pName, userId); 482 grantOverlayAccess(pName, userId); 483 grantNotificationPolicyAccess(pName); 484 grantNotificationListenerAccess(pName, userId); 485 } 486 487 /** 488 * Disable the permission given in {@link #IMPLIED_VR_LISTENER_PERMISSIONS} for the given 489 * component package and user. 490 * 491 * @param component the component whose package should be disabled. 492 * @param userId the user that owns the given component. 493 */ 494 private void disableImpliedPermissionsLocked(ComponentName component, UserHandle userId) { 495 if (!mGuard) { 496 // Impossible 497 throw new IllegalStateException("Disabling permissions without enabling."); 498 } 499 mGuard = false; 500 501 PackageManager pm = mContext.getPackageManager(); 502 503 if (pm == null) { 504 Slog.e(TAG, "Couldn't remove implied permissions for " + component + 505 ", PackageManager isn't running"); 506 return; 507 } 508 509 String pName = component.getPackageName(); 510 if (mWasDefaultGranted) { 511 revokeCoarseLocationAccess(userId); 512 revokeOverlayAccess(userId); 513 revokeNotificationPolicyAccess(pName); 514 revokeNotificiationListenerAccess(); 515 mWasDefaultGranted = false; 516 } 517 518 } 519 520 private void grantCoarseLocationAccess(String pkg, UserHandle userId) { 521 PackageManager pm = mContext.getPackageManager(); 522 boolean prev = (PackageManager.PERMISSION_GRANTED == 523 pm.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION, pkg)); 524 mPreviousCoarseLocationPackage = null; 525 if (!prev) { 526 pm.grantRuntimePermission(pkg, android.Manifest.permission.ACCESS_COARSE_LOCATION, 527 userId); 528 mPreviousCoarseLocationPackage = pkg; 529 } 530 } 531 532 private void revokeCoarseLocationAccess(UserHandle userId) { 533 PackageManager pm = mContext.getPackageManager(); 534 if (mPreviousCoarseLocationPackage != null) { 535 pm.revokeRuntimePermission(mPreviousCoarseLocationPackage, 536 android.Manifest.permission.ACCESS_COARSE_LOCATION, userId); 537 mPreviousCoarseLocationPackage = null; 538 } 539 } 540 541 private void grantOverlayAccess(String pkg, UserHandle userId) { 542 PackageManager pm = mContext.getPackageManager(); 543 boolean prev = (PackageManager.PERMISSION_GRANTED == 544 pm.checkPermission(android.Manifest.permission.SYSTEM_ALERT_WINDOW, pkg)); 545 mPreviousManageOverlayPackage = null; 546 if (!prev) { 547 pm.grantRuntimePermission(pkg, android.Manifest.permission.SYSTEM_ALERT_WINDOW, 548 userId); 549 mPreviousManageOverlayPackage = pkg; 550 } 551 } 552 553 private void revokeOverlayAccess(UserHandle userId) { 554 PackageManager pm = mContext.getPackageManager(); 555 if (mPreviousManageOverlayPackage != null) { 556 pm.revokeRuntimePermission(mPreviousManageOverlayPackage, 557 android.Manifest.permission.SYSTEM_ALERT_WINDOW, userId); 558 mPreviousManageOverlayPackage = null; 559 } 560 } 561 562 private void grantNotificationPolicyAccess(String pkg) { 563 NotificationManager nm = mContext.getSystemService(NotificationManager.class); 564 boolean prev = nm.isNotificationPolicyAccessGrantedForPackage(pkg); 565 mPreviousNotificationPolicyAccessPackage = null; 566 if (!prev) { 567 mPreviousNotificationPolicyAccessPackage = pkg; 568 nm.setNotificationPolicyAccessGranted(pkg, true); 569 } 570 } 571 572 private void revokeNotificationPolicyAccess(String pkg) { 573 NotificationManager nm = mContext.getSystemService(NotificationManager.class); 574 if (mPreviousNotificationPolicyAccessPackage != null) { 575 if (mPreviousNotificationPolicyAccessPackage.equals(pkg)) { 576 // Remove any DND zen rules possibly created by the package. 577 nm.removeAutomaticZenRules(mPreviousNotificationPolicyAccessPackage); 578 // Remove Notification Policy Access. 579 nm.setNotificationPolicyAccessGranted(mPreviousNotificationPolicyAccessPackage, false); 580 mPreviousNotificationPolicyAccessPackage = null; 581 } else { 582 Slog.e(TAG, "Couldn't remove Notification Policy Access for package: " + pkg); 583 } 584 } 585 } 586 587 private void grantNotificationListenerAccess(String pkg, UserHandle userId) { 588 PackageManager pm = mContext.getPackageManager(); 589 ArraySet<ComponentName> possibleServices = EnabledComponentsObserver.loadComponentNames(pm, 590 userId.getIdentifier(), NotificationListenerService.SERVICE_INTERFACE, 591 android.Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE); 592 ContentResolver resolver = mContext.getContentResolver(); 593 594 ArraySet<String> current = getCurrentNotifListeners(resolver); 595 596 mPreviousToggledListenerSettings.clear(); 597 598 for (ComponentName c : possibleServices) { 599 String flatName = c.flattenToString(); 600 if (Objects.equals(c.getPackageName(), pkg) 601 && !current.contains(flatName)) { 602 mPreviousToggledListenerSettings.add(flatName); 603 current.add(flatName); 604 } 605 } 606 607 if (current.size() > 0) { 608 String flatSettings = formatSettings(current); 609 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 610 flatSettings); 611 } 612 } 613 614 private void revokeNotificiationListenerAccess() { 615 if (mPreviousToggledListenerSettings.isEmpty()) { 616 return; 617 } 618 619 ContentResolver resolver = mContext.getContentResolver(); 620 ArraySet<String> current = getCurrentNotifListeners(resolver); 621 622 current.removeAll(mPreviousToggledListenerSettings); 623 mPreviousToggledListenerSettings.clear(); 624 625 String flatSettings = formatSettings(current); 626 Settings.Secure.putString(resolver, Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, 627 flatSettings); 628 } 629 630 private ArraySet<String> getCurrentNotifListeners(ContentResolver resolver) { 631 String flat = Settings.Secure.getString(resolver, 632 Settings.Secure.ENABLED_NOTIFICATION_LISTENERS); 633 634 ArraySet<String> current = new ArraySet<>(); 635 if (flat != null) { 636 String[] allowed = flat.split(":"); 637 for (String s : allowed) { 638 current.add(s); 639 } 640 } 641 return current; 642 } 643 644 private static String formatSettings(Collection<String> c) { 645 if (c == null || c.isEmpty()) { 646 return ""; 647 } 648 649 StringBuilder b = new StringBuilder(); 650 boolean start = true; 651 for (String s : c) { 652 if ("".equals(s)) { 653 continue; 654 } 655 if (!start) { 656 b.append(':'); 657 } 658 b.append(s); 659 start = false; 660 } 661 return b.toString(); 662 } 663 664 665 666 private void createAndConnectService(@NonNull ComponentName component, int userId) { 667 mCurrentVrService = VrManagerService.create(mContext, component, userId); 668 mCurrentVrService.connect(); 669 Slog.i(TAG, "Connecting " + component + " for user " + userId); 670 } 671 672 /** 673 * Send VR mode change callbacks to HAL and system services if mode has actually changed. 674 * <p/> 675 * Note: Must be called while holding {@code mLock}. 676 * 677 * @param enabled new state of the VR mode. 678 * @param exemptedComponent a component to exempt from AppOps restrictions for overlays. 679 */ 680 private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) { 681 if (mVrModeEnabled != enabled) { 682 mVrModeEnabled = enabled; 683 684 // Log mode change event. 685 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled")); 686 setVrModeNative(mVrModeEnabled); 687 688 updateOverlayStateLocked(exemptedComponent); 689 onVrModeChangedLocked(); 690 } 691 } 692 693 /** 694 * Notify system services of VR mode change. 695 * <p/> 696 * Note: Must be called while holding {@code mLock}. 697 */ 698 private void onVrModeChangedLocked() { 699 mHandler.sendMessage(mHandler.obtainMessage(MSG_VR_STATE_CHANGE, 700 (mVrModeEnabled) ? 1 : 0, 0)); 701 } 702 703 /** 704 * Helper function for making ManagedApplicationService instances. 705 */ 706 private static ManagedApplicationService create(@NonNull Context context, 707 @NonNull ComponentName component, int userId) { 708 return ManagedApplicationService.build(context, component, userId, 709 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS, 710 sBinderChecker); 711 } 712 713 private void consumeAndApplyPendingStateLocked() { 714 if (mPendingState != null) { 715 updateCurrentVrServiceLocked(mPendingState.enabled, 716 mPendingState.targetPackageName, mPendingState.userId, 717 mPendingState.callingPackage); 718 mPendingState = null; 719 } 720 } 721 722 /* 723 * Implementation of VrManagerInternal calls. These are callable from system services. 724 */ 725 726 private void setVrMode(boolean enabled, @NonNull ComponentName targetPackageName, 727 int userId, @NonNull ComponentName callingPackage) { 728 729 synchronized (mLock) { 730 731 if (!enabled && mCurrentVrService != null) { 732 // If we're transitioning out of VR mode, delay briefly to avoid expensive HAL calls 733 // and service bind/unbind in case we are immediately switching to another VR app. 734 if (mPendingState == null) { 735 mHandler.sendEmptyMessageDelayed(MSG_PENDING_VR_STATE_CHANGE, 736 PENDING_STATE_DELAY_MS); 737 } 738 739 mPendingState = new VrState(enabled, targetPackageName, userId, callingPackage); 740 return; 741 } else { 742 mHandler.removeMessages(MSG_PENDING_VR_STATE_CHANGE); 743 mPendingState = null; 744 } 745 746 updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage); 747 } 748 } 749 750 private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) { 751 synchronized (mLock) { 752 return mComponentObserver.isValid(targetPackageName, userId); 753 } 754 } 755 756 private boolean isCurrentVrListener(String packageName, int userId) { 757 synchronized (mLock) { 758 if (mCurrentVrService == null) { 759 return false; 760 } 761 return mCurrentVrService.getComponent().getPackageName().equals(packageName) && 762 userId == mCurrentVrService.getUserId(); 763 } 764 } 765 766 /* 767 * Implementation of IVrManager calls. 768 */ 769 770 private void addStateCallback(IVrStateCallbacks cb) { 771 mRemoteCallbacks.register(cb); 772 } 773 774 private void removeStateCallback(IVrStateCallbacks cb) { 775 mRemoteCallbacks.unregister(cb); 776 } 777 778 private boolean getVrMode() { 779 synchronized (mLock) { 780 return mVrModeEnabled; 781 } 782 } 783} 784