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