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 */ onEnabledComponentChanged()76 void onEnabledComponentChanged(); 77 } 78 EnabledComponentsObserver(@onNull Context context, @NonNull String settingName, @NonNull String servicePermission, @NonNull String serviceName, @NonNull Object lock, @NonNull Collection<EnabledComponentChangeListener> listeners)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 */ build(@onNull Context context, @NonNull Handler handler, @NonNull String settingName, @NonNull Looper looper, @NonNull String servicePermission, @NonNull String serviceName, @NonNull final Object lock, @NonNull Collection<EnabledComponentChangeListener> listeners)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 onPackagesChanged()149 public void onPackagesChanged() { 150 rebuildAll(); 151 } 152 153 @Override onSettingChanged()154 public void onSettingChanged() { 155 rebuildAll(); 156 } 157 158 @Override onSettingRestored(String prevValue, String newValue, int userId)159 public void onSettingRestored(String prevValue, String newValue, int userId) { 160 rebuildAll(); 161 } 162 onUsersChanged()163 public void onUsersChanged() { 164 rebuildAll(); 165 } 166 167 /** 168 * Rebuild the sets of allowed components for each current user profile. 169 */ rebuildAll()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 */ isValid(ComponentName component, int userId)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 */ getInstalled(int userId)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 */ getEnabled(int userId)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 getCurrentProfileIds()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 loadComponentNames(PackageManager pm, int userId, String serviceName, String permissionName)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 loadComponentNamesForUser(int userId)280 private ArraySet<ComponentName> loadComponentNamesForUser(int userId) { 281 return loadComponentNames(mContext.getPackageManager(), userId, mServiceName, 282 mServicePermission); 283 } 284 loadComponentNamesFromSetting(String settingName, int userId)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 sendSettingChanged()305 private void sendSettingChanged() { 306 for (EnabledComponentChangeListener l : mEnabledComponentListeners) { 307 l.onEnabledComponentChanged(); 308 } 309 } 310 311 } 312