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