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 return mInstalledSet.get(userId); 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 return mEnabledSet.get(userId); 231 } 232 } 233 getCurrentProfileIds()234 private int[] getCurrentProfileIds() { 235 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 236 if (userManager == null) { 237 return null; 238 } 239 return userManager.getEnabledProfileIds(ActivityManager.getCurrentUser()); 240 } 241 loadComponentNames(PackageManager pm, int userId, String serviceName, String permissionName)242 public static ArraySet<ComponentName> loadComponentNames(PackageManager pm, int userId, 243 String serviceName, String permissionName) { 244 245 ArraySet<ComponentName> installed = new ArraySet<>(); 246 Intent queryIntent = new Intent(serviceName); 247 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser( 248 queryIntent, 249 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA, 250 userId); 251 if (installedServices != null) { 252 for (int i = 0, count = installedServices.size(); i < count; i++) { 253 ResolveInfo resolveInfo = installedServices.get(i); 254 ServiceInfo info = resolveInfo.serviceInfo; 255 256 ComponentName component = new ComponentName(info.packageName, info.name); 257 if (!permissionName.equals(info.permission)) { 258 Slog.w(TAG, "Skipping service " + info.packageName + "/" + info.name 259 + ": it does not require the permission " 260 + permissionName); 261 continue; 262 } 263 installed.add(component); 264 } 265 } 266 return installed; 267 } 268 loadComponentNamesForUser(int userId)269 private ArraySet<ComponentName> loadComponentNamesForUser(int userId) { 270 return loadComponentNames(mContext.getPackageManager(), userId, mServiceName, 271 mServicePermission); 272 } 273 loadComponentNamesFromSetting(String settingName, int userId)274 private ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName, 275 int userId) { 276 final ContentResolver cr = mContext.getContentResolver(); 277 String settingValue = Settings.Secure.getStringForUser( 278 cr, 279 settingName, 280 userId); 281 if (TextUtils.isEmpty(settingValue)) 282 return new ArraySet<>(); 283 String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR); 284 ArraySet<ComponentName> result = new ArraySet<>(restored.length); 285 for (int i = 0; i < restored.length; i++) { 286 ComponentName value = ComponentName.unflattenFromString(restored[i]); 287 if (null != value) { 288 result.add(value); 289 } 290 } 291 return result; 292 } 293 sendSettingChanged()294 private void sendSettingChanged() { 295 for (EnabledComponentChangeListener l : mEnabledComponentListeners) { 296 l.onEnabledComponentChanged(); 297 } 298 } 299 300 } 301