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
17package com.android.server.notification;
18
19import static android.content.Context.BIND_ALLOW_WHITELIST_MANAGEMENT;
20import static android.content.Context.BIND_AUTO_CREATE;
21import static android.content.Context.BIND_FOREGROUND_SERVICE;
22
23import android.annotation.NonNull;
24import android.app.ActivityManager;
25import android.app.PendingIntent;
26import android.content.BroadcastReceiver;
27import android.content.ComponentName;
28import android.content.ContentResolver;
29import android.content.Context;
30import android.content.Intent;
31import android.content.IntentFilter;
32import android.content.ServiceConnection;
33import android.content.pm.ApplicationInfo;
34import android.content.pm.PackageManager;
35import android.content.pm.PackageManager.NameNotFoundException;
36import android.content.pm.ResolveInfo;
37import android.content.pm.ServiceInfo;
38import android.content.pm.UserInfo;
39import android.database.ContentObserver;
40import android.net.Uri;
41import android.os.Build;
42import android.os.Handler;
43import android.os.IBinder;
44import android.os.IInterface;
45import android.os.RemoteException;
46import android.os.UserHandle;
47import android.os.UserManager;
48import android.provider.Settings;
49import android.text.TextUtils;
50import android.util.ArraySet;
51import android.util.Log;
52import android.util.Slog;
53import android.util.SparseArray;
54
55import com.android.server.notification.NotificationManagerService.DumpFilter;
56
57import java.io.PrintWriter;
58import java.util.ArrayList;
59import java.util.Arrays;
60import java.util.HashSet;
61import java.util.List;
62import java.util.Objects;
63import java.util.Set;
64
65/**
66 * Manages the lifecycle of application-provided services bound by system server.
67 *
68 * Services managed by this helper must have:
69 *  - An associated system settings value with a list of enabled component names.
70 *  - A well-known action for services to use in their intent-filter.
71 *  - A system permission for services to require in order to ensure system has exclusive binding.
72 *  - A settings page for user configuration of enabled services, and associated intent action.
73 *  - A remote interface definition (aidl) provided by the service used for communication.
74 */
75abstract public class ManagedServices {
76    protected final String TAG = getClass().getSimpleName();
77    protected final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
78
79    protected static final String ENABLED_SERVICES_SEPARATOR = ":";
80
81    protected final Context mContext;
82    protected final Object mMutex;
83    private final UserProfiles mUserProfiles;
84    private final SettingsObserver mSettingsObserver;
85    private final Config mConfig;
86    private ArraySet<String> mRestored;
87
88    // contains connections to all connected services, including app services
89    // and system services
90    protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>();
91    // things that will be put into mServices as soon as they're ready
92    private final ArrayList<String> mServicesBinding = new ArrayList<String>();
93    // lists the component names of all enabled (and therefore potentially connected)
94    // app services for current profiles.
95    private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles
96            = new ArraySet<ComponentName>();
97    // Just the packages from mEnabledServicesForCurrentProfiles
98    private ArraySet<String> mEnabledServicesPackageNames = new ArraySet<String>();
99    // List of packages in restored setting across all mUserProfiles, for quick
100    // filtering upon package updates.
101    private ArraySet<String> mRestoredPackages = new ArraySet<>();
102    // List of enabled packages that have nevertheless asked not to be run
103    private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>();
104
105
106    // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a
107    // user change).
108    private int[] mLastSeenProfileIds;
109
110    private final BroadcastReceiver mRestoreReceiver;
111
112    public ManagedServices(Context context, Handler handler, Object mutex,
113            UserProfiles userProfiles) {
114        mContext = context;
115        mMutex = mutex;
116        mUserProfiles = userProfiles;
117        mConfig = getConfig();
118        mSettingsObserver = new SettingsObserver(handler);
119
120        mRestoreReceiver = new SettingRestoredReceiver();
121        IntentFilter filter = new IntentFilter(Intent.ACTION_SETTING_RESTORED);
122        context.registerReceiver(mRestoreReceiver, filter);
123        rebuildRestoredPackages();
124    }
125
126    class SettingRestoredReceiver extends BroadcastReceiver {
127        @Override
128        public void onReceive(Context context, Intent intent) {
129            if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
130                String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
131                if (Objects.equals(element, mConfig.secureSettingName)
132                        || Objects.equals(element, mConfig.secondarySettingName)) {
133                    String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
134                    String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
135                    settingRestored(element, prevValue, newValue, getSendingUserId());
136                }
137            }
138        }
139    }
140
141    abstract protected Config getConfig();
142
143    private String getCaption() {
144        return mConfig.caption;
145    }
146
147    abstract protected IInterface asInterface(IBinder binder);
148
149    abstract protected boolean checkType(IInterface service);
150
151    abstract protected void onServiceAdded(ManagedServiceInfo info);
152
153    protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
154
155    private ManagedServiceInfo newServiceInfo(IInterface service,
156            ComponentName component, int userid, boolean isSystem, ServiceConnection connection,
157            int targetSdkVersion) {
158        return new ManagedServiceInfo(service, component, userid, isSystem, connection,
159                targetSdkVersion);
160    }
161
162    public void onBootPhaseAppsCanStart() {
163        mSettingsObserver.observe();
164    }
165
166    public void dump(PrintWriter pw, DumpFilter filter) {
167        pw.println("    All " + getCaption() + "s (" + mEnabledServicesForCurrentProfiles.size()
168                + ") enabled for current profiles:");
169        for (ComponentName cmpt : mEnabledServicesForCurrentProfiles) {
170            if (filter != null && !filter.matches(cmpt)) continue;
171            pw.println("      " + cmpt);
172        }
173
174        pw.println("    Live " + getCaption() + "s (" + mServices.size() + "):");
175        for (ManagedServiceInfo info : mServices) {
176            if (filter != null && !filter.matches(info.component)) continue;
177            pw.println("      " + info.component
178                    + " (user " + info.userid + "): " + info.service
179                    + (info.isSystem?" SYSTEM":"")
180                    + (info.isGuest(this)?" GUEST":""));
181        }
182
183        pw.println("    Snoozed " + getCaption() + "s (" +
184                mSnoozingForCurrentProfiles.size() + "):");
185        for (ComponentName name : mSnoozingForCurrentProfiles) {
186            pw.println("      " + name.flattenToShortString());
187        }
188    }
189
190    // By convention, restored settings are replicated to another settings
191    // entry, named similarly but with a disambiguation suffix.
192    public static String restoredSettingName(String setting) {
193        return setting + ":restored";
194    }
195
196    // The OS has done a restore of this service's saved state.  We clone it to the
197    // 'restored' reserve, and then once we return and the actual write to settings is
198    // performed, our observer will do the work of maintaining the restored vs live
199    // settings data.
200    public void settingRestored(String element, String oldValue, String newValue, int userid) {
201        if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
202                + " ovalue=" + oldValue + " nvalue=" + newValue);
203        if (mConfig.secureSettingName.equals(element) ||
204                mConfig.secondarySettingName.equals(element)) {
205            if (element != null) {
206                Settings.Secure.putStringForUser(mContext.getContentResolver(),
207                        restoredSettingName(element),
208                        newValue,
209                        userid);
210                updateSettingsAccordingToInstalledServices(element, userid);
211                rebuildRestoredPackages();
212            }
213        }
214    }
215
216    public boolean isComponentEnabledForPackage(String pkg) {
217        return mEnabledServicesPackageNames.contains(pkg);
218    }
219
220    public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
221        if (DEBUG) Slog.d(TAG, "onPackagesChanged queryReplace=" + queryReplace
222                + " pkgList=" + (pkgList == null ? null : Arrays.asList(pkgList))
223                + " mEnabledServicesPackageNames=" + mEnabledServicesPackageNames);
224        boolean anyServicesInvolved = false;
225
226        if (pkgList != null && (pkgList.length > 0)) {
227            for (String pkgName : pkgList) {
228                if (mEnabledServicesPackageNames.contains(pkgName) ||
229                        mRestoredPackages.contains(pkgName)) {
230                    anyServicesInvolved = true;
231                }
232            }
233        }
234
235        if (anyServicesInvolved) {
236            // if we're not replacing a package, clean up orphaned bits
237            if (!queryReplace) {
238                updateSettingsAccordingToInstalledServices();
239                rebuildRestoredPackages();
240            }
241            // make sure we're still bound to any of our services who may have just upgraded
242            rebindServices(false);
243        }
244    }
245
246    public void onUserSwitched(int user) {
247        if (DEBUG) Slog.d(TAG, "onUserSwitched u=" + user);
248        rebuildRestoredPackages();
249        if (Arrays.equals(mLastSeenProfileIds, mUserProfiles.getCurrentProfileIds())) {
250            if (DEBUG) Slog.d(TAG, "Current profile IDs didn't change, skipping rebindServices().");
251            return;
252        }
253        rebindServices(true);
254    }
255
256    public void onUserUnlocked(int user) {
257        if (DEBUG) Slog.d(TAG, "onUserUnlocked u=" + user);
258        rebuildRestoredPackages();
259        rebindServices(false);
260    }
261
262    public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) {
263        if (service == null) {
264            return null;
265        }
266        final IBinder token = service.asBinder();
267        final int N = mServices.size();
268        for (int i = 0; i < N; i++) {
269            final ManagedServiceInfo info = mServices.get(i);
270            if (info.service.asBinder() == token) return info;
271        }
272        return null;
273    }
274
275    public ManagedServiceInfo checkServiceTokenLocked(IInterface service) {
276        checkNotNull(service);
277        ManagedServiceInfo info = getServiceFromTokenLocked(service);
278        if (info != null) {
279            return info;
280        }
281        throw new SecurityException("Disallowed call from unknown " + getCaption() + ": "
282                + service);
283    }
284
285    public void unregisterService(IInterface service, int userid) {
286        checkNotNull(service);
287        // no need to check permissions; if your service binder is in the list,
288        // that's proof that you had permission to add it in the first place
289        unregisterServiceImpl(service, userid);
290    }
291
292    public void registerService(IInterface service, ComponentName component, int userid) {
293        checkNotNull(service);
294        ManagedServiceInfo info = registerServiceImpl(service, component, userid);
295        if (info != null) {
296            onServiceAdded(info);
297        }
298    }
299
300    /**
301     * Add a service to our callbacks. The lifecycle of this service is managed externally,
302     * but unlike a system service, it should not be considered privledged.
303     * */
304    public void registerGuestService(ManagedServiceInfo guest) {
305        checkNotNull(guest.service);
306        if (!checkType(guest.service)) {
307            throw new IllegalArgumentException();
308        }
309        if (registerServiceImpl(guest) != null) {
310            onServiceAdded(guest);
311        }
312    }
313
314    public void setComponentState(ComponentName component, boolean enabled) {
315        boolean previous = !mSnoozingForCurrentProfiles.contains(component);
316        if (previous == enabled) {
317            return;
318        }
319
320        if (enabled) {
321            mSnoozingForCurrentProfiles.remove(component);
322        } else {
323            mSnoozingForCurrentProfiles.add(component);
324        }
325
326        // State changed
327        if (DEBUG) {
328            Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " +
329                    component.flattenToShortString());
330        }
331
332
333        synchronized (mMutex) {
334            final int[] userIds = mUserProfiles.getCurrentProfileIds();
335
336            for (int userId : userIds) {
337                if (enabled) {
338                    registerServiceLocked(component, userId);
339                } else {
340                    unregisterServiceLocked(component, userId);
341                }
342            }
343        }
344    }
345
346    private void rebuildRestoredPackages() {
347        mRestoredPackages.clear();
348        mSnoozingForCurrentProfiles.clear();
349        String secureSettingName = restoredSettingName(mConfig.secureSettingName);
350        String secondarySettingName = mConfig.secondarySettingName == null
351                ? null : restoredSettingName(mConfig.secondarySettingName);
352        int[] userIds = mUserProfiles.getCurrentProfileIds();
353        final int N = userIds.length;
354        for (int i = 0; i < N; ++i) {
355            ArraySet<ComponentName> names =
356                    loadComponentNamesFromSetting(secureSettingName, userIds[i]);
357            if (secondarySettingName != null) {
358                names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
359            }
360            for (ComponentName name : names) {
361                mRestoredPackages.add(name.getPackageName());
362            }
363        }
364    }
365
366
367    protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
368            int userId) {
369        final ContentResolver cr = mContext.getContentResolver();
370        String settingValue = Settings.Secure.getStringForUser(
371            cr,
372            settingName,
373            userId);
374        if (TextUtils.isEmpty(settingValue))
375            return new ArraySet<>();
376        String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
377        ArraySet<ComponentName> result = new ArraySet<>(restored.length);
378        for (int i = 0; i < restored.length; i++) {
379            ComponentName value = ComponentName.unflattenFromString(restored[i]);
380            if (null != value) {
381                result.add(value);
382            }
383        }
384        return result;
385    }
386
387    private void storeComponentsToSetting(Set<ComponentName> components,
388                                          String settingName,
389                                          int userId) {
390        String[] componentNames = null;
391        if (null != components) {
392            componentNames = new String[components.size()];
393            int index = 0;
394            for (ComponentName c: components) {
395                componentNames[index++] = c.flattenToString();
396            }
397        }
398        final String value = (componentNames == null) ? "" :
399                TextUtils.join(ENABLED_SERVICES_SEPARATOR, componentNames);
400        final ContentResolver cr = mContext.getContentResolver();
401        Settings.Secure.putStringForUser(
402            cr,
403            settingName,
404            value,
405            userId);
406    }
407
408    /**
409     * Remove access for any services that no longer exist.
410     */
411    private void updateSettingsAccordingToInstalledServices() {
412        int[] userIds = mUserProfiles.getCurrentProfileIds();
413        final int N = userIds.length;
414        for (int i = 0; i < N; ++i) {
415            updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
416            if (mConfig.secondarySettingName != null) {
417                updateSettingsAccordingToInstalledServices(
418                        mConfig.secondarySettingName, userIds[i]);
419            }
420        }
421        rebuildRestoredPackages();
422    }
423
424    protected Set<ComponentName> queryPackageForServices(String packageName, int userId) {
425        Set<ComponentName> installed = new ArraySet<>();
426        final PackageManager pm = mContext.getPackageManager();
427        Intent queryIntent = new Intent(mConfig.serviceInterface);
428        if (!TextUtils.isEmpty(packageName)) {
429            queryIntent.setPackage(packageName);
430        }
431        List<ResolveInfo> installedServices = pm.queryIntentServicesAsUser(
432                queryIntent,
433                PackageManager.GET_SERVICES | PackageManager.GET_META_DATA,
434                userId);
435        if (DEBUG)
436            Slog.v(TAG, mConfig.serviceInterface + " services: " + installedServices);
437        if (installedServices != null) {
438            for (int i = 0, count = installedServices.size(); i < count; i++) {
439                ResolveInfo resolveInfo = installedServices.get(i);
440                ServiceInfo info = resolveInfo.serviceInfo;
441
442                ComponentName component = new ComponentName(info.packageName, info.name);
443                if (!mConfig.bindPermission.equals(info.permission)) {
444                    Slog.w(TAG, "Skipping " + getCaption() + " service "
445                        + info.packageName + "/" + info.name
446                        + ": it does not require the permission "
447                        + mConfig.bindPermission);
448                    continue;
449                }
450                installed.add(component);
451            }
452        }
453        return installed;
454    }
455
456    private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
457        boolean restoredChanged = false;
458        boolean currentChanged = false;
459        Set<ComponentName> restored =
460                loadComponentNamesFromSetting(restoredSettingName(setting), userId);
461        Set<ComponentName> current =
462                loadComponentNamesFromSetting(setting, userId);
463        // Load all services for all packages.
464        Set<ComponentName> installed = queryPackageForServices(null, userId);
465
466        ArraySet<ComponentName> retained = new ArraySet<>();
467
468        for (ComponentName component : installed) {
469            if (null != restored) {
470                boolean wasRestored = restored.remove(component);
471                if (wasRestored) {
472                    // Freshly installed package has service that was mentioned in restored setting.
473                    if (DEBUG)
474                        Slog.v(TAG, "Restoring " + component + " for user " + userId);
475                    restoredChanged = true;
476                    currentChanged = true;
477                    retained.add(component);
478                    continue;
479                }
480            }
481
482            if (null != current) {
483                if (current.contains(component))
484                    retained.add(component);
485            }
486        }
487
488        currentChanged |= ((current == null ? 0 : current.size()) != retained.size());
489
490        if (currentChanged) {
491            if (DEBUG) Slog.v(TAG, "List of  " + getCaption() + " services was updated " + current);
492            storeComponentsToSetting(retained, setting, userId);
493        }
494
495        if (restoredChanged) {
496            if (DEBUG) Slog.v(TAG,
497                    "List of  " + getCaption() + " restored services was updated " + restored);
498            storeComponentsToSetting(restored, restoredSettingName(setting), userId);
499        }
500    }
501
502    /**
503     * Called whenever packages change, the user switches, or the secure setting
504     * is altered. (For example in response to USER_SWITCHED in our broadcast receiver)
505     */
506    private void rebindServices(boolean forceRebind) {
507        if (DEBUG) Slog.d(TAG, "rebindServices");
508        final int[] userIds = mUserProfiles.getCurrentProfileIds();
509        final int nUserIds = userIds.length;
510
511        final SparseArray<ArraySet<ComponentName>> componentsByUser = new SparseArray<>();
512
513        for (int i = 0; i < nUserIds; ++i) {
514            componentsByUser.put(userIds[i],
515                    loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
516            if (mConfig.secondarySettingName != null) {
517                componentsByUser.get(userIds[i]).addAll(
518                        loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
519            }
520        }
521
522        final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
523        final SparseArray<Set<ComponentName>> toAdd = new SparseArray<>();
524
525        synchronized (mMutex) {
526            // Rebind to non-system services if user switched
527            for (ManagedServiceInfo service : mServices) {
528                if (!service.isSystem && !service.isGuest(this)) {
529                    removableBoundServices.add(service);
530                }
531            }
532
533            mEnabledServicesForCurrentProfiles.clear();
534            mEnabledServicesPackageNames.clear();
535
536            for (int i = 0; i < nUserIds; ++i) {
537                // decode the list of components
538                final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
539                if (null == userComponents) {
540                    toAdd.put(userIds[i], new ArraySet<ComponentName>());
541                    continue;
542                }
543
544                final Set<ComponentName> add = new HashSet<>(userComponents);
545                add.removeAll(mSnoozingForCurrentProfiles);
546
547                toAdd.put(userIds[i], add);
548
549                mEnabledServicesForCurrentProfiles.addAll(userComponents);
550
551                for (int j = 0; j < userComponents.size(); j++) {
552                    final ComponentName component = userComponents.valueAt(j);
553                    mEnabledServicesPackageNames.add(component.getPackageName());
554                }
555            }
556        }
557
558        for (ManagedServiceInfo info : removableBoundServices) {
559            final ComponentName component = info.component;
560            final int oldUser = info.userid;
561            final Set<ComponentName> allowedComponents = toAdd.get(info.userid);
562            if (allowedComponents != null) {
563                if (allowedComponents.contains(component) && !forceRebind) {
564                    // Already bound, don't need to bind again.
565                    allowedComponents.remove(component);
566                } else {
567                    // No longer allowed to be bound, or must rebind.
568                    Slog.v(TAG, "disabling " + getCaption() + " for user "
569                            + oldUser + ": " + component);
570                    unregisterService(component, oldUser);
571                }
572            }
573        }
574
575        for (int i = 0; i < nUserIds; ++i) {
576            final Set<ComponentName> add = toAdd.get(userIds[i]);
577            for (ComponentName component : add) {
578                Slog.v(TAG, "enabling " + getCaption() + " for " + userIds[i] + ": " + component);
579                registerService(component, userIds[i]);
580            }
581        }
582
583        mLastSeenProfileIds = userIds;
584    }
585
586    /**
587     * Version of registerService that takes the name of a service component to bind to.
588     */
589    private void registerService(final ComponentName name, final int userid) {
590        synchronized (mMutex) {
591            registerServiceLocked(name, userid);
592        }
593    }
594
595    /**
596     * Inject a system service into the management list.
597     */
598    public void registerSystemService(final ComponentName name, final int userid) {
599        synchronized (mMutex) {
600            registerServiceLocked(name, userid, true /* isSystem */);
601        }
602    }
603
604    private void registerServiceLocked(final ComponentName name, final int userid) {
605        registerServiceLocked(name, userid, false /* isSystem */);
606    }
607
608    private void registerServiceLocked(final ComponentName name, final int userid,
609            final boolean isSystem) {
610        if (DEBUG) Slog.v(TAG, "registerService: " + name + " u=" + userid);
611
612        final String servicesBindingTag = name.toString() + "/" + userid;
613        if (mServicesBinding.contains(servicesBindingTag)) {
614            // stop registering this thing already! we're working on it
615            return;
616        }
617        mServicesBinding.add(servicesBindingTag);
618
619        final int N = mServices.size();
620        for (int i = N - 1; i >= 0; i--) {
621            final ManagedServiceInfo info = mServices.get(i);
622            if (name.equals(info.component)
623                && info.userid == userid) {
624                // cut old connections
625                if (DEBUG) Slog.v(TAG, "    disconnecting old " + getCaption() + ": "
626                    + info.service);
627                removeServiceLocked(i);
628                if (info.connection != null) {
629                    mContext.unbindService(info.connection);
630                }
631            }
632        }
633
634        Intent intent = new Intent(mConfig.serviceInterface);
635        intent.setComponent(name);
636
637        intent.putExtra(Intent.EXTRA_CLIENT_LABEL, mConfig.clientLabel);
638
639        final PendingIntent pendingIntent = PendingIntent.getActivity(
640            mContext, 0, new Intent(mConfig.settingsAction), 0);
641        intent.putExtra(Intent.EXTRA_CLIENT_INTENT, pendingIntent);
642
643        ApplicationInfo appInfo = null;
644        try {
645            appInfo = mContext.getPackageManager().getApplicationInfo(
646                name.getPackageName(), 0);
647        } catch (NameNotFoundException e) {
648            // Ignore if the package doesn't exist we won't be able to bind to the service.
649        }
650        final int targetSdkVersion =
651            appInfo != null ? appInfo.targetSdkVersion : Build.VERSION_CODES.BASE;
652
653        try {
654            if (DEBUG) Slog.v(TAG, "binding: " + intent);
655            ServiceConnection serviceConnection = new ServiceConnection() {
656                IInterface mService;
657
658                @Override
659                public void onServiceConnected(ComponentName name, IBinder binder) {
660                    boolean added = false;
661                    ManagedServiceInfo info = null;
662                    synchronized (mMutex) {
663                        mServicesBinding.remove(servicesBindingTag);
664                        try {
665                            mService = asInterface(binder);
666                            info = newServiceInfo(mService, name,
667                                userid, isSystem, this, targetSdkVersion);
668                            binder.linkToDeath(info, 0);
669                            added = mServices.add(info);
670                        } catch (RemoteException e) {
671                            // already dead
672                        }
673                    }
674                    if (added) {
675                        onServiceAdded(info);
676                    }
677                }
678
679                @Override
680                public void onServiceDisconnected(ComponentName name) {
681                    Slog.v(TAG, getCaption() + " connection lost: " + name);
682                }
683            };
684            if (!mContext.bindServiceAsUser(intent,
685                serviceConnection,
686                BIND_AUTO_CREATE | BIND_FOREGROUND_SERVICE | BIND_ALLOW_WHITELIST_MANAGEMENT,
687                new UserHandle(userid))) {
688                mServicesBinding.remove(servicesBindingTag);
689                Slog.w(TAG, "Unable to bind " + getCaption() + " service: " + intent);
690                return;
691            }
692        } catch (SecurityException ex) {
693            Slog.e(TAG, "Unable to bind " + getCaption() + " service: " + intent, ex);
694            return;
695        }
696    }
697
698    /**
699     * Remove a service for the given user by ComponentName
700     */
701    private void unregisterService(ComponentName name, int userid) {
702        synchronized (mMutex) {
703            unregisterServiceLocked(name, userid);
704        }
705    }
706
707    private void unregisterServiceLocked(ComponentName name, int userid) {
708        final int N = mServices.size();
709        for (int i = N - 1; i >= 0; i--) {
710            final ManagedServiceInfo info = mServices.get(i);
711            if (name.equals(info.component)
712                && info.userid == userid) {
713                removeServiceLocked(i);
714                if (info.connection != null) {
715                    try {
716                        mContext.unbindService(info.connection);
717                    } catch (IllegalArgumentException ex) {
718                        // something happened to the service: we think we have a connection
719                        // but it's bogus.
720                        Slog.e(TAG, getCaption() + " " + name + " could not be unbound: " + ex);
721                    }
722                }
723            }
724        }
725    }
726
727    /**
728     * Removes a service from the list but does not unbind
729     *
730     * @return the removed service.
731     */
732    private ManagedServiceInfo removeServiceImpl(IInterface service, final int userid) {
733        if (DEBUG) Slog.d(TAG, "removeServiceImpl service=" + service + " u=" + userid);
734        ManagedServiceInfo serviceInfo = null;
735        synchronized (mMutex) {
736            final int N = mServices.size();
737            for (int i = N - 1; i >= 0; i--) {
738                final ManagedServiceInfo info = mServices.get(i);
739                if (info.service.asBinder() == service.asBinder()
740                        && info.userid == userid) {
741                    if (DEBUG) Slog.d(TAG, "Removing active service " + info.component);
742                    serviceInfo = removeServiceLocked(i);
743                }
744            }
745        }
746        return serviceInfo;
747    }
748
749    private ManagedServiceInfo removeServiceLocked(int i) {
750        final ManagedServiceInfo info = mServices.remove(i);
751        onServiceRemovedLocked(info);
752        return info;
753    }
754
755    private void checkNotNull(IInterface service) {
756        if (service == null) {
757            throw new IllegalArgumentException(getCaption() + " must not be null");
758        }
759    }
760
761    private ManagedServiceInfo registerServiceImpl(final IInterface service,
762            final ComponentName component, final int userid) {
763        ManagedServiceInfo info = newServiceInfo(service, component, userid,
764                true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
765        return registerServiceImpl(info);
766    }
767
768    private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
769        synchronized (mMutex) {
770            try {
771                info.service.asBinder().linkToDeath(info, 0);
772                mServices.add(info);
773                return info;
774            } catch (RemoteException e) {
775                // already dead
776            }
777        }
778        return null;
779    }
780
781    /**
782     * Removes a service from the list and unbinds.
783     */
784    private void unregisterServiceImpl(IInterface service, int userid) {
785        ManagedServiceInfo info = removeServiceImpl(service, userid);
786        if (info != null && info.connection != null && !info.isGuest(this)) {
787            mContext.unbindService(info.connection);
788        }
789    }
790
791    private class SettingsObserver extends ContentObserver {
792        private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
793        private final Uri mSecondarySettingsUri;
794
795        private SettingsObserver(Handler handler) {
796            super(handler);
797            if (mConfig.secondarySettingName != null) {
798                mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
799            } else {
800                mSecondarySettingsUri = null;
801            }
802        }
803
804        private void observe() {
805            ContentResolver resolver = mContext.getContentResolver();
806            resolver.registerContentObserver(mSecureSettingsUri,
807                    false, this, UserHandle.USER_ALL);
808            if (mSecondarySettingsUri != null) {
809                resolver.registerContentObserver(mSecondarySettingsUri,
810                        false, this, UserHandle.USER_ALL);
811            }
812            update(null);
813        }
814
815        @Override
816        public void onChange(boolean selfChange, Uri uri) {
817            update(uri);
818        }
819
820        private void update(Uri uri) {
821            if (uri == null || mSecureSettingsUri.equals(uri)
822                    || uri.equals(mSecondarySettingsUri)) {
823                if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
824                rebindServices(false);
825                rebuildRestoredPackages();
826            }
827        }
828    }
829
830    public class ManagedServiceInfo implements IBinder.DeathRecipient {
831        public IInterface service;
832        public ComponentName component;
833        public int userid;
834        public boolean isSystem;
835        public ServiceConnection connection;
836        public int targetSdkVersion;
837
838        public ManagedServiceInfo(IInterface service, ComponentName component,
839                int userid, boolean isSystem, ServiceConnection connection, int targetSdkVersion) {
840            this.service = service;
841            this.component = component;
842            this.userid = userid;
843            this.isSystem = isSystem;
844            this.connection = connection;
845            this.targetSdkVersion = targetSdkVersion;
846        }
847
848        public boolean isGuest(ManagedServices host) {
849            return ManagedServices.this != host;
850        }
851
852        public ManagedServices getOwner() {
853            return ManagedServices.this;
854        }
855
856        @Override
857        public String toString() {
858            return new StringBuilder("ManagedServiceInfo[")
859                    .append("component=").append(component)
860                    .append(",userid=").append(userid)
861                    .append(",isSystem=").append(isSystem)
862                    .append(",targetSdkVersion=").append(targetSdkVersion)
863                    .append(",connection=").append(connection == null ? null : "<connection>")
864                    .append(",service=").append(service)
865                    .append(']').toString();
866        }
867
868        public boolean enabledAndUserMatches(int nid) {
869            if (!isEnabledForCurrentProfiles()) {
870                return false;
871            }
872            if (this.userid == UserHandle.USER_ALL) return true;
873            if (this.isSystem) return true;
874            if (nid == UserHandle.USER_ALL || nid == this.userid) return true;
875            return supportsProfiles() && mUserProfiles.isCurrentProfile(nid);
876        }
877
878        public boolean supportsProfiles() {
879            return targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
880        }
881
882        @Override
883        public void binderDied() {
884            if (DEBUG) Slog.d(TAG, "binderDied");
885            // Remove the service, but don't unbind from the service. The system will bring the
886            // service back up, and the onServiceConnected handler will readd the service with the
887            // new binding. If this isn't a bound service, and is just a registered
888            // service, just removing it from the list is all we need to do anyway.
889            removeServiceImpl(this.service, this.userid);
890        }
891
892        /** convenience method for looking in mEnabledServicesForCurrentProfiles */
893        public boolean isEnabledForCurrentProfiles() {
894            if (this.isSystem) return true;
895            if (this.connection == null) return false;
896            return mEnabledServicesForCurrentProfiles.contains(this.component);
897        }
898    }
899
900    /** convenience method for looking in mEnabledServicesForCurrentProfiles */
901    public boolean isComponentEnabledForCurrentProfiles(ComponentName component) {
902        return mEnabledServicesForCurrentProfiles.contains(component);
903    }
904
905    public static class UserProfiles {
906        // Profiles of the current user.
907        private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<>();
908
909        public void updateCache(@NonNull Context context) {
910            UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
911            if (userManager != null) {
912                int currentUserId = ActivityManager.getCurrentUser();
913                List<UserInfo> profiles = userManager.getProfiles(currentUserId);
914                synchronized (mCurrentProfiles) {
915                    mCurrentProfiles.clear();
916                    for (UserInfo user : profiles) {
917                        mCurrentProfiles.put(user.id, user);
918                    }
919                }
920            }
921        }
922
923        public int[] getCurrentProfileIds() {
924            synchronized (mCurrentProfiles) {
925                int[] users = new int[mCurrentProfiles.size()];
926                final int N = mCurrentProfiles.size();
927                for (int i = 0; i < N; ++i) {
928                    users[i] = mCurrentProfiles.keyAt(i);
929                }
930                return users;
931            }
932        }
933
934        public boolean isCurrentProfile(int userId) {
935            synchronized (mCurrentProfiles) {
936                return mCurrentProfiles.get(userId) != null;
937            }
938        }
939    }
940
941    public static class Config {
942        public String caption;
943        public String serviceInterface;
944        public String secureSettingName;
945        public String secondarySettingName;
946        public String bindPermission;
947        public String settingsAction;
948        public int clientLabel;
949    }
950}
951