Home | History | Annotate | Download | only in vr
      1 /**
      2  * Copyright (C) 2016 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  */
     16 package com.android.server.vr;
     17 
     18 import android.annotation.NonNull;
     19 import android.app.ActivityManager;
     20 import android.content.ComponentName;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.content.pm.ServiceInfo;
     27 import android.os.Handler;
     28 import android.os.Looper;
     29 import android.os.UserHandle;
     30 import android.os.UserManager;
     31 import android.provider.Settings;
     32 import android.text.TextUtils;
     33 import android.util.ArraySet;
     34 import android.util.Slog;
     35 import android.util.SparseArray;
     36 
     37 import com.android.internal.content.PackageMonitor;
     38 import com.android.server.vr.SettingsObserver.SettingChangeListener;
     39 
     40 import java.util.Collection;
     41 import java.util.List;
     42 import java.util.Set;
     43 
     44 /**
     45  * Detects changes in packages, settings, and current users that may affect whether components
     46  * implementing a given service can be run.
     47  *
     48  * @hide
     49  */
     50 public class EnabledComponentsObserver implements SettingChangeListener {
     51 
     52     private static final String TAG = EnabledComponentsObserver.class.getSimpleName();
     53     private static final String ENABLED_SERVICES_SEPARATOR = ":";
     54 
     55     public static final int NO_ERROR = 0;
     56     public static final int DISABLED = -1;
     57     public static final int NOT_INSTALLED = -2;
     58 
     59     private final Object mLock;
     60     private final Context mContext;
     61     private final String mSettingName;
     62     private final String mServiceName;
     63     private final String mServicePermission;
     64     private final SparseArray<ArraySet<ComponentName>> mInstalledSet = new SparseArray<>();
     65     private final SparseArray<ArraySet<ComponentName>> mEnabledSet = new SparseArray<>();
     66     private final Set<EnabledComponentChangeListener> mEnabledComponentListeners = new ArraySet<>();
     67 
     68     /**
     69      * Implement this to receive callbacks when relevant changes to the allowed components occur.
     70      */
     71     public interface EnabledComponentChangeListener {
     72 
     73         /**
     74          * Called when a change in the allowed components occurs.
     75          */
     76         void onEnabledComponentChanged();
     77     }
     78 
     79     private EnabledComponentsObserver(@NonNull Context context, @NonNull String settingName,
     80             @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock,
     81             @NonNull Collection<EnabledComponentChangeListener> listeners) {
     82         mLock = lock;
     83         mContext = context;
     84         mSettingName = settingName;
     85         mServiceName = serviceName;
     86         mServicePermission = servicePermission;
     87         mEnabledComponentListeners.addAll(listeners);
     88     }
     89 
     90     /**
     91      * Create a EnabledComponentObserver instance.
     92      *
     93      * @param context the context to query for changes.
     94      * @param handler a handler to receive lifecycle events from system services on.
     95      * @param settingName the name of a setting to monitor for a list of enabled components.
     96      * @param looper a {@link Looper} to use for receiving package callbacks.
     97      * @param servicePermission the permission required by the components to be bound.
     98      * @param serviceName the intent action implemented by the tracked components.
     99      * @param lock a lock object used to guard instance state in all callbacks and method calls.
    100      * @return an EnableComponentObserver instance.
    101      */
    102     public static EnabledComponentsObserver build(@NonNull Context context,
    103             @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper,
    104             @NonNull String servicePermission, @NonNull String serviceName,
    105             @NonNull final Object lock,
    106             @NonNull Collection<EnabledComponentChangeListener> listeners) {
    107 
    108         SettingsObserver s = SettingsObserver.build(context, handler, settingName);
    109 
    110         final EnabledComponentsObserver o = new EnabledComponentsObserver(context, settingName,
    111                 servicePermission, serviceName, lock, listeners);
    112 
    113         PackageMonitor packageMonitor = new PackageMonitor() {
    114             @Override
    115             public void onSomePackagesChanged() {
    116                 o.onPackagesChanged();
    117 
    118             }
    119 
    120             @Override
    121             public void onPackageDisappeared(String packageName, int reason) {
    122                 o.onPackagesChanged();
    123 
    124             }
    125 
    126             @Override
    127             public void onPackageModified(String packageName) {
    128                 o.onPackagesChanged();
    129 
    130             }
    131 
    132             @Override
    133             public boolean onHandleForceStop(Intent intent, String[] packages, int uid,
    134                     boolean doit) {
    135                 o.onPackagesChanged();
    136 
    137                 return super.onHandleForceStop(intent, packages, uid, doit);
    138             }
    139         };
    140 
    141         packageMonitor.register(context, looper, UserHandle.ALL, true);
    142 
    143         s.addListener(o);
    144 
    145         return o;
    146 
    147     }
    148 
    149     public void onPackagesChanged() {
    150         rebuildAll();
    151     }
    152 
    153     @Override
    154     public void onSettingChanged() {
    155         rebuildAll();
    156     }
    157 
    158     @Override
    159     public void onSettingRestored(String prevValue, String newValue, int userId) {
    160         rebuildAll();
    161     }
    162 
    163     public void onUsersChanged() {
    164         rebuildAll();
    165     }
    166 
    167     /**
    168      * Rebuild the sets of allowed components for each current user profile.
    169      */
    170     public void rebuildAll() {
    171         synchronized (mLock) {
    172             mInstalledSet.clear();
    173             mEnabledSet.clear();
    174             final int[] userIds = getCurrentProfileIds();
    175             for (int i : userIds) {
    176                 ArraySet<ComponentName> implementingPackages = loadComponentNamesForUser(i);
    177                 ArraySet<ComponentName> packagesFromSettings =
    178                         loadComponentNamesFromSetting(mSettingName, i);
    179                 packagesFromSettings.retainAll(implementingPackages);
    180 
    181                 mInstalledSet.put(i, implementingPackages);
    182                 mEnabledSet.put(i, packagesFromSettings);
    183 
    184             }
    185         }
    186         sendSettingChanged();
    187     }
    188 
    189     /**
    190      * Check whether a given component is present and enabled for the given user.
    191      *
    192      * @param component the component to check.
    193      * @param userId the user ID for the component to check.
    194      * @return {@code true} if present and enabled.
    195      */
    196     public int isValid(ComponentName component, int userId) {
    197         synchronized (mLock) {
    198             ArraySet<ComponentName> installedComponents = mInstalledSet.get(userId);
    199             if (installedComponents == null || !installedComponents.contains(component)) {
    200                 return NOT_INSTALLED;
    201             }
    202             ArraySet<ComponentName> validComponents = mEnabledSet.get(userId);
    203             if (validComponents == null || !validComponents.contains(component)) {
    204                 return DISABLED;
    205             }
    206             return NO_ERROR;
    207         }
    208     }
    209 
    210     /**
    211      * Return all VrListenerService components installed for this user.
    212      *
    213      * @param userId ID of the user to check.
    214      * @return a set of {@link ComponentName}s.
    215      */
    216     public ArraySet<ComponentName> getInstalled(int userId) {
    217         synchronized (mLock) {
    218             ArraySet<ComponentName> ret = mInstalledSet.get(userId);
    219             if (ret == null) {
    220                 return new ArraySet<ComponentName>();
    221             }
    222             return ret;
    223         }
    224     }
    225 
    226     /**
    227      * Return all VrListenerService components enabled for this user.
    228      *
    229      * @param userId ID of the user to check.
    230      * @return a set of {@link ComponentName}s.
    231      */
    232     public ArraySet<ComponentName> getEnabled(int userId) {
    233         synchronized (mLock) {
    234             ArraySet<ComponentName> ret = mEnabledSet.get(userId);
    235             if (ret == null) {
    236                 return new ArraySet<ComponentName>();
    237             }
    238             return ret;
    239 
    240         }
    241     }
    242 
    243     private int[] getCurrentProfileIds() {
    244         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    245         if (userManager == null) {
    246             return null;
    247         }
    248         return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser());
    249     }
    250 
    251     public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId,
    252             String serviceName, String permissionName) {
    253 
    254         ArraySet<ComponentName> installed = new ArraySet<>();
    255         Intent queryIntent = new Intent(serviceName);
    256         List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
    257                 queryIntent,
    258                 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA |
    259                                     PackageManager.MATCH_DIRECT_BOOT_AWARE |
    260                                     PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
    261                 userId);
    262         if (installedServices != null) {
    263             for (int i = 0, count = installedServices.size(); i < count; i++) {
    264                 ResolveInfo resolveInfo = installedServices.get(i);
    265                 ServiceInfo info = resolveInfo.serviceInfo;
    266 
    267                 ComponentName component = new ComponentName(info.packageName, info.name);
    268                 if (!permissionName.equals(info.permission)) {
    269                     Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name
    270                             + ": it does not require the permission "
    271                             + permissionName);
    272                     continue;
    273                 }
    274                 installed.add(component);
    275             }
    276         }
    277         return installed;
    278     }
    279 
    280     private ArraySet<ComponentName> loadComponentNamesForUser(int userId) {
    281         return loadComponentNames(mContext.getPackageManager(), userId, mServiceName,
    282                 mServicePermission);
    283     }
    284 
    285     private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
    286             int userId) {
    287         final ContentResolver cr = mContext.getContentResolver();
    288         String settingValue = Settings.Secure.getStringForUser(
    289                 cr,
    290                 settingName,
    291                 userId);
    292         if (TextUtils.isEmpty(settingValue))
    293             return new ArraySet<>();
    294         String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
    295         ArraySet<ComponentName> result = new ArraySet<>(restored.length);
    296         for (int i = 0; i < restored.length; i++) {
    297             ComponentName value = ComponentName.unflattenFromString(restored[i]);
    298             if (null != value) {
    299                 result.add(value);
    300             }
    301         }
    302         return result;
    303     }
    304 
    305     private void sendSettingChanged() {
    306         for (EnabledComponentChangeListener l : mEnabledComponentListeners) {
    307             l.onEnabledComponentChanged();
    308         }
    309     }
    310 
    311 }
    312