blob: aa6f59ef6e9a5f5a281b653d2f4845762bf3d46d [file] [log] [blame]
Ruben Brunke24b9a62016-02-16 21:38:24 -08001/**
Ruben Brunkdd18a0b2015-12-04 16:16:31 -08002 * 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
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080018import android.app.AppOpsManager;
Ruben Brunke24b9a62016-02-16 21:38:24 -080019import android.annotation.NonNull;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080020import android.content.Context;
Ruben Brunke24b9a62016-02-16 21:38:24 -080021import android.content.ComponentName;
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080022import android.os.Binder;
Ruben Brunke24b9a62016-02-16 21:38:24 -080023import android.os.Handler;
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080024import android.os.IBinder;
Ruben Brunke24b9a62016-02-16 21:38:24 -080025import android.os.IInterface;
26import android.os.Looper;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080027import android.os.RemoteException;
Ruben Brunke24b9a62016-02-16 21:38:24 -080028import android.provider.Settings;
29import android.service.vr.IVrListener;
30import android.service.vr.VrListenerService;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080031import android.util.ArraySet;
32import android.util.Slog;
33
Ruben Brunke24b9a62016-02-16 21:38:24 -080034import com.android.internal.R;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080035import com.android.server.SystemService;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080036import com.android.server.utils.ManagedApplicationService.PendingEvent;
Ruben Brunke24b9a62016-02-16 21:38:24 -080037import com.android.server.vr.EnabledComponentsObserver.EnabledComponentChangeListener;
38import com.android.server.utils.ManagedApplicationService;
39import com.android.server.utils.ManagedApplicationService.BinderChecker;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080040
41import java.util.ArrayList;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080042import java.util.Objects;
Ruben Brunke24b9a62016-02-16 21:38:24 -080043import java.util.Set;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080044
45/**
Ruben Brunke24b9a62016-02-16 21:38:24 -080046 * Service tracking whether VR mode is active, and notifying listening services of state changes.
47 * <p/>
48 * Services running in system server may modify the state of VrManagerService via the interface in
49 * VrManagerInternal, and may register to receive callbacks when the system VR mode changes via the
50 * interface given in VrStateListener.
51 * <p/>
52 * Device vendors may choose to receive VR state changes by implementing the VR mode HAL, e.g.:
53 * hardware/libhardware/modules/vr
54 * <p/>
55 * In general applications may enable or disable VR mode by calling
56 * {@link android.app.Activity#setVrMode)}. An application may also implement a service to be run
57 * while in VR mode by implementing {@link android.service.vr.VrListenerService}.
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080058 *
Ruben Brunke24b9a62016-02-16 21:38:24 -080059 * @see {@link android.service.vr.VrListenerService}
60 * @see {@link com.android.server.vr.VrManagerInternal}
61 * @see {@link com.android.server.vr.VrStateListener}
62 *
63 * @hide
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080064 */
Ruben Brunke24b9a62016-02-16 21:38:24 -080065public class VrManagerService extends SystemService implements EnabledComponentChangeListener{
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080066
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080067 public static final String TAG = "VrManagerService";
68
Ruben Brunkbaa4b552016-02-02 16:27:37 -080069 private static native void initializeNative();
70 private static native void setVrModeNative(boolean enabled);
71
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080072 private final Object mLock = new Object();
Svetoslav Ganov47d98de2016-03-01 15:01:14 -080073
74 private final IBinder mOverlayToken = new Binder();
75
Ruben Brunke24b9a62016-02-16 21:38:24 -080076 // State protected by mLock
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080077 private boolean mVrModeEnabled = false;
Ruben Brunke24b9a62016-02-16 21:38:24 -080078 private final Set<VrStateListener> mListeners = new ArraySet<>();
79 private EnabledComponentsObserver mComponentObserver;
80 private ManagedApplicationService mCurrentVrService;
81 private Context mContext;
Ruben Brunkc7354fe2016-03-07 23:37:12 -080082 private ComponentName mCurrentVrModeComponent;
83 private int mCurrentVrModeUser;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080084
Ruben Brunke24b9a62016-02-16 21:38:24 -080085 private static final BinderChecker sBinderChecker = new BinderChecker() {
86 @Override
87 public IInterface asInterface(IBinder binder) {
88 return IVrListener.Stub.asInterface(binder);
89 }
90
91 @Override
92 public boolean checkType(IInterface service) {
93 return service instanceof IVrListener;
94 }
95 };
96
97 /**
98 * Called when a user, package, or setting changes that could affect whether or not the
99 * currently bound VrListenerService is changed.
100 */
101 @Override
102 public void onEnabledComponentChanged() {
103 synchronized (mLock) {
104 if (mCurrentVrService == null) {
105 return; // No active services
106 }
107
108 // There is an active service, update it if needed
109 updateCurrentVrServiceLocked(mVrModeEnabled, mCurrentVrService.getComponent(),
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800110 mCurrentVrService.getUserId(), null);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800111 }
112 }
113
114 /**
115 * Implementation of VrManagerInternal. Callable only from system services.
116 */
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800117 private final class LocalService extends VrManagerInternal {
118 @Override
119 public boolean isInVrMode() {
120 return VrManagerService.this.getVrMode();
121 }
122
123 @Override
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800124 public void setVrMode(boolean enabled, ComponentName packageName, int userId,
125 ComponentName callingPackage) {
126 VrManagerService.this.setVrMode(enabled, packageName, userId, callingPackage);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800127 }
128
129 @Override
Ruben Brunk8f1d5cb2016-03-22 18:08:41 -0700130 public boolean isCurrentVrListener(String packageName, int userId) {
131 return VrManagerService.this.isCurrentVrListener(packageName, userId);
132 }
133
134 @Override
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800135 public void registerListener(VrStateListener listener) {
136 VrManagerService.this.addListener(listener);
137 }
138
139 @Override
140 public void unregisterListener(VrStateListener listener) {
141 VrManagerService.this.removeListener(listener);
142 }
Ruben Brunke24b9a62016-02-16 21:38:24 -0800143
144 @Override
145 public int hasVrPackage(ComponentName packageName, int userId) {
146 return VrManagerService.this.hasVrPackage(packageName, userId);
147 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800148 }
149
150 public VrManagerService(Context context) {
151 super(context);
152 }
153
154 @Override
155 public void onStart() {
Ruben Brunkbaa4b552016-02-02 16:27:37 -0800156 synchronized(mLock) {
157 initializeNative();
Ruben Brunke24b9a62016-02-16 21:38:24 -0800158 mContext = getContext();
Ruben Brunkbaa4b552016-02-02 16:27:37 -0800159 }
160
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800161 publishLocalService(VrManagerInternal.class, new LocalService());
162 }
163
Ruben Brunke24b9a62016-02-16 21:38:24 -0800164 @Override
165 public void onBootPhase(int phase) {
Ruben Brunk85070042016-03-21 12:10:38 -0700166 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800167 synchronized (mLock) {
168 Looper looper = Looper.getMainLooper();
169 Handler handler = new Handler(looper);
170 ArrayList<EnabledComponentChangeListener> listeners = new ArrayList<>();
171 listeners.add(this);
172 mComponentObserver = EnabledComponentsObserver.build(mContext, handler,
173 Settings.Secure.ENABLED_VR_LISTENERS, looper,
174 android.Manifest.permission.BIND_VR_LISTENER_SERVICE,
175 VrListenerService.SERVICE_INTERFACE, mLock, listeners);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800176
Ruben Brunke24b9a62016-02-16 21:38:24 -0800177 mComponentObserver.rebuildAll();
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800178 }
179 }
180 }
181
Ruben Brunke24b9a62016-02-16 21:38:24 -0800182 @Override
183 public void onStartUser(int userHandle) {
184 synchronized (mLock) {
185 mComponentObserver.onUsersChanged();
186 }
187 }
188
189 @Override
190 public void onSwitchUser(int userHandle) {
191 synchronized (mLock) {
192 mComponentObserver.onUsersChanged();
193 }
194
195 }
196
197 @Override
198 public void onStopUser(int userHandle) {
199 synchronized (mLock) {
200 mComponentObserver.onUsersChanged();
201 }
202
203 }
204
205 @Override
206 public void onCleanupUser(int userHandle) {
207 synchronized (mLock) {
208 mComponentObserver.onUsersChanged();
209 }
210 }
211
Ruben Brunk29931bc2016-03-11 00:24:26 -0800212 private void updateOverlayStateLocked(ComponentName exemptedComponent) {
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800213 final long identity = Binder.clearCallingIdentity();
214 try {
215 AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
216 if (appOpsManager != null) {
Ruben Brunk29931bc2016-03-11 00:24:26 -0800217 String[] exemptions = (exemptedComponent == null) ? new String[0] :
218 new String[] { exemptedComponent.getPackageName() };
219
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800220 appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
Ruben Brunk29931bc2016-03-11 00:24:26 -0800221 mVrModeEnabled, mOverlayToken, exemptions);
Svetoslav Ganov47d98de2016-03-01 15:01:14 -0800222 }
223 } finally {
224 Binder.restoreCallingIdentity(identity);
225 }
226 }
227
Ruben Brunke24b9a62016-02-16 21:38:24 -0800228 /**
229 * Send VR mode changes (if the mode state has changed), and update the bound/unbound state of
230 * the currently selected VR listener service. If the component selected for the VR listener
231 * service has changed, unbind the previous listener and bind the new listener (if enabled).
232 * <p/>
233 * Note: Must be called while holding {@code mLock}.
234 *
235 * @param enabled new state for VR mode.
236 * @param component new component to be bound as a VR listener.
237 * @param userId user owning the component to be bound.
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800238 * @param calling the component currently using VR mode, or null to leave unchanged.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800239 *
240 * @return {@code true} if the component/user combination specified is valid.
241 */
242 private boolean updateCurrentVrServiceLocked(boolean enabled,
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800243 @NonNull ComponentName component, int userId, ComponentName calling) {
244
245 boolean sendUpdatedCaller = false;
Ruben Brunke24b9a62016-02-16 21:38:24 -0800246
Ruben Brunke24b9a62016-02-16 21:38:24 -0800247 boolean validUserComponent = (mComponentObserver.isValid(component, userId) ==
248 EnabledComponentsObserver.NO_ERROR);
249
Ruben Brunk29931bc2016-03-11 00:24:26 -0800250 // Always send mode change events.
251 changeVrModeLocked(enabled, (enabled && validUserComponent) ? component : null);
252
Ruben Brunke24b9a62016-02-16 21:38:24 -0800253 if (!enabled || !validUserComponent) {
254 // Unbind whatever is running
255 if (mCurrentVrService != null) {
256 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
257 mCurrentVrService.getUserId());
258 mCurrentVrService.disconnect();
259 mCurrentVrService = null;
260 }
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800261 } else {
262 if (mCurrentVrService != null) {
263 // Unbind any running service that doesn't match the component/user selection
264 if (mCurrentVrService.disconnectIfNotMatching(component, userId)) {
265 Slog.i(TAG, "Disconnecting " + mCurrentVrService.getComponent() + " for user " +
266 mCurrentVrService.getUserId());
267 createAndConnectService(component, userId);
268 sendUpdatedCaller = true;
269 }
270 // The service with the correct component/user is bound
271 } else {
272 // Nothing was previously running, bind a new service
273 createAndConnectService(component, userId);
274 sendUpdatedCaller = true;
275 }
Ruben Brunke24b9a62016-02-16 21:38:24 -0800276 }
277
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800278 if (calling != null && !Objects.equals(calling, mCurrentVrModeComponent)) {
279 mCurrentVrModeComponent = calling;
280 mCurrentVrModeUser = userId;
281 sendUpdatedCaller = true;
282 }
283
284 if (mCurrentVrService != null && sendUpdatedCaller) {
285 final ComponentName c = mCurrentVrModeComponent;
286 mCurrentVrService.sendEvent(new PendingEvent() {
287 @Override
288 public void runEvent(IInterface service) throws RemoteException {
289 IVrListener l = (IVrListener) service;
290 l.focusedActivityChanged(c);
291 }
292 });
Ruben Brunke24b9a62016-02-16 21:38:24 -0800293 }
294
295 return validUserComponent;
296 }
297
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800298 private void createAndConnectService(@NonNull ComponentName component, int userId) {
299 mCurrentVrService = VrManagerService.create(mContext, component, userId);
300 mCurrentVrService.connect();
301 Slog.i(TAG, "Connecting " + component + " for user " + userId);
302 }
303
Ruben Brunke24b9a62016-02-16 21:38:24 -0800304 /**
305 * Send VR mode change callbacks to HAL and system services if mode has actually changed.
306 * <p/>
307 * Note: Must be called while holding {@code mLock}.
308 *
309 * @param enabled new state of the VR mode.
Ruben Brunk29931bc2016-03-11 00:24:26 -0800310 * @param exemptedComponent a component to exempt from AppOps restrictions for overlays.
Ruben Brunke24b9a62016-02-16 21:38:24 -0800311 */
Ruben Brunk29931bc2016-03-11 00:24:26 -0800312 private void changeVrModeLocked(boolean enabled, ComponentName exemptedComponent) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800313 if (mVrModeEnabled != enabled) {
314 mVrModeEnabled = enabled;
315
316 // Log mode change event.
317 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
318 setVrModeNative(mVrModeEnabled);
319
Ruben Brunk29931bc2016-03-11 00:24:26 -0800320 updateOverlayStateLocked(exemptedComponent);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800321 onVrModeChangedLocked();
322 }
323 }
324
325 /**
326 * Notify system services of VR mode change.
327 * <p/>
328 * Note: Must be called while holding {@code mLock}.
329 */
330 private void onVrModeChangedLocked() {
331 for (VrStateListener l : mListeners) {
332 l.onVrStateChanged(mVrModeEnabled);
333 }
334 }
335
336 /**
337 * Helper function for making ManagedApplicationService instances.
338 */
339 private static ManagedApplicationService create(@NonNull Context context,
340 @NonNull ComponentName component, int userId) {
341 return ManagedApplicationService.build(context, component, userId,
342 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
343 sBinderChecker);
344 }
345
346 /*
347 * Implementation of VrManagerInternal calls. These are callable from system services.
348 */
349
350 private boolean setVrMode(boolean enabled, @NonNull ComponentName targetPackageName,
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800351 int userId, @NonNull ComponentName callingPackage) {
Ruben Brunke24b9a62016-02-16 21:38:24 -0800352 synchronized (mLock) {
Ruben Brunkc7354fe2016-03-07 23:37:12 -0800353 return updateCurrentVrServiceLocked(enabled, targetPackageName, userId, callingPackage);
Ruben Brunke24b9a62016-02-16 21:38:24 -0800354 }
355 }
356
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800357 private boolean getVrMode() {
358 synchronized (mLock) {
359 return mVrModeEnabled;
360 }
361 }
362
Ruben Brunk8f1d5cb2016-03-22 18:08:41 -0700363 private boolean isCurrentVrListener(String packageName, int userId) {
364 synchronized (mLock) {
365 if (mCurrentVrService == null) {
366 return false;
367 }
368 return mCurrentVrService.getComponent().getPackageName().equals(packageName) &&
369 userId == mCurrentVrService.getUserId();
370 }
371 }
372
Ruben Brunke24b9a62016-02-16 21:38:24 -0800373 private void addListener(VrStateListener listener) {
374 synchronized (mLock) {
375 mListeners.add(listener);
376 }
377 }
378
379 private void removeListener(VrStateListener listener) {
380 synchronized (mLock) {
381 mListeners.remove(listener);
382 }
383 }
384
385 private int hasVrPackage(@NonNull ComponentName targetPackageName, int userId) {
386 synchronized (mLock) {
387 return mComponentObserver.isValid(targetPackageName, userId);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800388 }
389 }
390}