OSDN Git Service

DO NOT MERGE Remove window obscurement information. am: c3c2ed94ff am: 96fe6421f6...
[android-x86/frameworks-base.git] / services / core / java / com / android / server / notification / ManagedServices.java
1 /**
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
17 package com.android.server.notification;
18
19 import android.app.ActivityManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.ComponentName;
23 import android.content.ContentResolver;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.content.IntentFilter;
27 import android.content.ServiceConnection;
28 import android.content.pm.ApplicationInfo;
29 import android.content.pm.PackageManager;
30 import android.content.pm.PackageManager.NameNotFoundException;
31 import android.content.pm.ResolveInfo;
32 import android.content.pm.ServiceInfo;
33 import android.content.pm.UserInfo;
34 import android.database.ContentObserver;
35 import android.net.Uri;
36 import android.os.Build;
37 import android.os.Handler;
38 import android.os.IBinder;
39 import android.os.IInterface;
40 import android.os.RemoteException;
41 import android.os.UserHandle;
42 import android.os.UserManager;
43 import android.provider.Settings;
44 import android.text.TextUtils;
45 import android.util.ArraySet;
46 import android.util.Log;
47 import android.util.Slog;
48 import android.util.SparseArray;
49
50 import com.android.server.notification.NotificationManagerService.DumpFilter;
51
52 import java.io.PrintWriter;
53 import java.util.ArrayList;
54 import java.util.Arrays;
55 import java.util.List;
56 import java.util.Objects;
57 import java.util.Set;
58
59 /**
60  * Manages the lifecycle of application-provided services bound by system server.
61  *
62  * Services managed by this helper must have:
63  *  - An associated system settings value with a list of enabled component names.
64  *  - A well-known action for services to use in their intent-filter.
65  *  - A system permission for services to require in order to ensure system has exclusive binding.
66  *  - A settings page for user configuration of enabled services, and associated intent action.
67  *  - A remote interface definition (aidl) provided by the service used for communication.
68  */
69 abstract public class ManagedServices {
70     protected final String TAG = getClass().getSimpleName();
71     protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
72
73     private static final String ENABLED_SERVICES_SEPARATOR = ":";
74
75     protected final Context mContext;
76     protected final Object mMutex;
77     private final UserProfiles mUserProfiles;
78     private final SettingsObserver mSettingsObserver;
79     private final Config mConfig;
80     private ArraySet<String> mRestored;
81
82     // contains connections to all connected services, including app services
83     // and system services
84     protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
85     // things that will be put into mServices as soon as they're ready
86     private final ArrayList<String> mServicesBinding = new ArrayList<String>();
87     // lists the component names of all enabled (and therefore connected)
88     // app services for current profiles.
89     private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
90             = new ArraySet<ComponentName>();
91     // Just the packages from mEnabledServicesForCurrentProfiles
92     private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
93
94     // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
95     // user change).
96     private int[] mLastSeenProfileIds;
97
98     private final BroadcastReceiver mRestoreReceiver;
99
100     public ManagedServices(Context context, Handler handler, Object mutex,
101             UserProfiles userProfiles) {
102         mContext = context;
103         mMutex = mutex;
104         mUserProfiles = userProfiles;
105         mConfig = getConfig();
106         mSettingsObserver = new SettingsObserver(handler);
107
108         mRestoreReceiver = new SettingRestoredReceiver();
109         IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
110         context.registerReceiver(mRestoreReceiver, filter);
111     }
112
113     class SettingRestoredReceiver extends BroadcastReceiver {
114         @Override
115         public void onReceive(Context context, Intent intent) {
116             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
117                 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
118                 if (Objects.equals(element, mConfig.secureSettingName)) {
119                     String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
120                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
121                     settingRestored(element, prevValue, newValue, getSendingUserId());
122                 }
123             }
124         }
125     }
126
127     abstract protected Config getConfig();
128
129     private String getCaption() {
130         return mConfig.caption;
131     }
132
133     abstract protected IInterface asInterface(IBinder binder);
134
135     abstract protected void onServiceAdded(ManagedServiceInfo info);
136
137     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
138
139     private ManagedServiceInfo newServiceInfo(IInterface service,
140             ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
141             int targetSdkVersion) {
142         return new ManagedServiceInfo(service, component, userid, isSystem, connection,
143                 targetSdkVersion);
144     }
145
146     public void onBootPhaseAppsCanStart() {
147         mSettingsObserver.observe();
148     }
149
150     public void dump(PrintWriter pw, DumpFilter filter) {
151         pw.println("    All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
152                 + ") enabled for current profiles:");
153         for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
154             if (filter != null && !filter.matches(cmpt)) continue;
155             pw.println("      " + cmpt);
156         }
157
158         pw.println("    Live " + getCaption() + "s (" + mServices.size() + "):");
159         for (ManagedServiceInfo info : mServices) {
160             if (filter != null && !filter.matches(info.component)) continue;
161             pw.println("      " + info.component
162                     + " (user " + info.userid + "): " + info.service
163                     + (info.isSystem?" SYSTEM":""));
164         }
165     }
166
167     // By convention, restored settings are replicated to another settings
168     // entry, named similarly but with a disambiguation suffix.
169     public static final String restoredSettingName(Config config) {
170         return config.secureSettingName + ":restored";
171     }
172
173     // The OS has done a restore of this service's saved state.  We clone it to the
174     // 'restored' reserve, and then once we return and the actual write to settings is
175     // performed, our observer will do the work of maintaining the restored vs live
176     // settings data.
177     public void settingRestored(String element, String oldValue, String newValue, int userid) {
178         if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
179                 + " ovalue=" + oldValue + " nvalue=" + newValue);
180         if (mConfig.secureSettingName.equals(element)) {
181             if (element != null) {
182                 mRestored = null;
183                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
184                         restoredSettingName(mConfig),
185                         newValue,
186                         userid);
187                 disableNonexistentServices(userid);
188             }
189         }
190     }
191
192     public boolean isComponentEnabledForPackage(String pkg) {
193         return mEnabledServicesPackageNames.contains(pkg);
194     }
195
196     public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
197         if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
198                 + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
199                 + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
200         boolean anyServicesInvolved = false;
201         if (pkgList != null && (pkgList.length > 0)) {
202             for (String pkgName : pkgList) {
203                 if (mEnabledServicesPackageNames.contains(pkgName)) {
204                     anyServicesInvolved = true;
205                 }
206             }
207         }
208
209         if (anyServicesInvolved) {
210             // if we're not replacing a package, clean up orphaned bits
211             if (!queryReplace) {
212                 disableNonexistentServices();
213             }
214             // make sure we're still bound to any of our services who may have just upgraded
215             rebindServices();
216         }
217     }
218
219     public void onUserSwitched(int user) {
220         if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
221         if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
222             if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
223             return;
224         }
225         rebindServices();
226     }
227
228     public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
229         checkNotNull(service);
230         final IBinder token = service.asBinder();
231         final int N = mServices.size();
232         for (int i=0; i<N; i++) {
233             final ManagedServiceInfo info = mServices.get(i);
234             if (info.service.asBinder() == token) return info;
235         }
236         throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
237                 + service);
238     }
239
240     public void unregisterService(IInterface service, int userid) {
241         checkNotNull(service);
242         // no need to check permissions; if your service binder is in the list,
243         // that's proof that you had permission to add it in the first place
244         unregisterServiceImpl(service, userid);
245     }
246
247     public void registerService(IInterface service, ComponentName component, int userid) {
248         checkNotNull(service);
249         ManagedServiceInfo info = registerServiceImpl(service, component, userid);
250         if (info != null) {
251             onServiceAdded(info);
252         }
253     }
254
255     /**
256      * Remove access for any services that no longer exist.
257      */
258     private void disableNonexistentServices() {
259         int[] userIds = mUserProfiles.getCurrentProfileIds();
260         final int N = userIds.length;
261         for (int i = 0 ; i < N; ++i) {
262             disableNonexistentServices(userIds[i]);
263         }
264     }
265
266     private void disableNonexistentServices(int userId) {
267         final ContentResolver cr = mContext.getContentResolver();
268         boolean restoredChanged = false;
269         if (mRestored == null) {
270             String restoredSetting = Settings.Secure.getStringForUser(
271                     cr,
272                     restoredSettingName(mConfig),
273                     userId);
274             if (!TextUtils.isEmpty(restoredSetting)) {
275                 if (DEBUG) Slog.d(TAG, "restored: " + restoredSetting);
276                 String[] restored = restoredSetting.split(ENABLED_SERVICES_SEPARATOR);
277                 mRestored = new ArraySet<String>(Arrays.asList(restored));
278             } else {
279                 mRestored = new ArraySet<String>();
280             }
281         }
282         String flatIn = Settings.Secure.getStringForUser(
283                 cr,
284                 mConfig.secureSettingName,
285                 userId);
286         if (!TextUtils.isEmpty(flatIn)) {
287             if (DEBUG) Slog.v(TAG, "flat before: " + flatIn);
288             PackageManager pm = mContext.getPackageManager();
289             List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
290                     new Intent(mConfig.serviceInterface),
291                     PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
292                     userId);
293             if (DEBUG) Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
294             Set<ComponentName> installed = new ArraySet<ComponentName>();
295             for (int i = 0, count = installedServices.size(); i < count; i++) {
296                 ResolveInfo resolveInfo = installedServices.get(i);
297                 ServiceInfo info = resolveInfo.serviceInfo;
298
299                 ComponentName component = new ComponentName(info.packageName, info.name);
300                 if (!mConfig.bindPermission.equals(info.permission)) {
301                     Slog.w(TAG, "Skipping " + getCaption() + " service "
302                             + info.packageName + "/" + info.name
303                             + ": it does not require the permission "
304                             + mConfig.bindPermission);
305                     restoredChanged |= mRestored.remove(component.flattenToString());
306                     continue;
307                 }
308                 installed.add(component);
309             }
310
311             String flatOut = "";
312             if (!installed.isEmpty()) {
313                 String[] enabled = flatIn.split(ENABLED_SERVICES_SEPARATOR);
314                 ArrayList<String> remaining = new ArrayList<String>(enabled.length);
315                 for (int i = 0; i < enabled.length; i++) {
316                     ComponentName enabledComponent = ComponentName.unflattenFromString(enabled[i]);
317                     if (installed.contains(enabledComponent)) {
318                         remaining.add(enabled[i]);
319                         restoredChanged |= mRestored.remove(enabled[i]);
320                     }
321                 }
322                 remaining.addAll(mRestored);
323                 flatOut = TextUtils.join(ENABLED_SERVICES_SEPARATOR, remaining);
324             }
325             if (DEBUG) Slog.v(TAG, "flat after: " + flatOut);
326             if (!flatIn.equals(flatOut)) {
327                 Settings.Secure.putStringForUser(cr,
328                         mConfig.secureSettingName,
329                         flatOut, userId);
330             }
331             if (restoredChanged) {
332                 if (DEBUG) Slog.d(TAG, "restored changed; rewriting");
333                 final String flatRestored = TextUtils.join(ENABLED_SERVICES_SEPARATOR,
334                         mRestored.toArray());
335                 Settings.Secure.putStringForUser(cr,
336                         restoredSettingName(mConfig),
337                         flatRestored,
338                         userId);
339             }
340         }
341     }
342
343     /**
344      * Called whenever packages change, the user switches, or the secure setting
345      * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
346      */
347     private void rebindServices() {
348         if (DEBUG) Slog.d(TAG, "rebindServices");
349         final int[] userIds = mUserProfiles.getCurrentProfileIds();
350         final int nUserIds = userIds.length;
351
352         final SparseArray<String> flat = new SparseArray<String>();
353
354         for (int i = 0; i < nUserIds; ++i) {
355             flat.put(userIds[i], Settings.Secure.getStringForUser(
356                     mContext.getContentResolver(),
357                     mConfig.secureSettingName,
358                     userIds[i]));
359         }
360
361         ArrayList<ManagedServiceInfo> toRemove = new ArrayList<ManagedServiceInfo>();
362         final SparseArray<ArrayList<ComponentName>> toAdd
363                 = new SparseArray<ArrayList<ComponentName>>();
364
365         synchronized (mMutex) {
366             // Unbind automatically bound services, retain system services.
367             for (ManagedServiceInfo service : mServices) {
368                 if (!service.isSystem) {
369                     toRemove.add(service);
370                 }
371             }
372
373             final ArraySet<ComponentName> newEnabled = new ArraySet<ComponentName>();
374             final ArraySet<String> newPackages = new ArraySet<String>();
375
376             for (int i = 0; i < nUserIds; ++i) {
377                 final ArrayList<ComponentName> add = new ArrayList<ComponentName>();
378                 toAdd.put(userIds[i], add);
379
380                 // decode the list of components
381                 String toDecode = flat.get(userIds[i]);
382                 if (toDecode != null) {
383                     String[] components = toDecode.split(ENABLED_SERVICES_SEPARATOR);
384                     for (int j = 0; j < components.length; j++) {
385                         final ComponentName component
386                                 = ComponentName.unflattenFromString(components[j]);
387                         if (component != null) {
388                             newEnabled.add(component);
389                             add.add(component);
390                             newPackages.add(component.getPackageName());
391                         }
392                     }
393
394                 }
395             }
396             mEnabledServicesForCurrentProfiles = newEnabled;
397             mEnabledServicesPackageNames = newPackages;
398         }
399
400         for (ManagedServiceInfo info : toRemove) {
401             final ComponentName component = info.component;
402             final int oldUser = info.userid;
403             Slog.v(TAG, "disabling " + getCaption() + " for user "
404                     + oldUser + ": " + component);
405             unregisterService(component, info.userid);
406         }
407
408         for (int i = 0; i < nUserIds; ++i) {
409             final ArrayList<ComponentName> add = toAdd.get(userIds[i]);
410             final int N = add.size();
411             for (int j = 0; j < N; j++) {
412                 final ComponentName component = add.get(j);
413                 Slog.v(TAG, "enabling " + getCaption() + " for user " + userIds[i] + ": "
414                         + component);
415                 registerService(component, userIds[i]);
416             }
417         }
418
419         mLastSeenProfileIds = mUserProfiles.getCurrentProfileIds();
420     }
421
422     /**
423      * Version of registerService that takes the name of a service component to bind to.
424      */
425     private void registerService(final ComponentName name, final int userid) {
426         if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
427
428         synchronized (mMutex) {
429             final String servicesBindingTag = name.toString() + "/" + userid;
430             if (mServicesBinding.contains(servicesBindingTag)) {
431                 // stop registering this thing already! we're working on it
432                 return;
433             }
434             mServicesBinding.add(servicesBindingTag);
435
436             final int N = mServices.size();
437             for (int i=N-1; i>=0; i--) {
438                 final ManagedServiceInfo info = mServices.get(i);
439                 if (name.equals(info.component)
440                         && info.userid == userid) {
441                     // cut old connections
442                     if (DEBUG) Slog.v(TAG, "    disconnecting old " + getCaption() + ": "
443                             + info.service);
444                     removeServiceLocked(i);
445                     if (info.connection != null) {
446                         mContext.unbindService(info.connection);
447                     }
448                 }
449             }
450
451             Intent intent = new Intent(mConfig.serviceInterface);
452             intent.setComponent(name);
453
454             intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
455
456             final PendingIntent pendingIntent = PendingIntent.getActivity(
457                     mContext, 0, new Intent(mConfig.settingsAction), 0);
458             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
459
460             ApplicationInfo appInfo = null;
461             try {
462                 appInfo = mContext.getPackageManager().getApplicationInfo(
463                         name.getPackageName(), 0);
464             } catch (NameNotFoundException e) {
465                 // Ignore if the package doesn't exist we won't be able to bind to the service.
466             }
467             final int targetSdkVersion =
468                     appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
469
470             try {
471                 if (DEBUG) Slog.v(TAG, "binding: " + intent);
472                 if (!mContext.bindServiceAsUser(intent,
473                         new ServiceConnection() {
474                             IInterface mService;
475
476                             @Override
477                             public void onServiceConnected(ComponentName name, IBinder binder) {
478                                 boolean added = false;
479                                 ManagedServiceInfo info = null;
480                                 synchronized (mMutex) {
481                                     mServicesBinding.remove(servicesBindingTag);
482                                     try {
483                                         mService = asInterface(binder);
484                                         info = newServiceInfo(mService, name,
485                                                 userid, false /*isSystem*/, this, targetSdkVersion);
486                                         binder.linkToDeath(info, 0);
487                                         added = mServices.add(info);
488                                     } catch (RemoteException e) {
489                                         // already dead
490                                     }
491                                 }
492                                 if (added) {
493                                     onServiceAdded(info);
494                                 }
495                             }
496
497                             @Override
498                             public void onServiceDisconnected(ComponentName name) {
499                                 Slog.v(TAG, getCaption() + " connection lost: " + name);
500                             }
501                         },
502                         Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
503                         new UserHandle(userid)))
504                 {
505                     mServicesBinding.remove(servicesBindingTag);
506                     Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
507                     return;
508                 }
509             } catch (SecurityException ex) {
510                 Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
511                 return;
512             }
513         }
514     }
515
516     /**
517      * Remove a service for the given user by ComponentName
518      */
519     private void unregisterService(ComponentName name, int userid) {
520         synchronized (mMutex) {
521             final int N = mServices.size();
522             for (int i=N-1; i>=0; i--) {
523                 final ManagedServiceInfo info = mServices.get(i);
524                 if (name.equals(info.component)
525                         && info.userid == userid) {
526                     removeServiceLocked(i);
527                     if (info.connection != null) {
528                         try {
529                             mContext.unbindService(info.connection);
530                         } catch (IllegalArgumentException ex) {
531                             // something happened to the service: we think we have a connection
532                             // but it's bogus.
533                             Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
534                         }
535                     }
536                 }
537             }
538         }
539     }
540
541     /**
542      * Removes a service from the list but does not unbind
543      *
544      * @return the removed service.
545      */
546     private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
547         if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
548         ManagedServiceInfo serviceInfo = null;
549         synchronized (mMutex) {
550             final int N = mServices.size();
551             for (int i=N-1; i>=0; i--) {
552                 final ManagedServiceInfo info = mServices.get(i);
553                 if (info.service.asBinder() == service.asBinder()
554                         && info.userid == userid) {
555                     if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
556                     serviceInfo = removeServiceLocked(i);
557                 }
558             }
559         }
560         return serviceInfo;
561     }
562
563     private ManagedServiceInfo removeServiceLocked(int i) {
564         final ManagedServiceInfo info = mServices.remove(i);
565         onServiceRemovedLocked(info);
566         return info;
567     }
568
569     private void checkNotNull(IInterface service) {
570         if (service == null) {
571             throw new IllegalArgumentException(getCaption() + " must not be null");
572         }
573     }
574
575     private ManagedServiceInfo registerServiceImpl(final IInterface service,
576             final ComponentName component, final int userid) {
577         synchronized (mMutex) {
578             try {
579                 ManagedServiceInfo info = newServiceInfo(service, component, userid,
580                         true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
581                 service.asBinder().linkToDeath(info, 0);
582                 mServices.add(info);
583                 return info;
584             } catch (RemoteException e) {
585                 // already dead
586             }
587         }
588         return null;
589     }
590
591     /**
592      * Removes a service from the list and unbinds.
593      */
594     private void unregisterServiceImpl(IInterface service, int userid) {
595         ManagedServiceInfo info = removeServiceImpl(service, userid);
596         if (info != null && info.connection != null) {
597             mContext.unbindService(info.connection);
598         }
599     }
600
601     private class SettingsObserver extends ContentObserver {
602         private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
603
604         private SettingsObserver(Handler handler) {
605             super(handler);
606         }
607
608         private void observe() {
609             ContentResolver resolver = mContext.getContentResolver();
610             resolver.registerContentObserver(mSecureSettingsUri,
611                     false, this, UserHandle.USER_ALL);
612             update(null);
613         }
614
615         @Override
616         public void onChange(boolean selfChange, Uri uri) {
617             update(uri);
618         }
619
620         private void update(Uri uri) {
621             if (uri == null || mSecureSettingsUri.equals(uri)) {
622                 if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
623                         " / uri=" + uri);
624                 rebindServices();
625             }
626         }
627     }
628
629     public class ManagedServiceInfo implements IBinder.DeathRecipient {
630         public IInterface service;
631         public ComponentName component;
632         public int userid;
633         public boolean isSystem;
634         public ServiceConnection connection;
635         public int targetSdkVersion;
636
637         public ManagedServiceInfo(IInterface service, ComponentName component,
638                 int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
639             this.service = service;
640             this.component = component;
641             this.userid = userid;
642             this.isSystem = isSystem;
643             this.connection = connection;
644             this.targetSdkVersion = targetSdkVersion;
645         }
646
647         @Override
648         public String toString() {
649             return new StringBuilder("ManagedServiceInfo[")
650                     .append("component=").append(component)
651                     .append(",userid=").append(userid)
652                     .append(",isSystem=").append(isSystem)
653                     .append(",targetSdkVersion=").append(targetSdkVersion)
654                     .append(",connection=").append(connection == null ? null : "<connection>")
655                     .append(",service=").append(service)
656                     .append(']').toString();
657         }
658
659         public boolean enabledAndUserMatches(int nid) {
660             if (!isEnabledForCurrentProfiles()) {
661                 return false;
662             }
663             if (this.userid == UserHandle.USER_ALL) return true;
664             if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
665             return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
666         }
667
668         public boolean supportsProfiles() {
669             return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
670         }
671
672         @Override
673         public void binderDied() {
674             if (DEBUG) Slog.d(TAG, "binderDied");
675             // Remove the service, but don't unbind from the service. The system will bring the
676             // service back up, and the onServiceConnected handler will readd the service with the
677             // new binding. If this isn't a bound service, and is just a registered
678             // service, just removing it from the list is all we need to do anyway.
679             removeServiceImpl(this.service, this.userid);
680         }
681
682         /** convenience method for looking in mEnabledServicesForCurrentProfiles */
683         public boolean isEnabledForCurrentProfiles() {
684             if (this.isSystem) return true;
685             if (this.connection == null) return false;
686             return mEnabledServicesForCurrentProfiles.contains(this.component);
687         }
688     }
689
690     public static class UserProfiles {
691         // Profiles of the current user.
692         private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>();
693
694         public void updateCache(Context context) {
695             UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
696             if (userManager != null) {
697                 int currentUserId = ActivityManager.getCurrentUser();
698                 List<UserInfo> profiles = userManager.getProfiles(currentUserId);
699                 synchronized (mCurrentProfiles) {
700                     mCurrentProfiles.clear();
701                     for (UserInfo user : profiles) {
702                         mCurrentProfiles.put(user.id, user);
703                     }
704                 }
705             }
706         }
707
708         public int[] getCurrentProfileIds() {
709             synchronized (mCurrentProfiles) {
710                 int[] users = new int[mCurrentProfiles.size()];
711                 final int N = mCurrentProfiles.size();
712                 for (int i = 0; i < N; ++i) {
713                     users[i] = mCurrentProfiles.keyAt(i);
714                 }
715                 return users;
716             }
717         }
718
719         public boolean isCurrentProfile(int userId) {
720             synchronized (mCurrentProfiles) {
721                 return mCurrentProfiles.get(userId) != null;
722             }
723         }
724     }
725
726     protected static class Config {
727         String caption;
728         String serviceInterface;
729         String secureSettingName;
730         String bindPermission;
731         String settingsAction;
732         int clientLabel;
733     }
734 }