2 * Copyright (c) 2014, The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.notification;
19 import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
20 import static android.content.Context.BIND_AUTO_CREATE;
21 import static android.content.Context.BIND_FOREGROUND_SERVICE;
22 import static android.content.Context.DEVICE_POLICY_SERVICE;
24 import android.annotation.NonNull;
25 import android.app.ActivityManager;
26 import android.app.PendingIntent;
27 import android.app.admin.DevicePolicyManager;
28 import android.content.ComponentName;
29 import android.content.ContentResolver;
30 import android.content.Context;
31 import android.content.Intent;
32 import android.content.ServiceConnection;
33 import android.content.pm.ApplicationInfo;
34 import android.content.pm.IPackageManager;
35 import android.content.pm.PackageManager;
36 import android.content.pm.PackageManager.NameNotFoundException;
37 import android.content.pm.ResolveInfo;
38 import android.content.pm.ServiceInfo;
39 import android.content.pm.UserInfo;
40 import android.os.Binder;
41 import android.os.Build;
42 import android.os.IBinder;
43 import android.os.IInterface;
44 import android.os.RemoteException;
45 import android.os.UserHandle;
46 import android.os.UserManager;
47 import android.provider.Settings;
48 import android.text.TextUtils;
49 import android.util.ArrayMap;
50 import android.util.ArraySet;
51 import android.util.Log;
52 import android.util.Slog;
53 import android.util.SparseArray;
55 import com.android.internal.util.XmlUtils;
56 import com.android.server.notification.NotificationManagerService.DumpFilter;
58 import org.xmlpull.v1.XmlPullParser;
59 import org.xmlpull.v1.XmlPullParserException;
60 import org.xmlpull.v1.XmlSerializer;
62 import java.io.IOException;
63 import java.io.PrintWriter;
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.HashSet;
67 import java.util.List;
69 import java.util.stream.Collectors;
72 * Manages the lifecycle of application-provided services bound by system server.
74 * Services managed by this helper must have:
75 * - An associated system settings value with a list of enabled component names.
76 * - A well-known action for services to use in their intent-filter.
77 * - A system permission for services to require in order to ensure system has exclusive binding.
78 * - A settings page for user configuration of enabled services, and associated intent action.
79 * - A remote interface definition (aidl) provided by the service used for communication.
81 abstract public class ManagedServices {
82 protected final String TAG = getClass().getSimpleName();
83 protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
85 protected static final String ENABLED_SERVICES_SEPARATOR = ":";
88 * List of components and apps that can have running {@link ManagedServices}.
90 static final String TAG_MANAGED_SERVICES = "service_listing";
91 static final String ATT_APPROVED_LIST = "approved";
92 static final String ATT_USER_ID = "user";
93 static final String ATT_IS_PRIMARY = "primary";
95 static final int APPROVAL_BY_PACKAGE = 0;
96 static final int APPROVAL_BY_COMPONENT = 1;
98 protected final Context mContext;
99 protected final Object mMutex;
100 private final UserProfiles mUserProfiles;
101 private final IPackageManager mPm;
102 private final Config mConfig;
104 // contains connections to all connected services, including app services
105 // and system services
106 private final ArrayList<ManagedServiceInfo> mServices = new ArrayList<>();
107 // things that will be put into mServices as soon as they're ready
108 private final ArrayList<String> mServicesBinding = new ArrayList<>();
109 // lists the component names of all enabled (and therefore potentially connected)
110 // app services for current profiles.
111 private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
113 // Just the packages from mEnabledServicesForCurrentProfiles
114 private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<>();
115 // List of enabled packages that have nevertheless asked not to be run
116 private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
118 // List of approved packages or components (by user, then by primary/secondary) that are
119 // allowed to be bound as managed services. A package or component appearing in this list does
120 // not mean that we are currently bound to said package/component.
121 private ArrayMap<Integer, ArrayMap<Boolean, ArraySet<String>>> mApproved = new ArrayMap<>();
123 // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
125 private int[] mLastSeenProfileIds;
127 // True if approved services are stored in xml, not settings.
128 private boolean mUseXml;
130 // Whether managed services are approved individually or package wide
131 protected int mApprovalLevel;
133 public ManagedServices(Context context, Object mutex, UserProfiles userProfiles,
134 IPackageManager pm) {
137 mUserProfiles = userProfiles;
139 mConfig = getConfig();
140 mApprovalLevel = APPROVAL_BY_COMPONENT;
143 abstract protected Config getConfig();
145 private String getCaption() {
146 return mConfig.caption;
149 abstract protected IInterface asInterface(IBinder binder);
151 abstract protected boolean checkType(IInterface service);
153 abstract protected void onServiceAdded(ManagedServiceInfo info);
155 protected List<ManagedServiceInfo> getServices() {
156 synchronized (mMutex) {
157 List<ManagedServiceInfo> services = new ArrayList<>(mServices);
162 protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
164 private ManagedServiceInfo newServiceInfo(IInterface service,
165 ComponentName component, int userId, boolean isSystem, ServiceConnection connection,
166 int targetSdkVersion) {
167 return new ManagedServiceInfo(service, component, userId, isSystem, connection,
171 public void onBootPhaseAppsCanStart() {}
173 public void dump(PrintWriter pw, DumpFilter filter) {
174 pw.println(" Allowed " + getCaption() + "s:");
175 final int N = mApproved.size();
176 for (int i = 0 ; i < N; i++) {
177 final int userId = mApproved.keyAt(i);
178 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
179 if (approvedByType != null) {
180 final int M = approvedByType.size();
181 for (int j = 0; j < M; j++) {
182 final boolean isPrimary = approvedByType.keyAt(j);
183 final ArraySet<String> approved = approvedByType.valueAt(j);
184 if (approvedByType != null && approvedByType.size() > 0) {
185 pw.println(" " + String.join(ENABLED_SERVICES_SEPARATOR, approved)
186 + " (user: " + userId + " isPrimary: " + isPrimary + ")");
192 pw.println(" All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
193 + ") enabled for current profiles:");
194 for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
195 if (filter != null && !filter.matches(cmpt)) continue;
196 pw.println(" " + cmpt);
199 pw.println(" Live " + getCaption() + "s (" + mServices.size() + "):");
200 for (ManagedServiceInfo info : mServices) {
201 if (filter != null && !filter.matches(info.component)) continue;
202 pw.println(" " + info.component
203 + " (user " + info.userid + "): " + info.service
204 + (info.isSystem?" SYSTEM":"")
205 + (info.isGuest(this)?" GUEST":""));
208 pw.println(" Snoozed " + getCaption() + "s (" +
209 mSnoozingForCurrentProfiles.size() + "):");
210 for (ComponentName name : mSnoozingForCurrentProfiles) {
211 pw.println(" " + name.flattenToShortString());
215 protected void onSettingRestored(String element, String value, int backupSdkInt, int userId) {
217 Slog.d(TAG, "Restored managed service setting: " + element);
218 if (mConfig.secureSettingName.equals(element) ||
219 (mConfig.secondarySettingName != null
220 && mConfig.secondarySettingName.equals(element))) {
221 if (backupSdkInt < Build.VERSION_CODES.O) {
222 // automatic system grants were added in O, so append the approved apps
223 // rather than wiping out the setting
224 String currentSetting =
225 getApproved(userId, mConfig.secureSettingName.equals(element));
226 if (!TextUtils.isEmpty(currentSetting)) {
227 if (!TextUtils.isEmpty(value)) {
228 value = value + ENABLED_SERVICES_SEPARATOR + currentSetting;
230 value = currentSetting;
234 Settings.Secure.putStringForUser(
235 mContext.getContentResolver(), element, value, userId);
236 loadAllowedComponentsFromSettings();
237 rebindServices(false);
242 public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
243 out.startTag(null, getConfig().xmlTag);
246 trimApprovedListsAccordingToInstalledServices();
249 final int N = mApproved.size();
250 for (int i = 0 ; i < N; i++) {
251 final int userId = mApproved.keyAt(i);
252 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
253 if (approvedByType != null) {
254 final int M = approvedByType.size();
255 for (int j = 0; j < M; j++) {
256 final boolean isPrimary = approvedByType.keyAt(j);
257 final Set<String> approved = approvedByType.valueAt(j);
258 if (approved != null) {
259 String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
260 out.startTag(null, TAG_MANAGED_SERVICES);
261 out.attribute(null, ATT_APPROVED_LIST, allowedItems);
262 out.attribute(null, ATT_USER_ID, Integer.toString(userId));
263 out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
264 out.endTag(null, TAG_MANAGED_SERVICES);
266 if (!forBackup && isPrimary) {
267 // Also write values to settings, for observers who haven't migrated yet
268 Settings.Secure.putStringForUser(mContext.getContentResolver(),
269 getConfig().secureSettingName, allowedItems, userId);
277 out.endTag(null, getConfig().xmlTag);
280 protected void migrateToXml() {
281 loadAllowedComponentsFromSettings();
284 public void readXml(XmlPullParser parser)
285 throws XmlPullParserException, IOException {
287 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
288 String tag = parser.getName();
289 if (type == XmlPullParser.END_TAG
290 && getConfig().xmlTag.equals(tag)) {
293 if (type == XmlPullParser.START_TAG) {
294 if (TAG_MANAGED_SERVICES.equals(tag)) {
295 final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
296 final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
297 final boolean isPrimary =
298 XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
299 addApprovedList(approved, userId, isPrimary);
304 rebindServices(false);
307 private void loadAllowedComponentsFromSettings() {
309 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
310 for (UserInfo user : userManager.getUsers()) {
311 final ContentResolver cr = mContext.getContentResolver();
312 addApprovedList(Settings.Secure.getStringForUser(
314 getConfig().secureSettingName,
315 user.id), user.id, true);
316 if (!TextUtils.isEmpty(getConfig().secondarySettingName)) {
317 addApprovedList(Settings.Secure.getStringForUser(
319 getConfig().secondarySettingName,
320 user.id), user.id, false);
323 Slog.d(TAG, "Done loading approved values from settings");
326 private void addApprovedList(String approved, int userId, boolean isPrimary) {
327 if (TextUtils.isEmpty(approved)) {
330 ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
331 if (approvedByType == null) {
332 approvedByType = new ArrayMap<>();
333 mApproved.put(userId, approvedByType);
335 String[] approvedArray = approved.split(ENABLED_SERVICES_SEPARATOR);
336 final ArraySet<String> approvedList = new ArraySet<>();
337 for (String pkgOrComponent : approvedArray) {
338 String approvedItem = getApprovedValue(pkgOrComponent);
339 if (approvedItem != null) {
340 approvedList.add(approvedItem);
343 approvedByType.put(isPrimary, approvedList);
346 protected boolean isComponentEnabledForPackage(String pkg) {
347 return mEnabledServicesPackageNames.contains(pkg);
350 protected void setPackageOrComponentEnabled(String pkgOrComponent, int userId,
351 boolean isPrimary, boolean enabled) {
352 ArrayMap<Boolean, ArraySet<String>> allowedByType = mApproved.get(userId);
353 if (allowedByType == null) {
354 allowedByType = new ArrayMap<>();
355 mApproved.put(userId, allowedByType);
357 ArraySet<String> approved = allowedByType.get(isPrimary);
358 if (approved == null) {
359 approved = new ArraySet<>();
360 allowedByType.put(isPrimary, approved);
362 String approvedItem = getApprovedValue(pkgOrComponent);
364 if (approvedItem != null) {
366 approved.add(approvedItem);
368 approved.remove(approvedItem);
372 rebindServices(false);
375 private String getApprovedValue(String pkgOrComponent) {
376 if (mApprovalLevel == APPROVAL_BY_COMPONENT) {
377 if(ComponentName.unflattenFromString(pkgOrComponent) != null) {
378 return pkgOrComponent;
382 return getPackageName(pkgOrComponent);
386 protected String getApproved(int userId, boolean primary) {
387 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
388 mApproved.getOrDefault(userId, new ArrayMap<>());
389 ArraySet<String> approved = allowedByType.getOrDefault(primary, new ArraySet<>());
390 return String.join(ENABLED_SERVICES_SEPARATOR, approved);
393 protected List<ComponentName> getAllowedComponents(int userId) {
394 final List<ComponentName> allowedComponents = new ArrayList<>();
395 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
396 mApproved.getOrDefault(userId, new ArrayMap<>());
397 for (int i = 0; i < allowedByType.size(); i++) {
398 final ArraySet<String> allowed = allowedByType.valueAt(i);
399 allowedComponents.addAll(allowed.stream().map(ComponentName::unflattenFromString)
400 .filter(out -> out != null).collect(Collectors.toList()));
402 return allowedComponents;
405 protected List<String> getAllowedPackages(int userId) {
406 final List<String> allowedPackages = new ArrayList<>();
407 final ArrayMap<Boolean, ArraySet<String>> allowedByType =
408 mApproved.getOrDefault(userId, new ArrayMap<>());
409 for (int i = 0; i < allowedByType.size(); i++) {
410 final ArraySet<String> allowed = allowedByType.valueAt(i);
411 allowedPackages.addAll(
412 allowed.stream().map(this::getPackageName).collect(Collectors.toList()));
414 return allowedPackages;
417 protected boolean isPackageOrComponentAllowed(String pkgOrComponent, int userId) {
418 ArrayMap<Boolean, ArraySet<String>> allowedByType =
419 mApproved.getOrDefault(userId, new ArrayMap<>());
420 for (int i = 0; i < allowedByType.size(); i++) {
421 ArraySet<String> allowed = allowedByType.valueAt(i);
422 if (allowed.contains(pkgOrComponent)) {
429 public void onPackagesChanged(boolean removingPackage, String[] pkgList, int[] uidList) {
430 if (DEBUG) Slog.d(TAG, "onPackagesChanged removingPackage=" + removingPackage
431 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
432 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
434 if (pkgList != null && (pkgList.length > 0)) {
435 boolean anyServicesInvolved = false;
436 // Remove notification settings for uninstalled package
437 if (removingPackage) {
438 int size = Math.min(pkgList.length, uidList.length);
439 for (int i = 0; i < size; i++) {
440 final String pkg = pkgList[i];
441 final int userId = UserHandle.getUserId(uidList[i]);
442 anyServicesInvolved = removeUninstalledItemsFromApprovedLists(userId, pkg);
445 for (String pkgName : pkgList) {
446 if (mEnabledServicesPackageNames.contains(pkgName)) {
447 anyServicesInvolved = true;
451 if (anyServicesInvolved) {
452 // make sure we're still bound to any of our services who may have just upgraded
453 rebindServices(false);
458 public void onUserSwitched(int user) {
459 if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
460 if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
461 if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
464 rebindServices(true);
467 public void onUserUnlocked(int user) {
468 if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
469 rebindServices(false);
472 private ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
473 if (service == null) {
476 final IBinder token = service.asBinder();
477 final int N = mServices.size();
478 for (int i = 0; i < N; i++) {
479 final ManagedServiceInfo info = mServices.get(i);
480 if (info.service.asBinder() == token) return info;
485 protected ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
486 checkNotNull(service);
487 ManagedServiceInfo info = getServiceFromTokenLocked(service);
491 throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
495 public void unregisterService(IInterface service, int userid) {
496 checkNotNull(service);
497 // no need to check permissions; if your service binder is in the list,
498 // that's proof that you had permission to add it in the first place
499 unregisterServiceImpl(service, userid);
502 public void registerService(IInterface service, ComponentName component, int userid) {
503 checkNotNull(service);
504 ManagedServiceInfo info = registerServiceImpl(service, component, userid);
506 onServiceAdded(info);
511 * Add a service to our callbacks. The lifecycle of this service is managed externally,
512 * but unlike a system service, it should not be considered privileged.
514 protected void registerGuestService(ManagedServiceInfo guest) {
515 checkNotNull(guest.service);
516 if (!checkType(guest.service)) {
517 throw new IllegalArgumentException();
519 if (registerServiceImpl(guest) != null) {
520 onServiceAdded(guest);
524 protected void setComponentState(ComponentName component, boolean enabled) {
525 boolean previous = !mSnoozingForCurrentProfiles.contains(component);
526 if (previous == enabled) {
531 mSnoozingForCurrentProfiles.remove(component);
533 mSnoozingForCurrentProfiles.add(component);
538 Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
539 component.flattenToShortString());
542 synchronized (mMutex) {
543 final int[] userIds = mUserProfiles.getCurrentProfileIds();
545 for (int userId : userIds) {
547 registerServiceLocked(component, userId);
549 unregisterServiceLocked(component, userId);
555 private @NonNull ArraySet<ComponentName> loadComponentNamesFromValues(
556 ArraySet<String> approved, int userId) {
557 if (approved == null || approved.size() == 0)
558 return new ArraySet<>();
559 ArraySet<ComponentName> result = new ArraySet<>(approved.size());
560 for (int i = 0; i < approved.size(); i++) {
561 final String packageOrComponent = approved.valueAt(i);
562 if (!TextUtils.isEmpty(packageOrComponent)) {
563 ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
564 if (component != null) {
565 result.add(component);
567 result.addAll(queryPackageForServices(packageOrComponent, userId));
574 protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
575 return queryPackageForServices(packageName, 0, userId);
578 protected Set<ComponentName> queryPackageForServices(String packageName, int extraFlags,
580 Set<ComponentName> installed = new ArraySet<>();
581 final PackageManager pm = mContext.getPackageManager();
582 Intent queryIntent = new Intent(mConfig.serviceInterface);
583 if (!TextUtils.isEmpty(packageName)) {
584 queryIntent.setPackage(packageName);
586 List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
588 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA | extraFlags,
591 Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
592 if (installedServices != null) {
593 for (int i = 0, count = installedServices.size(); i < count; i++) {
594 ResolveInfo resolveInfo = installedServices.get(i);
595 ServiceInfo info = resolveInfo.serviceInfo;
597 ComponentName component = new ComponentName(info.packageName, info.name);
598 if (!mConfig.bindPermission.equals(info.permission)) {
599 Slog.w(TAG, "Skipping " + getCaption() + " service "
600 + info.packageName + "/" + info.name
601 + ": it does not require the permission "
602 + mConfig.bindPermission);
605 installed.add(component);
611 private void trimApprovedListsAccordingToInstalledServices() {
612 int N = mApproved.size();
613 for (int i = 0 ; i < N; i++) {
614 final int userId = mApproved.keyAt(i);
615 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
616 int M = approvedByType.size();
617 for (int j = 0; j < M; j++) {
618 final ArraySet<String> approved = approvedByType.valueAt(j);
619 int P = approved.size();
620 for (int k = P - 1; k >= 0; k--) {
621 final String approvedPackageOrComponent = approved.valueAt(k);
622 if (!hasMatchingServices(approvedPackageOrComponent, userId)){
623 approved.removeAt(k);
625 Slog.v(TAG, "Removing " + approvedPackageOrComponent
626 + " from approved list; no matching services found");
630 Slog.v(TAG, "Keeping " + approvedPackageOrComponent
631 + " on approved list; matching services found");
639 private boolean removeUninstalledItemsFromApprovedLists(int uninstalledUserId, String pkg) {
640 boolean removed = false;
641 final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(uninstalledUserId);
642 if (approvedByType != null) {
643 int M = approvedByType.size();
644 for (int j = 0; j < M; j++) {
645 final ArraySet<String> approved = approvedByType.valueAt(j);
646 int O = approved.size();
647 for (int k = O - 1; k >= 0; k--) {
648 final String packageOrComponent = approved.valueAt(k);
649 final String packageName = getPackageName(packageOrComponent);
650 if (TextUtils.equals(pkg, packageName)) {
651 approved.removeAt(k);
653 Slog.v(TAG, "Removing " + packageOrComponent
654 + " from approved list; uninstalled");
663 protected String getPackageName(String packageOrComponent) {
664 final ComponentName component = ComponentName.unflattenFromString(packageOrComponent);
665 if (component != null) {
666 return component.getPackageName();
668 return packageOrComponent;
672 private boolean hasMatchingServices(String packageOrComponent, int userId) {
673 if (!TextUtils.isEmpty(packageOrComponent)) {
674 final String packageName = getPackageName(packageOrComponent);
675 return queryPackageForServices(packageName, userId).size() > 0;
681 * Called whenever packages change, the user switches, or the secure setting
682 * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
684 private void rebindServices(boolean forceRebind) {
685 if (DEBUG) Slog.d(TAG, "rebindServices");
686 final int[] userIds = mUserProfiles.getCurrentProfileIds();
687 final int nUserIds = userIds.length;
689 final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
691 for (int i = 0; i < nUserIds; ++i) {
692 final int userId = userIds[i];
693 final ArrayMap<Boolean, ArraySet<String>> approvedLists = mApproved.get(userIds[i]);
694 if (approvedLists != null) {
695 final int N = approvedLists.size();
696 for (int j = 0; j < N; j++) {
697 ArraySet<ComponentName> approvedByUser = componentsByUser.get(userId);
698 if (approvedByUser == null) {
699 approvedByUser = new ArraySet<>();
700 componentsByUser.put(userId, approvedByUser);
702 approvedByUser.addAll(
703 loadComponentNamesFromValues(approvedLists.valueAt(j), userId));
708 final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
709 final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
711 synchronized (mMutex) {
712 // Rebind to non-system services if user switched
713 for (ManagedServiceInfo service : mServices) {
714 if (!service.isSystem && !service.isGuest(this)) {
715 removableBoundServices.add(service);
719 mEnabledServicesForCurrentProfiles.clear();
720 mEnabledServicesPackageNames.clear();
722 for (int i = 0; i < nUserIds; ++i) {
723 // decode the list of components
724 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
725 if (null == userComponents) {
726 toAdd.put(userIds[i], new ArraySet<>());
730 final Set<ComponentName> add = new HashSet<>(userComponents);
731 add.removeAll(mSnoozingForCurrentProfiles);
733 toAdd.put(userIds[i], add);
735 mEnabledServicesForCurrentProfiles.addAll(userComponents);
737 for (int j = 0; j < userComponents.size(); j++) {
738 final ComponentName component = userComponents.valueAt(j);
739 mEnabledServicesPackageNames.add(component.getPackageName());
744 for (ManagedServiceInfo info : removableBoundServices) {
745 final ComponentName component = info.component;
746 final int oldUser = info.userid;
747 final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
748 if (allowedComponents != null) {
749 if (allowedComponents.contains(component) && !forceRebind) {
750 // Already bound, don't need to bind again.
751 allowedComponents.remove(component);
753 // No longer allowed to be bound, or must rebind.
754 Slog.v(TAG, "disabling " + getCaption() + " for user "
755 + oldUser + ": " + component);
756 unregisterService(component, oldUser);
761 for (int i = 0; i < nUserIds; ++i) {
762 final Set<ComponentName> add = toAdd.get(userIds[i]);
763 for (ComponentName component : add) {
765 ServiceInfo info = mPm.getServiceInfo(component,
766 PackageManager.MATCH_DIRECT_BOOT_AWARE
767 | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userIds[i]);
768 if (info == null || !mConfig.bindPermission.equals(info.permission)) {
769 Slog.w(TAG, "Not binding " + getCaption() + " service " + component
770 + ": it does not require the permission " + mConfig.bindPermission);
774 "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
775 registerService(component, userIds[i]);
776 } catch (RemoteException e) {
777 e.rethrowFromSystemServer();
782 mLastSeenProfileIds = userIds;
786 * Version of registerService that takes the name of a service component to bind to.
788 private void registerService(final ComponentName name, final int userid) {
789 synchronized (mMutex) {
790 registerServiceLocked(name, userid);
795 * Inject a system service into the management list.
797 public void registerSystemService(final ComponentName name, final int userid) {
798 synchronized (mMutex) {
799 registerServiceLocked(name, userid, true /* isSystem */);
803 private void registerServiceLocked(final ComponentName name, final int userid) {
804 registerServiceLocked(name, userid, false /* isSystem */);
807 private void registerServiceLocked(final ComponentName name, final int userid,
808 final boolean isSystem) {
809 if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
811 final String servicesBindingTag = name.toString() + "/" + userid;
812 if (mServicesBinding.contains(servicesBindingTag)) {
813 // stop registering this thing already! we're working on it
816 mServicesBinding.add(servicesBindingTag);
818 final int N = mServices.size();
819 for (int i = N - 1; i >= 0; i--) {
820 final ManagedServiceInfo info = mServices.get(i);
821 if (name.equals(info.component)
822 && info.userid == userid) {
823 // cut old connections
824 if (DEBUG) Slog.v(TAG, " disconnecting old " + getCaption() + ": "
826 removeServiceLocked(i);
827 if (info.connection != null) {
828 mContext.unbindService(info.connection);
833 Intent intent = new Intent(mConfig.serviceInterface);
834 intent.setComponent(name);
836 intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
838 final PendingIntent pendingIntent = PendingIntent.getActivity(
839 mContext, 0, new Intent(mConfig.settingsAction), 0);
840 intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
842 ApplicationInfo appInfo = null;
844 appInfo = mContext.getPackageManager().getApplicationInfo(
845 name.getPackageName(), 0);
846 } catch (NameNotFoundException e) {
847 // Ignore if the package doesn't exist we won't be able to bind to the service.
849 final int targetSdkVersion =
850 appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
853 if (DEBUG) Slog.v(TAG, "binding: " + intent);
854 ServiceConnection serviceConnection = new ServiceConnection() {
858 public void onServiceConnected(ComponentName name, IBinder binder) {
859 boolean added = false;
860 ManagedServiceInfo info = null;
861 synchronized (mMutex) {
862 mServicesBinding.remove(servicesBindingTag);
864 mService = asInterface(binder);
865 info = newServiceInfo(mService, name,
866 userid, isSystem, this, targetSdkVersion);
867 binder.linkToDeath(info, 0);
868 added = mServices.add(info);
869 } catch (RemoteException e) {
874 onServiceAdded(info);
879 public void onServiceDisconnected(ComponentName name) {
880 Slog.v(TAG, getCaption() + " connection lost: " + name);
883 if (!mContext.bindServiceAsUser(intent,
885 BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
886 new UserHandle(userid))) {
887 mServicesBinding.remove(servicesBindingTag);
888 Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
891 } catch (SecurityException ex) {
892 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
897 * Remove a service for the given user by ComponentName
899 private void unregisterService(ComponentName name, int userid) {
900 synchronized (mMutex) {
901 unregisterServiceLocked(name, userid);
905 private void unregisterServiceLocked(ComponentName name, int userid) {
906 final int N = mServices.size();
907 for (int i = N - 1; i >= 0; i--) {
908 final ManagedServiceInfo info = mServices.get(i);
909 if (name.equals(info.component)
910 && info.userid == userid) {
911 removeServiceLocked(i);
912 if (info.connection != null) {
914 mContext.unbindService(info.connection);
915 } catch (IllegalArgumentException ex) {
916 // something happened to the service: we think we have a connection
918 Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
926 * Removes a service from the list but does not unbind
928 * @return the removed service.
930 private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
931 if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
932 ManagedServiceInfo serviceInfo = null;
933 synchronized (mMutex) {
934 final int N = mServices.size();
935 for (int i = N - 1; i >= 0; i--) {
936 final ManagedServiceInfo info = mServices.get(i);
937 if (info.service.asBinder() == service.asBinder()
938 && info.userid == userid) {
939 if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
940 serviceInfo = removeServiceLocked(i);
947 private ManagedServiceInfo removeServiceLocked(int i) {
948 final ManagedServiceInfo info = mServices.remove(i);
949 onServiceRemovedLocked(info);
953 private void checkNotNull(IInterface service) {
954 if (service == null) {
955 throw new IllegalArgumentException(getCaption() + " must not be null");
959 private ManagedServiceInfo registerServiceImpl(final IInterface service,
960 final ComponentName component, final int userid) {
961 ManagedServiceInfo info = newServiceInfo(service, component, userid,
962 true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
963 return registerServiceImpl(info);
966 private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
967 synchronized (mMutex) {
969 info.service.asBinder().linkToDeath(info, 0);
972 } catch (RemoteException e) {
980 * Removes a service from the list and unbinds.
982 private void unregisterServiceImpl(IInterface service, int userid) {
983 ManagedServiceInfo info = removeServiceImpl(service, userid);
984 if (info != null && info.connection != null && !info.isGuest(this)) {
985 mContext.unbindService(info.connection);
989 public class ManagedServiceInfo implements IBinder.DeathRecipient {
990 public IInterface service;
991 public ComponentName component;
993 public boolean isSystem;
994 public ServiceConnection connection;
995 public int targetSdkVersion;
997 public ManagedServiceInfo(IInterface service, ComponentName component,
998 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
999 this.service = service;
1000 this.component = component;
1001 this.userid = userid;
1002 this.isSystem = isSystem;
1003 this.connection = connection;
1004 this.targetSdkVersion = targetSdkVersion;
1007 public boolean isGuest(ManagedServices host) {
1008 return ManagedServices.this != host;
1011 public ManagedServices getOwner() {
1012 return ManagedServices.this;
1016 public String toString() {
1017 return new StringBuilder("ManagedServiceInfo[")
1018 .append("component=").append(component)
1019 .append(",userid=").append(userid)
1020 .append(",isSystem=").append(isSystem)
1021 .append(",targetSdkVersion=").append(targetSdkVersion)
1022 .append(",connection=").append(connection == null ? null : "<connection>")
1023 .append(",service=").append(service)
1024 .append(']').toString();
1027 public boolean enabledAndUserMatches(int nid) {
1028 if (!isEnabledForCurrentProfiles()) {
1031 if (this.userid == UserHandle.USER_ALL) return true;
1032 if (this.isSystem) return true;
1033 if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
1034 return supportsProfiles()
1035 && mUserProfiles.isCurrentProfile(nid)
1036 && isPermittedForProfile(nid);
1039 public boolean supportsProfiles() {
1040 return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
1044 public void binderDied() {
1045 if (DEBUG) Slog.d(TAG, "binderDied");
1046 // Remove the service, but don't unbind from the service. The system will bring the
1047 // service back up, and the onServiceConnected handler will read the service with the
1048 // new binding. If this isn't a bound service, and is just a registered
1049 // service, just removing it from the list is all we need to do anyway.
1050 removeServiceImpl(this.service, this.userid);
1053 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1054 public boolean isEnabledForCurrentProfiles() {
1055 if (this.isSystem) return true;
1056 if (this.connection == null) return false;
1057 return mEnabledServicesForCurrentProfiles.contains(this.component);
1061 * Returns true if this service is allowed to receive events for the given userId. A
1062 * managed profile owner can disallow non-system services running outside of the profile
1063 * from receiving events from the profile.
1065 public boolean isPermittedForProfile(int userId) {
1066 if (!mUserProfiles.isManagedProfile(userId)) {
1069 DevicePolicyManager dpm =
1070 (DevicePolicyManager) mContext.getSystemService(DEVICE_POLICY_SERVICE);
1071 final long identity = Binder.clearCallingIdentity();
1073 return dpm.isNotificationListenerServicePermitted(
1074 component.getPackageName(), userId);
1076 Binder.restoreCallingIdentity(identity);
1081 /** convenience method for looking in mEnabledServicesForCurrentProfiles */
1082 public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
1083 return mEnabledServicesForCurrentProfiles.contains(component);
1086 public static class UserProfiles {
1087 // Profiles of the current user.
1088 private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
1090 public void updateCache(@NonNull Context context) {
1091 UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
1092 if (userManager != null) {
1093 int currentUserId = ActivityManager.getCurrentUser();
1094 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
1095 synchronized (mCurrentProfiles) {
1096 mCurrentProfiles.clear();
1097 for (UserInfo user : profiles) {
1098 mCurrentProfiles.put(user.id, user);
1104 public int[] getCurrentProfileIds() {
1105 synchronized (mCurrentProfiles) {
1106 int[] users = new int[mCurrentProfiles.size()];
1107 final int N = mCurrentProfiles.size();
1108 for (int i = 0; i < N; ++i) {
1109 users[i] = mCurrentProfiles.keyAt(i);
1115 public boolean isCurrentProfile(int userId) {
1116 synchronized (mCurrentProfiles) {
1117 return mCurrentProfiles.get(userId) != null;
1121 public boolean isManagedProfile(int userId) {
1122 synchronized (mCurrentProfiles) {
1123 UserInfo user = mCurrentProfiles.get(userId);
1124 return user != null && user.isManagedProfile();
1129 public static class Config {
1130 public String caption;
1131 public String serviceInterface;
1132 public String secureSettingName;
1133 public String secondarySettingName;
1134 public String xmlTag;
1135 public String bindPermission;
1136 public String settingsAction;
1137 public int clientLabel;