blob: b7662daffec4e5b09ca45df1c217acd33947d142 [file] [log] [blame]
John Spurlock7340fc82014-04-24 18:50:12 -04001/**
2 * Copyright (c) 2014, 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
17package com.android.server.notification;
18
19import android.app.ActivityManager;
20import android.app.PendingIntent;
Christopher Tate6597e342015-02-17 12:15:25 -080021import android.content.BroadcastReceiver;
John Spurlock7340fc82014-04-24 18:50:12 -040022import android.content.ComponentName;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
Christopher Tate6597e342015-02-17 12:15:25 -080026import android.content.IntentFilter;
John Spurlock7340fc82014-04-24 18:50:12 -040027import android.content.ServiceConnection;
28import android.content.pm.ApplicationInfo;
29import android.content.pm.PackageManager;
30import android.content.pm.PackageManager.NameNotFoundException;
31import android.content.pm.ResolveInfo;
32import android.content.pm.ServiceInfo;
33import android.content.pm.UserInfo;
34import android.database.ContentObserver;
35import android.net.Uri;
36import android.os.Build;
37import android.os.Handler;
38import android.os.IBinder;
39import android.os.IInterface;
40import android.os.RemoteException;
41import android.os.UserHandle;
42import android.os.UserManager;
43import android.provider.Settings;
44import android.text.TextUtils;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080045import android.util.ArrayMap;
John Spurlock7340fc82014-04-24 18:50:12 -040046import android.util.ArraySet;
John Spurlock4db0d982014-08-13 09:19:03 -040047import android.util.Log;
John Spurlock7340fc82014-04-24 18:50:12 -040048import android.util.Slog;
49import android.util.SparseArray;
50
John Spurlock25e2d242014-06-27 13:58:23 -040051import com.android.server.notification.NotificationManagerService.DumpFilter;
52
John Spurlock7340fc82014-04-24 18:50:12 -040053import java.io.PrintWriter;
54import java.util.ArrayList;
John Spurlocke77bb362014-04-26 10:24:59 -040055import java.util.Arrays;
John Spurlock7340fc82014-04-24 18:50:12 -040056import java.util.List;
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080057import java.util.Map.Entry;
Christopher Tate6597e342015-02-17 12:15:25 -080058import java.util.Objects;
John Spurlock7340fc82014-04-24 18:50:12 -040059import java.util.Set;
60
61/**
62 * Manages the lifecycle of application-provided services bound by system server.
63 *
64 * Services managed by this helper must have:
65 * - An associated system settings value with a list of enabled component names.
66 * - A well-known action for services to use in their intent-filter.
67 * - A system permission for services to require in order to ensure system has exclusive binding.
68 * - A settings page for user configuration of enabled services, and associated intent action.
69 * - A remote interface definition (aidl) provided by the service used for communication.
70 */
71abstract public class ManagedServices {
72 protected final String TAG = getClass().getSimpleName();
John Spurlock4db0d982014-08-13 09:19:03 -040073 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
John Spurlock7340fc82014-04-24 18:50:12 -040074
Julia Reynoldsc279b992015-10-30 08:23:51 -040075 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
John Spurlock7340fc82014-04-24 18:50:12 -040076
John Spurlockaf8d6c42014-05-07 17:49:08 -040077 protected final Context mContext;
John Spurlocke77bb362014-04-26 10:24:59 -040078 protected final Object mMutex;
John Spurlock7340fc82014-04-24 18:50:12 -040079 private final UserProfiles mUserProfiles;
80 private final SettingsObserver mSettingsObserver;
81 private final Config mConfig;
Christopher Tate6597e342015-02-17 12:15:25 -080082 private ArraySet<String> mRestored;
John Spurlock7340fc82014-04-24 18:50:12 -040083
84 // contains connections to all connected services, including app services
85 // and system services
86 protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
87 // things that will be put into mServices as soon as they're ready
88 private final ArrayList<String> mServicesBinding = new ArrayList<String>();
89 // lists the component names of all enabled (and therefore connected)
90 // app services for current profiles.
91 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
92 = new ArraySet<ComponentName>();
93 // Just the packages from mEnabledServicesForCurrentProfiles
94 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +020095 // List of packages in restored setting across all mUserProfiles, for quick
96 // filtering upon package updates.
97 private ArraySet<String> mRestoredPackages = new ArraySet<>();
Ruben Brunkdd18a0b2015-12-04 16:16:31 -080098 // State of current service categories
99 private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200100
John Spurlock7340fc82014-04-24 18:50:12 -0400101
Christoph Studerb53dfd42014-09-12 14:45:59 +0200102 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
103 // user change).
104 private int[] mLastSeenProfileIds;
105
Christopher Tate6597e342015-02-17 12:15:25 -0800106 private final BroadcastReceiver mRestoreReceiver;
107
John Spurlock7340fc82014-04-24 18:50:12 -0400108 public ManagedServices(Context context, Handler handler, Object mutex,
109 UserProfiles userProfiles) {
110 mContext = context;
111 mMutex = mutex;
112 mUserProfiles = userProfiles;
113 mConfig = getConfig();
114 mSettingsObserver = new SettingsObserver(handler);
Christopher Tate6597e342015-02-17 12:15:25 -0800115
116 mRestoreReceiver = new SettingRestoredReceiver();
117 IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
118 context.registerReceiver(mRestoreReceiver, filter);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200119 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800120 }
121
122 class SettingRestoredReceiver extends BroadcastReceiver {
123 @Override
124 public void onReceive(Context context, Intent intent) {
125 if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
126 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
127 if (Objects.equals(element, mConfig.secureSettingName)) {
128 String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
129 String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
130 settingRestored(element, prevValue, newValue, getSendingUserId());
131 }
132 }
133 }
John Spurlock7340fc82014-04-24 18:50:12 -0400134 }
135
136 abstract protected Config getConfig();
137
138 private String getCaption() {
139 return mConfig.caption;
140 }
141
142 abstract protected IInterface asInterface(IBinder binder);
143
John Spurlock3b98b3f2014-05-01 09:08:48 -0400144 abstract protected void onServiceAdded(ManagedServiceInfo info);
John Spurlock7340fc82014-04-24 18:50:12 -0400145
John Spurlocke77bb362014-04-26 10:24:59 -0400146 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
147
John Spurlock7340fc82014-04-24 18:50:12 -0400148 private ManagedServiceInfo newServiceInfo(IInterface service,
149 ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
150 int targetSdkVersion) {
151 return new ManagedServiceInfo(service, component, userid, isSystem, connection,
152 targetSdkVersion);
153 }
154
155 public void onBootPhaseAppsCanStart() {
156 mSettingsObserver.observe();
157 }
158
John Spurlock25e2d242014-06-27 13:58:23 -0400159 public void dump(PrintWriter pw, DumpFilter filter) {
John Spurlocke77bb362014-04-26 10:24:59 -0400160 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
John Spurlock7340fc82014-04-24 18:50:12 -0400161 + ") enabled for current profiles:");
162 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
John Spurlock25e2d242014-06-27 13:58:23 -0400163 if (filter != null && !filter.matches(cmpt)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400164 pw.println(" " + cmpt);
John Spurlock7340fc82014-04-24 18:50:12 -0400165 }
166
John Spurlocke77bb362014-04-26 10:24:59 -0400167 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
John Spurlock7340fc82014-04-24 18:50:12 -0400168 for (ManagedServiceInfo info : mServices) {
John Spurlock25e2d242014-06-27 13:58:23 -0400169 if (filter != null && !filter.matches(info.component)) continue;
John Spurlocke77bb362014-04-26 10:24:59 -0400170 pw.println(" " + info.component
John Spurlock7340fc82014-04-24 18:50:12 -0400171 + " (user " + info.userid + "): " + info.service
172 + (info.isSystem?" SYSTEM":""));
173 }
174 }
175
Christopher Tate6597e342015-02-17 12:15:25 -0800176 // By convention, restored settings are replicated to another settings
177 // entry, named similarly but with a disambiguation suffix.
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200178 public static String restoredSettingName(Config config) {
Christopher Tate6597e342015-02-17 12:15:25 -0800179 return config.secureSettingName + ":restored";
180 }
181
182 // The OS has done a restore of this service's saved state. We clone it to the
183 // 'restored' reserve, and then once we return and the actual write to settings is
184 // performed, our observer will do the work of maintaining the restored vs live
185 // settings data.
186 public void settingRestored(String element, String oldValue, String newValue, int userid) {
187 if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
188 + " ovalue=" + oldValue + " nvalue=" + newValue);
189 if (mConfig.secureSettingName.equals(element)) {
190 if (element != null) {
191 mRestored = null;
192 Settings.Secure.putStringForUser(mContext.getContentResolver(),
193 restoredSettingName(mConfig),
194 newValue,
195 userid);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200196 updateSettingsAccordingToInstalledServices(userid);
197 rebuildRestoredPackages();
Christopher Tate6597e342015-02-17 12:15:25 -0800198 }
199 }
200 }
201
John Spurlock80774932015-05-07 17:38:50 -0400202 public boolean isComponentEnabledForPackage(String pkg) {
203 return mEnabledServicesPackageNames.contains(pkg);
204 }
205
John Spurlock7340fc82014-04-24 18:50:12 -0400206 public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
John Spurlocke77bb362014-04-26 10:24:59 -0400207 if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
208 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
209 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
John Spurlock7340fc82014-04-24 18:50:12 -0400210 boolean anyServicesInvolved = false;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200211
John Spurlock7340fc82014-04-24 18:50:12 -0400212 if (pkgList != null && (pkgList.length > 0)) {
213 for (String pkgName : pkgList) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200214 if (mEnabledServicesPackageNames.contains(pkgName) ||
215 mRestoredPackages.contains(pkgName)) {
John Spurlock7340fc82014-04-24 18:50:12 -0400216 anyServicesInvolved = true;
217 }
218 }
219 }
220
221 if (anyServicesInvolved) {
222 // if we're not replacing a package, clean up orphaned bits
223 if (!queryReplace) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200224 updateSettingsAccordingToInstalledServices();
225 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400226 }
227 // make sure we're still bound to any of our services who may have just upgraded
228 rebindServices();
229 }
230 }
231
John Spurlock1b8b22b2015-05-20 09:47:13 -0400232 public void onUserSwitched(int user) {
233 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200234 rebuildRestoredPackages();
Christoph Studerb53dfd42014-09-12 14:45:59 +0200235 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
236 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
237 return;
238 }
239 rebindServices();
240 }
241
John Spurlock7340fc82014-04-24 18:50:12 -0400242 public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
243 checkNotNull(service);
244 final IBinder token = service.asBinder();
245 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200246 for (int i = 0; i < N; i++) {
John Spurlock7340fc82014-04-24 18:50:12 -0400247 final ManagedServiceInfo info = mServices.get(i);
248 if (info.service.asBinder() == token) return info;
249 }
250 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
251 + service);
252 }
253
254 public void unregisterService(IInterface service, int userid) {
255 checkNotNull(service);
256 // no need to check permissions; if your service binder is in the list,
257 // that's proof that you had permission to add it in the first place
258 unregisterServiceImpl(service, userid);
259 }
260
261 public void registerService(IInterface service, ComponentName component, int userid) {
262 checkNotNull(service);
Christoph Studer3e144d32014-05-22 16:48:40 +0200263 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
264 if (info != null) {
265 onServiceAdded(info);
266 }
John Spurlock7340fc82014-04-24 18:50:12 -0400267 }
268
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800269 public void setCategoryState(String category, boolean enabled) {
270 synchronized (mMutex) {
271 final Boolean previous = mCategoryEnabled.put(category, enabled);
272 if (!(previous == null || previous != enabled)) {
273 return;
274 }
275
276 // State changed
277 if (DEBUG) {
278 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "category " + category);
279 }
280
281 final int[] userIds = mUserProfiles.getCurrentProfileIds();
282 for (int userId : userIds) {
283 final Set<ComponentName> componentNames = queryPackageForServices(null,
284 userId, category);
285
286 // Disallow services not enabled in Settings
287 final ArraySet<ComponentName> userComponents =
288 loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
289 if (userComponents == null) {
290 componentNames.clear();
291 } else {
292 componentNames.retainAll(userComponents);
293 }
294
295 if (DEBUG) {
296 Slog.d(TAG, "Components for category " + category + ": " + componentNames);
297 }
298 for (ComponentName c : componentNames) {
299 if (enabled) {
300 registerServiceLocked(c, userId);
301 } else {
302 unregisterServiceLocked(c, userId);
303 }
304 }
305 }
306
307 }
308 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200309
310 private void rebuildRestoredPackages() {
311 mRestoredPackages.clear();
312 String settingName = restoredSettingName(mConfig);
John Spurlock7340fc82014-04-24 18:50:12 -0400313 int[] userIds = mUserProfiles.getCurrentProfileIds();
314 final int N = userIds.length;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200315 for (int i = 0; i < N; ++i) {
316 ArraySet<ComponentName> names = loadComponentNamesFromSetting(settingName, userIds[i]);
317 if (names == null)
318 continue;
319 for (ComponentName name: names) {
320 mRestoredPackages.add(name.getPackageName());
321 }
John Spurlock7340fc82014-04-24 18:50:12 -0400322 }
323 }
324
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200325
Julia Reynoldsc279b992015-10-30 08:23:51 -0400326 protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
327 int userId) {
Christopher Tate6597e342015-02-17 12:15:25 -0800328 final ContentResolver cr = mContext.getContentResolver();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200329 String settingValue = Settings.Secure.getStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800330 cr,
331 settingName,
332 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200333 if (TextUtils.isEmpty(settingValue))
334 return null;
335 String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
336 ArraySet<ComponentName> result = new ArraySet<>(restored.length);
337 for (int i = 0; i < restored.length; i++) {
338 ComponentName value = ComponentName.unflattenFromString(restored[i]);
339 if (null != value) {
340 result.add(value);
Christopher Tate6597e342015-02-17 12:15:25 -0800341 }
342 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200343 return result;
344 }
John Spurlock7340fc82014-04-24 18:50:12 -0400345
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200346 private void storeComponentsToSetting(Set<ComponentName> components,
347 String settingName,
348 int userId) {
349 String[] componentNames = null;
350 if (null != components) {
351 componentNames = new String[components.size()];
352 int index = 0;
353 for (ComponentName c: components) {
354 componentNames[index++] = c.flattenToString();
355 }
356 }
357 final String value = (componentNames == null) ? "" :
358 TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
359 final ContentResolver cr = mContext.getContentResolver();
360 Settings.Secure.putStringForUser(
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800361 cr,
362 settingName,
363 value,
364 userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200365 }
366
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200367 /**
368 * Remove access for any services that no longer exist.
369 */
370 private void updateSettingsAccordingToInstalledServices() {
371 int[] userIds = mUserProfiles.getCurrentProfileIds();
372 final int N = userIds.length;
373 for (int i = 0; i < N; ++i) {
374 updateSettingsAccordingToInstalledServices(userIds[i]);
375 }
376 rebuildRestoredPackages();
377 }
378
Julia Reynoldsc279b992015-10-30 08:23:51 -0400379 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800380 return queryPackageForServices(packageName, userId, null);
381 }
382
383 protected Set<ComponentName> queryPackageForServices(String packageName, int userId,
384 String category) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200385 Set<ComponentName> installed = new ArraySet<>();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200386 final PackageManager pm = mContext.getPackageManager();
Julia Reynoldsc279b992015-10-30 08:23:51 -0400387 Intent queryIntent = new Intent(mConfig.serviceInterface);
388 if (!TextUtils.isEmpty(packageName)) {
389 queryIntent.setPackage(packageName);
390 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800391 if (category != null) {
392 queryIntent.addCategory(category);
393 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200394 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
Julia Reynoldsc279b992015-10-30 08:23:51 -0400395 queryIntent,
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200396 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
397 userId);
398 if (DEBUG)
399 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
Julia Reynolds50f05142015-10-30 17:03:59 -0400400 if (installedServices != null) {
401 for (int i = 0, count = installedServices.size(); i < count; i++) {
402 ResolveInfo resolveInfo = installedServices.get(i);
403 ServiceInfo info = resolveInfo.serviceInfo;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200404
Julia Reynolds50f05142015-10-30 17:03:59 -0400405 ComponentName component = new ComponentName(info.packageName, info.name);
406 if (!mConfig.bindPermission.equals(info.permission)) {
407 Slog.w(TAG, "Skipping " + getCaption() + " service "
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800408 + info.packageName + "/" + info.name
409 + ": it does not require the permission "
410 + mConfig.bindPermission);
Julia Reynolds50f05142015-10-30 17:03:59 -0400411 continue;
412 }
413 installed.add(component);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200414 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200415 }
Julia Reynoldsc279b992015-10-30 08:23:51 -0400416 return installed;
417 }
418
419 private void updateSettingsAccordingToInstalledServices(int userId) {
420 boolean restoredChanged = false;
421 boolean currentChanged = false;
422 Set<ComponentName> restored =
423 loadComponentNamesFromSetting(restoredSettingName(mConfig), userId);
424 Set<ComponentName> current =
425 loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
426 // Load all services for all packages.
427 Set<ComponentName> installed = queryPackageForServices(null, userId);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200428
429 ArraySet<ComponentName> retained = new ArraySet<>();
430
431 for (ComponentName component : installed) {
432 if (null != restored) {
433 boolean wasRestored = restored.remove(component);
434 if (wasRestored) {
435 // Freshly installed package has service that was mentioned in restored setting.
436 if (DEBUG)
437 Slog.v(TAG, "Restoring " + component + " for user " + userId);
438 restoredChanged = true;
439 currentChanged = true;
440 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400441 continue;
442 }
John Spurlock7340fc82014-04-24 18:50:12 -0400443 }
444
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200445 if (null != current) {
446 if (current.contains(component))
447 retained.add(component);
John Spurlock7340fc82014-04-24 18:50:12 -0400448 }
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200449 }
450
451 currentChanged |= ((current == null ? 0 : current.size()) != retained.size());
452
453 if (currentChanged) {
454 if (DEBUG) Slog.v(TAG, "List of " + getCaption() + " services was updated " + current);
455 storeComponentsToSetting(retained, mConfig.secureSettingName, userId);
456 }
457
458 if (restoredChanged) {
459 if (DEBUG) Slog.v(TAG,
460 "List of " + getCaption() + " restored services was updated " + restored);
461 storeComponentsToSetting(restored, restoredSettingName(mConfig), userId);
John Spurlock7340fc82014-04-24 18:50:12 -0400462 }
463 }
464
465 /**
466 * Called whenever packages change, the user switches, or the secure setting
467 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
468 */
469 private void rebindServices() {
470 if (DEBUG) Slog.d(TAG, "rebindServices");
471 final int[] userIds = mUserProfiles.getCurrentProfileIds();
472 final int nUserIds = userIds.length;
473
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200474 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400475
476 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200477 componentsByUser.put(userIds[i],
478 loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
John Spurlock7340fc82014-04-24 18:50:12 -0400479 }
480
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200481 final ArrayList<ManagedServiceInfo> toRemove = new ArrayList<>();
482 final SparseArray<ArrayList<ComponentName>> toAdd = new SparseArray<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400483
484 synchronized (mMutex) {
Christoph Studer5d423842014-05-23 13:15:54 +0200485 // Unbind automatically bound services, retain system services.
486 for (ManagedServiceInfo service : mServices) {
487 if (!service.isSystem) {
488 toRemove.add(service);
489 }
490 }
John Spurlock7340fc82014-04-24 18:50:12 -0400491
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200492 final ArraySet<ComponentName> newEnabled = new ArraySet<>();
493 final ArraySet<String> newPackages = new ArraySet<>();
John Spurlock7340fc82014-04-24 18:50:12 -0400494
495 for (int i = 0; i < nUserIds; ++i) {
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200496 // decode the list of components
497 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
498 if (null == userComponents) {
499 toAdd.put(userIds[i], new ArrayList<ComponentName>());
500 continue;
501 }
502
503 final ArrayList<ComponentName> add = new ArrayList<>(userComponents);
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800504
505 // Remove components from disabled categories so that those services aren't run.
506 for (Entry<String, Boolean> e : mCategoryEnabled.entrySet()) {
507 if (!e.getValue()) {
508 Set<ComponentName> c = queryPackageForServices(null, userIds[i],
509 e.getKey());
510 add.removeAll(c);
511 }
512 }
513
John Spurlock7340fc82014-04-24 18:50:12 -0400514 toAdd.put(userIds[i], add);
515
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200516 newEnabled.addAll(userComponents);
John Spurlock7340fc82014-04-24 18:50:12 -0400517
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200518 for (int j = 0; j < userComponents.size(); j++) {
Chris Wren083094c2015-12-15 16:25:07 -0500519 final ComponentName component = userComponents.valueAt(j);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200520 newPackages.add(component.getPackageName());
John Spurlock7340fc82014-04-24 18:50:12 -0400521 }
522 }
523 mEnabledServicesForCurrentProfiles = newEnabled;
524 mEnabledServicesPackageNames = newPackages;
525 }
526
527 for (ManagedServiceInfo info : toRemove) {
528 final ComponentName component = info.component;
529 final int oldUser = info.userid;
530 Slog.v(TAG, "disabling " + getCaption() + " for user "
531 + oldUser + ": " + component);
532 unregisterService(component, info.userid);
533 }
534
535 for (int i = 0; i < nUserIds; ++i) {
536 final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
537 final int N = add.size();
538 for (int j = 0; j < N; j++) {
539 final ComponentName component = add.get(j);
540 Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
541 + component);
542 registerService(component, userIds[i]);
543 }
544 }
Christoph Studerb53dfd42014-09-12 14:45:59 +0200545
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200546 mLastSeenProfileIds = userIds;
John Spurlock7340fc82014-04-24 18:50:12 -0400547 }
548
549 /**
550 * Version of registerService that takes the name of a service component to bind to.
551 */
552 private void registerService(final ComponentName name, final int userid) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800553 synchronized (mMutex) {
554 registerServiceLocked(name, userid);
555 }
556 }
557
558 private void registerServiceLocked(final ComponentName name, final int userid) {
John Spurlock7340fc82014-04-24 18:50:12 -0400559 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
560
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800561 final String servicesBindingTag = name.toString() + "/" + userid;
562 if (mServicesBinding.contains(servicesBindingTag)) {
563 // stop registering this thing already! we're working on it
564 return;
565 }
566 mServicesBinding.add(servicesBindingTag);
John Spurlock7340fc82014-04-24 18:50:12 -0400567
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800568 final int N = mServices.size();
569 for (int i = N - 1; i >= 0; i--) {
570 final ManagedServiceInfo info = mServices.get(i);
571 if (name.equals(info.component)
572 && info.userid == userid) {
573 // cut old connections
574 if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
575 + info.service);
576 removeServiceLocked(i);
577 if (info.connection != null) {
578 mContext.unbindService(info.connection);
John Spurlock7340fc82014-04-24 18:50:12 -0400579 }
580 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800581 }
John Spurlock7340fc82014-04-24 18:50:12 -0400582
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800583 Intent intent = new Intent(mConfig.serviceInterface);
584 intent.setComponent(name);
John Spurlock7340fc82014-04-24 18:50:12 -0400585
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800586 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
John Spurlock7340fc82014-04-24 18:50:12 -0400587
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800588 final PendingIntent pendingIntent = PendingIntent.getActivity(
589 mContext, 0, new Intent(mConfig.settingsAction), 0);
590 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
John Spurlock7340fc82014-04-24 18:50:12 -0400591
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800592 ApplicationInfo appInfo = null;
593 try {
594 appInfo = mContext.getPackageManager().getApplicationInfo(
595 name.getPackageName(), 0);
596 } catch (NameNotFoundException e) {
597 // Ignore if the package doesn't exist we won't be able to bind to the service.
598 }
599 final int targetSdkVersion =
600 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
John Spurlock7340fc82014-04-24 18:50:12 -0400601
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800602 try {
603 if (DEBUG) Slog.v(TAG, "binding: " + intent);
604 ServiceConnection serviceConnection = new ServiceConnection() {
605 IInterface mService;
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200606
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800607 @Override
608 public void onServiceConnected(ComponentName name, IBinder binder) {
609 boolean added = false;
610 ManagedServiceInfo info = null;
611 synchronized (mMutex) {
612 mServicesBinding.remove(servicesBindingTag);
613 try {
614 mService = asInterface(binder);
615 info = newServiceInfo(mService, name,
616 userid, false /*isSystem*/, this, targetSdkVersion);
617 binder.linkToDeath(info, 0);
618 added = mServices.add(info);
619 } catch (RemoteException e) {
620 // already dead
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200621 }
622 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800623 if (added) {
624 onServiceAdded(info);
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200625 }
John Spurlock7340fc82014-04-24 18:50:12 -0400626 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800627
628 @Override
629 public void onServiceDisconnected(ComponentName name) {
630 Slog.v(TAG, getCaption() + " connection lost: " + name);
631 }
632 };
633 if (!mContext.bindServiceAsUser(intent,
634 serviceConnection,
635 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
636 new UserHandle(userid))) {
637 mServicesBinding.remove(servicesBindingTag);
638 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
John Spurlock7340fc82014-04-24 18:50:12 -0400639 return;
640 }
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800641 } catch (SecurityException ex) {
642 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
643 return;
John Spurlock7340fc82014-04-24 18:50:12 -0400644 }
645 }
646
647 /**
648 * Remove a service for the given user by ComponentName
649 */
650 private void unregisterService(ComponentName name, int userid) {
651 synchronized (mMutex) {
Ruben Brunkdd18a0b2015-12-04 16:16:31 -0800652 unregisterServiceLocked(name, userid);
653 }
654 }
655
656 private void unregisterServiceLocked(ComponentName name, int userid) {
657 final int N = mServices.size();
658 for (int i = N - 1; i >= 0; i--) {
659 final ManagedServiceInfo info = mServices.get(i);
660 if (name.equals(info.component)
661 && info.userid == userid) {
662 removeServiceLocked(i);
663 if (info.connection != null) {
664 try {
665 mContext.unbindService(info.connection);
666 } catch (IllegalArgumentException ex) {
667 // something happened to the service: we think we have a connection
668 // but it's bogus.
669 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
John Spurlock7340fc82014-04-24 18:50:12 -0400670 }
671 }
672 }
673 }
674 }
675
676 /**
677 * Removes a service from the list but does not unbind
678 *
679 * @return the removed service.
680 */
681 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400682 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
John Spurlock7340fc82014-04-24 18:50:12 -0400683 ManagedServiceInfo serviceInfo = null;
684 synchronized (mMutex) {
685 final int N = mServices.size();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200686 for (int i = N - 1; i >= 0; i--) {
John Spurlock7340fc82014-04-24 18:50:12 -0400687 final ManagedServiceInfo info = mServices.get(i);
688 if (info.service.asBinder() == service.asBinder()
689 && info.userid == userid) {
John Spurlocke77bb362014-04-26 10:24:59 -0400690 if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
691 serviceInfo = removeServiceLocked(i);
John Spurlock7340fc82014-04-24 18:50:12 -0400692 }
693 }
694 }
695 return serviceInfo;
696 }
697
John Spurlocke77bb362014-04-26 10:24:59 -0400698 private ManagedServiceInfo removeServiceLocked(int i) {
699 final ManagedServiceInfo info = mServices.remove(i);
700 onServiceRemovedLocked(info);
701 return info;
702 }
703
John Spurlock7340fc82014-04-24 18:50:12 -0400704 private void checkNotNull(IInterface service) {
705 if (service == null) {
706 throw new IllegalArgumentException(getCaption() + " must not be null");
707 }
708 }
709
Christoph Studer3e144d32014-05-22 16:48:40 +0200710 private ManagedServiceInfo registerServiceImpl(final IInterface service,
John Spurlock7340fc82014-04-24 18:50:12 -0400711 final ComponentName component, final int userid) {
712 synchronized (mMutex) {
713 try {
714 ManagedServiceInfo info = newServiceInfo(service, component, userid,
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700715 true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
John Spurlock7340fc82014-04-24 18:50:12 -0400716 service.asBinder().linkToDeath(info, 0);
717 mServices.add(info);
Christoph Studer3e144d32014-05-22 16:48:40 +0200718 return info;
John Spurlock7340fc82014-04-24 18:50:12 -0400719 } catch (RemoteException e) {
720 // already dead
721 }
722 }
Christoph Studer3e144d32014-05-22 16:48:40 +0200723 return null;
John Spurlock7340fc82014-04-24 18:50:12 -0400724 }
725
726 /**
727 * Removes a service from the list and unbinds.
728 */
729 private void unregisterServiceImpl(IInterface service, int userid) {
730 ManagedServiceInfo info = removeServiceImpl(service, userid);
731 if (info != null && info.connection != null) {
732 mContext.unbindService(info.connection);
733 }
734 }
735
736 private class SettingsObserver extends ContentObserver {
737 private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
738
739 private SettingsObserver(Handler handler) {
740 super(handler);
741 }
742
743 private void observe() {
744 ContentResolver resolver = mContext.getContentResolver();
745 resolver.registerContentObserver(mSecureSettingsUri,
746 false, this, UserHandle.USER_ALL);
747 update(null);
748 }
749
750 @Override
751 public void onChange(boolean selfChange, Uri uri) {
752 update(uri);
753 }
754
755 private void update(Uri uri) {
756 if (uri == null || mSecureSettingsUri.equals(uri)) {
Christoph Studerb53dfd42014-09-12 14:45:59 +0200757 if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
758 " / uri=" + uri);
John Spurlock7340fc82014-04-24 18:50:12 -0400759 rebindServices();
Denis Kuznetsov76c02682015-09-17 19:57:00 +0200760 rebuildRestoredPackages();
John Spurlock7340fc82014-04-24 18:50:12 -0400761 }
762 }
763 }
764
765 public class ManagedServiceInfo implements IBinder.DeathRecipient {
766 public IInterface service;
767 public ComponentName component;
768 public int userid;
769 public boolean isSystem;
770 public ServiceConnection connection;
771 public int targetSdkVersion;
772
773 public ManagedServiceInfo(IInterface service, ComponentName component,
774 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
775 this.service = service;
776 this.component = component;
777 this.userid = userid;
778 this.isSystem = isSystem;
779 this.connection = connection;
780 this.targetSdkVersion = targetSdkVersion;
781 }
782
John Spurlocke77bb362014-04-26 10:24:59 -0400783 @Override
784 public String toString() {
785 return new StringBuilder("ManagedServiceInfo[")
786 .append("component=").append(component)
787 .append(",userid=").append(userid)
788 .append(",isSystem=").append(isSystem)
789 .append(",targetSdkVersion=").append(targetSdkVersion)
790 .append(",connection=").append(connection == null ? null : "<connection>")
791 .append(",service=").append(service)
792 .append(']').toString();
793 }
794
John Spurlock7340fc82014-04-24 18:50:12 -0400795 public boolean enabledAndUserMatches(int nid) {
796 if (!isEnabledForCurrentProfiles()) {
797 return false;
798 }
799 if (this.userid == UserHandle.USER_ALL) return true;
800 if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
801 return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
802 }
803
804 public boolean supportsProfiles() {
Dianne Hackborn955d8d62014-10-07 20:17:19 -0700805 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
John Spurlock7340fc82014-04-24 18:50:12 -0400806 }
807
808 @Override
809 public void binderDied() {
John Spurlocke77bb362014-04-26 10:24:59 -0400810 if (DEBUG) Slog.d(TAG, "binderDied");
John Spurlock7340fc82014-04-24 18:50:12 -0400811 // Remove the service, but don't unbind from the service. The system will bring the
812 // service back up, and the onServiceConnected handler will readd the service with the
813 // new binding. If this isn't a bound service, and is just a registered
814 // service, just removing it from the list is all we need to do anyway.
815 removeServiceImpl(this.service, this.userid);
816 }
817
818 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
819 public boolean isEnabledForCurrentProfiles() {
820 if (this.isSystem) return true;
821 if (this.connection == null) return false;
822 return mEnabledServicesForCurrentProfiles.contains(this.component);
823 }
824 }
825
826 public static class UserProfiles {
827 // Profiles of the current user.
828 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
829
830 public void updateCache(Context context) {
831 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
832 if (userManager != null) {
833 int currentUserId = ActivityManager.getCurrentUser();
834 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
835 synchronized (mCurrentProfiles) {
836 mCurrentProfiles.clear();
837 for (UserInfo user : profiles) {
838 mCurrentProfiles.put(user.id, user);
839 }
840 }
841 }
842 }
843
844 public int[] getCurrentProfileIds() {
845 synchronized (mCurrentProfiles) {
846 int[] users = new int[mCurrentProfiles.size()];
847 final int N = mCurrentProfiles.size();
848 for (int i = 0; i < N; ++i) {
849 users[i] = mCurrentProfiles.keyAt(i);
850 }
851 return users;
852 }
853 }
854
855 public boolean isCurrentProfile(int userId) {
856 synchronized (mCurrentProfiles) {
857 return mCurrentProfiles.get(userId) != null;
858 }
859 }
860 }
861
862 protected static class Config {
863 String caption;
864 String serviceInterface;
865 String secureSettingName;
866 String bindPermission;
867 String settingsAction;
868 int clientLabel;
869 }
870}