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