AutofillManagerService.java revision 6a6cd3fa38c515abec602ea05d15efc8f22fcc71
1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.autofill;
18
19import static android.Manifest.permission.MANAGE_AUTO_FILL;
20import static android.content.Context.AUTOFILL_MANAGER_SERVICE;
21
22import static com.android.server.autofill.Helper.bundleToString;
23import static com.android.server.autofill.Helper.sDebug;
24import static com.android.server.autofill.Helper.sPartitionMaxCount;
25import static com.android.server.autofill.Helper.sVerbose;
26
27import android.annotation.NonNull;
28import android.annotation.Nullable;
29import android.app.ActivityManager;
30import android.app.ActivityThread;
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.ContentResolver;
34import android.content.Context;
35import android.content.Intent;
36import android.content.IntentFilter;
37import android.content.pm.PackageManager;
38import android.content.pm.UserInfo;
39import android.database.ContentObserver;
40import android.graphics.Rect;
41import android.net.Uri;
42import android.os.Binder;
43import android.os.Build;
44import android.os.Bundle;
45import android.os.Handler;
46import android.os.IBinder;
47import android.os.RemoteException;
48import android.os.ResultReceiver;
49import android.os.ShellCallback;
50import android.os.UserHandle;
51import android.os.UserManager;
52import android.os.UserManagerInternal;
53import android.provider.Settings;
54import android.service.autofill.FillEventHistory;
55import android.util.LocalLog;
56import android.util.Slog;
57import android.util.SparseArray;
58import android.util.SparseBooleanArray;
59import android.view.autofill.AutofillId;
60import android.view.autofill.AutofillManager;
61import android.view.autofill.AutofillManagerInternal;
62import android.view.autofill.AutofillValue;
63import android.view.autofill.IAutoFillManager;
64import android.view.autofill.IAutoFillManagerClient;
65
66import com.android.internal.annotations.GuardedBy;
67import com.android.internal.content.PackageMonitor;
68import com.android.internal.os.BackgroundThread;
69import com.android.internal.os.IResultReceiver;
70import com.android.internal.util.DumpUtils;
71import com.android.internal.util.Preconditions;
72import com.android.server.FgThread;
73import com.android.server.LocalServices;
74import com.android.server.SystemService;
75import com.android.server.autofill.ui.AutoFillUI;
76
77import java.io.FileDescriptor;
78import java.io.PrintWriter;
79import java.util.ArrayList;
80import java.util.List;
81import java.util.Objects;
82
83/**
84 * Entry point service for autofill management.
85 *
86 * <p>This service provides the {@link IAutoFillManager} implementation and keeps a list of
87 * {@link AutofillManagerServiceImpl} per user; the real work is done by
88 * {@link AutofillManagerServiceImpl} itself.
89 */
90public final class AutofillManagerService extends SystemService {
91
92    private static final String TAG = "AutofillManagerService";
93
94    static final String RECEIVER_BUNDLE_EXTRA_SESSIONS = "sessions";
95
96    private final Context mContext;
97    private final AutoFillUI mUi;
98
99    private final Object mLock = new Object();
100
101    /**
102     * Cache of {@link AutofillManagerServiceImpl} per user id.
103     * <p>
104     * It has to be mapped by user id because the same current user could have simultaneous sessions
105     * associated to different user profiles (for example, in a multi-window environment or when
106     * device has work profiles).
107     */
108    @GuardedBy("mLock")
109    private SparseArray<AutofillManagerServiceImpl> mServicesCache = new SparseArray<>();
110
111    /**
112     * Users disabled due to {@link UserManager} restrictions.
113     */
114    @GuardedBy("mLock")
115    private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
116
117    private final LocalLog mRequestsHistory = new LocalLog(20);
118
119    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
120        @Override
121        public void onReceive(Context context, Intent intent) {
122            if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
123                mUi.hideAll(null);
124            }
125        }
126    };
127
128    public AutofillManagerService(Context context) {
129        super(context);
130        mContext = context;
131        mUi = new AutoFillUI(ActivityThread.currentActivityThread().getSystemUiContext());
132
133        final boolean debug = Build.IS_DEBUGGABLE;
134        Slog.i(TAG, "Setting debug to " + debug);
135        setDebugLocked(debug);
136
137        final IntentFilter filter = new IntentFilter();
138        filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
139        mContext.registerReceiver(mBroadcastReceiver, filter, null, FgThread.getHandler());
140
141        // Hookup with UserManager to disable service when necessary.
142        final UserManager um = context.getSystemService(UserManager.class);
143        final UserManagerInternal umi = LocalServices.getService(UserManagerInternal.class);
144        final List<UserInfo> users = um.getUsers();
145        for (int i = 0; i < users.size(); i++) {
146            final int userId = users.get(i).id;
147            final boolean disabled = umi.getUserRestriction(userId, UserManager.DISALLOW_AUTOFILL);
148            if (disabled) {
149                if (disabled) {
150                    Slog.i(TAG, "Disabling Autofill for user " + userId);
151                }
152                mDisabledUsers.put(userId, disabled);
153            }
154        }
155        umi.addUserRestrictionsListener((userId, newRestrictions, prevRestrictions) -> {
156            final boolean disabledNow =
157                    newRestrictions.getBoolean(UserManager.DISALLOW_AUTOFILL, false);
158            synchronized (mLock) {
159                final boolean disabledBefore = mDisabledUsers.get(userId);
160                if (disabledBefore == disabledNow) {
161                    // Nothing changed, do nothing.
162                    if (sDebug) {
163                        Slog.d(TAG, "Autofill restriction did not change for user " + userId + ": "
164                                + bundleToString(newRestrictions));
165                        return;
166                    }
167                }
168                Slog.i(TAG, "Updating Autofill for user " + userId + ": disabled=" + disabledNow);
169                mDisabledUsers.put(userId, disabledNow);
170                updateCachedServiceLocked(userId, disabledNow);
171            }
172        });
173        startTrackingPackageChanges();
174    }
175
176    private void startTrackingPackageChanges() {
177        PackageMonitor monitor = new PackageMonitor() {
178            @Override
179            public void onSomePackagesChanged() {
180                synchronized (mLock) {
181                    updateCachedServiceLocked(getChangingUserId());
182                }
183            }
184
185            @Override
186            public void onPackageUpdateFinished(String packageName, int uid) {
187                synchronized (mLock) {
188                    final String activePackageName = getActiveAutofillServicePackageName();
189                    if (packageName.equals(activePackageName)) {
190                        removeCachedServiceLocked(getChangingUserId());
191                    }
192                }
193            }
194
195            @Override
196            public void onPackageRemoved(String packageName, int uid) {
197                synchronized (mLock) {
198                    final int userId = getChangingUserId();
199                    final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId);
200                    if (userState != null) {
201                        final ComponentName componentName = userState.getServiceComponentName();
202                        if (componentName != null) {
203                            if (packageName.equals(componentName.getPackageName())) {
204                                handleActiveAutofillServiceRemoved(userId);
205                            }
206                        }
207                    }
208                }
209            }
210
211            @Override
212            public boolean onHandleForceStop(Intent intent, String[] packages,
213                    int uid, boolean doit) {
214                synchronized (mLock) {
215                    final String activePackageName = getActiveAutofillServicePackageName();
216                    for (String pkg : packages) {
217                        if (pkg.equals(activePackageName)) {
218                            if (!doit) {
219                                return true;
220                            }
221                            removeCachedServiceLocked(getChangingUserId());
222                        }
223                    }
224                }
225                return false;
226            }
227
228            private void handleActiveAutofillServiceRemoved(int userId) {
229                removeCachedServiceLocked(userId);
230                Settings.Secure.putStringForUser(mContext.getContentResolver(),
231                        Settings.Secure.AUTOFILL_SERVICE, null, userId);
232            }
233
234            private String getActiveAutofillServicePackageName() {
235                final int userId = getChangingUserId();
236                final AutofillManagerServiceImpl userState = peekServiceForUserLocked(userId);
237                if (userState == null) {
238                    return null;
239                }
240                final ComponentName serviceComponent = userState.getServiceComponentName();
241                if (serviceComponent == null) {
242                    return null;
243                }
244                return serviceComponent.getPackageName();
245            }
246        };
247
248        // package changes
249        monitor.register(mContext, null,  UserHandle.ALL, true);
250    }
251
252    @Override
253    public void onStart() {
254        publishBinderService(AUTOFILL_MANAGER_SERVICE, new AutoFillManagerServiceStub());
255        publishLocalService(AutofillManagerInternal.class, new LocalService());
256    }
257
258    @Override
259    public void onBootPhase(int phase) {
260        if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
261            new SettingsObserver(BackgroundThread.getHandler());
262        }
263    }
264
265    @Override
266    public void onUnlockUser(int userId) {
267        synchronized (mLock) {
268            updateCachedServiceLocked(userId);
269        }
270    }
271
272    @Override
273    public void onCleanupUser(int userId) {
274        synchronized (mLock) {
275            removeCachedServiceLocked(userId);
276        }
277    }
278
279    /**
280     * Gets the service instance for an user.
281     *
282     * @return service instance.
283     */
284    @NonNull
285    AutofillManagerServiceImpl getServiceForUserLocked(int userId) {
286        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
287                Binder.getCallingUid(), userId, false, false, null, null);
288        AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
289        if (service == null) {
290            service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
291                    resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
292            mServicesCache.put(userId, service);
293        }
294        return service;
295    }
296
297    /**
298     * Peeks the service instance for a user.
299     *
300     * @return service instance or {@code null} if not already present
301     */
302    @Nullable
303    AutofillManagerServiceImpl peekServiceForUserLocked(int userId) {
304        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
305                Binder.getCallingUid(), userId, false, false, null, null);
306        return mServicesCache.get(resolvedUserId);
307    }
308
309    // Called by Shell command.
310    void destroySessions(int userId, IResultReceiver receiver) {
311        Slog.i(TAG, "destroySessions() for userId " + userId);
312        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
313
314        synchronized (mLock) {
315            if (userId != UserHandle.USER_ALL) {
316                AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
317                if (service != null) {
318                    service.destroySessionsLocked();
319                }
320            } else {
321                final int size = mServicesCache.size();
322                for (int i = 0; i < size; i++) {
323                    mServicesCache.valueAt(i).destroySessionsLocked();
324                }
325            }
326        }
327
328        try {
329            receiver.send(0, new Bundle());
330        } catch (RemoteException e) {
331            // Just ignore it...
332        }
333    }
334
335    // Called by Shell command.
336    void listSessions(int userId, IResultReceiver receiver) {
337        Slog.i(TAG, "listSessions() for userId " + userId);
338        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
339
340        final Bundle resultData = new Bundle();
341        final ArrayList<String> sessions = new ArrayList<>();
342
343        synchronized (mLock) {
344            if (userId != UserHandle.USER_ALL) {
345                AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
346                if (service != null) {
347                    service.listSessionsLocked(sessions);
348                }
349            } else {
350                final int size = mServicesCache.size();
351                for (int i = 0; i < size; i++) {
352                    mServicesCache.valueAt(i).listSessionsLocked(sessions);
353                }
354            }
355        }
356
357        resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
358        try {
359            receiver.send(0, resultData);
360        } catch (RemoteException e) {
361            // Just ignore it...
362        }
363    }
364
365    // Called by Shell command.
366    void reset() {
367        Slog.i(TAG, "reset()");
368        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
369
370        synchronized (mLock) {
371            final int size = mServicesCache.size();
372            for (int i = 0; i < size; i++) {
373                mServicesCache.valueAt(i).destroyLocked();
374            }
375            mServicesCache.clear();
376        }
377    }
378
379    // Called by Shell command.
380    void setLogLevel(int level) {
381        Slog.i(TAG, "setLogLevel(): " + level);
382        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
383
384        boolean debug = false;
385        boolean verbose = false;
386        if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
387            debug = verbose = true;
388        } else if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) {
389            debug = true;
390        }
391        synchronized (mLock) {
392            setDebugLocked(debug);
393            setVerboseLocked(verbose);
394        }
395    }
396
397    // Called by Shell command.
398    int getLogLevel() {
399        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
400
401        synchronized (mLock) {
402            if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
403            if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
404            return 0;
405        }
406    }
407
408    // Called by Shell command.
409    public int getMaxPartitions() {
410        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
411
412        synchronized (mLock) {
413            return sPartitionMaxCount;
414        }
415    }
416
417    // Called by Shell command.
418    public void setMaxPartitions(int max) {
419        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
420        Slog.i(TAG, "setMaxPartitions(): " + max);
421        synchronized (mLock) {
422            sPartitionMaxCount = max;
423        }
424    }
425
426    private void setDebugLocked(boolean debug) {
427        com.android.server.autofill.Helper.sDebug = debug;
428        android.view.autofill.Helper.sDebug = debug;
429    }
430
431
432    private void setVerboseLocked(boolean verbose) {
433        com.android.server.autofill.Helper.sVerbose = verbose;
434        android.view.autofill.Helper.sVerbose = verbose;
435    }
436
437    /**
438     * Removes a cached service for a given user.
439     */
440    private void removeCachedServiceLocked(int userId) {
441        final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
442        if (service != null) {
443            mServicesCache.delete(userId);
444            service.destroyLocked();
445        }
446    }
447
448    /**
449     * Updates a cached service for a given user.
450     */
451    private void updateCachedServiceLocked(int userId) {
452        updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
453    }
454
455    /**
456     * Updates a cached service for a given user.
457     */
458    private void updateCachedServiceLocked(int userId, boolean disabled) {
459        AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
460        if (service != null) {
461            service.destroySessionsLocked();
462            service.updateLocked(disabled);
463            if (!service.isEnabled()) {
464                removeCachedServiceLocked(userId);
465            }
466        }
467    }
468
469    private final class LocalService extends AutofillManagerInternal {
470
471        @Override
472        public void onBackKeyPressed() {
473            if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
474            mUi.hideAll(null);
475        }
476    }
477
478    final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
479        @Override
480        public int addClient(IAutoFillManagerClient client, int userId) {
481            synchronized (mLock) {
482                int flags = 0;
483                if (getServiceForUserLocked(userId).addClientLocked(client)) {
484                    flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED;
485                }
486                if (sDebug) {
487                    flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
488                }
489                if (sVerbose) {
490                    flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
491                }
492                return flags;
493            }
494        }
495
496        @Override
497        public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
498                int userId) {
499            synchronized (mLock) {
500                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
501                service.setAuthenticationResultLocked(data, sessionId, authenticationId,
502                        getCallingUid());
503            }
504        }
505
506        @Override
507        public void setHasCallback(int sessionId, int userId, boolean hasIt) {
508            synchronized (mLock) {
509                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
510                service.setHasCallback(sessionId, getCallingUid(), hasIt);
511            }
512        }
513
514        @Override
515        public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
516                Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
517                String packageName) {
518
519            activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
520            appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
521            autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
522            packageName = Preconditions.checkNotNull(packageName, "packageName");
523
524            Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
525
526            try {
527                mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
528            } catch (PackageManager.NameNotFoundException e) {
529                throw new IllegalArgumentException(packageName + " is not a valid package", e);
530            }
531
532            synchronized (mLock) {
533                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
534                return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
535                        autofillId, bounds, value, hasCallback, flags, packageName);
536            }
537        }
538
539        @Override
540        public FillEventHistory getFillEventHistory() throws RemoteException {
541            UserHandle user = getCallingUserHandle();
542            int uid = getCallingUid();
543
544            synchronized (mLock) {
545                AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier());
546                if (service != null) {
547                    return service.getFillEventHistory(uid);
548                }
549            }
550
551            return null;
552        }
553
554        @Override
555        public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback)
556                throws RemoteException {
557            activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
558            appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
559
560            synchronized (mLock) {
561                final AutofillManagerServiceImpl service = mServicesCache.get(
562                        UserHandle.getCallingUserId());
563                if (service != null) {
564                    return service.restoreSession(sessionId, getCallingUid(), activityToken,
565                            appCallback);
566                }
567            }
568
569            return false;
570        }
571
572        @Override
573        public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
574                AutofillValue value, int action, int flags, int userId) {
575            synchronized (mLock) {
576                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
577                if (service != null) {
578                    service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
579                            value, action, flags);
580                }
581            }
582        }
583
584        @Override
585        public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
586                AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
587                boolean hasCallback, int flags, String packageName, int sessionId, int action) {
588            boolean restart = false;
589            synchronized (mLock) {
590                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
591                if (service != null) {
592                    restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId,
593                            bounds, value, action, flags);
594                }
595            }
596            if (restart) {
597                return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
598                        hasCallback, flags, packageName);
599            }
600
601            // Nothing changed...
602            return sessionId;
603        }
604
605        @Override
606        public void finishSession(int sessionId, int userId) {
607            synchronized (mLock) {
608                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
609                if (service != null) {
610                    service.finishSessionLocked(sessionId, getCallingUid());
611                }
612            }
613        }
614
615        @Override
616        public void cancelSession(int sessionId, int userId) {
617            synchronized (mLock) {
618                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
619                if (service != null) {
620                    service.cancelSessionLocked(sessionId, getCallingUid());
621                }
622            }
623        }
624
625        @Override
626        public void disableOwnedAutofillServices(int userId) {
627            synchronized (mLock) {
628                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
629                if (service != null) {
630                    service.disableOwnedAutofillServicesLocked(Binder.getCallingUid());
631                }
632            }
633        }
634
635        @Override
636        public boolean isServiceSupported(int userId) {
637            synchronized (mLock) {
638                return !mDisabledUsers.get(userId);
639            }
640        }
641
642        @Override
643        public boolean isServiceEnabled(int userId, String packageName) {
644            synchronized (mLock) {
645                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
646                if (service == null) return false;
647                return Objects.equals(packageName, service.getPackageName());
648            }
649        }
650
651        @Override
652        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
653            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
654
655            boolean showHistory = true;
656            boolean uiOnly = false;
657            if (args != null) {
658                for (String arg : args) {
659                    switch(arg) {
660                        case "--no-history":
661                            showHistory = false;
662                            break;
663                        case "--ui-only":
664                            uiOnly = true;
665                            break;
666                        case "--help":
667                            pw.println("Usage: dumpsys autofill [--ui-only|--no-history]");
668                            return;
669                        default:
670                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
671                    }
672                }
673            }
674
675            if (uiOnly) {
676                mUi.dump(pw);
677                return;
678            }
679
680            boolean oldDebug = sDebug;
681            try {
682                synchronized (mLock) {
683                    oldDebug = sDebug;
684                    setDebugLocked(true);
685                    pw.print("Debug mode: "); pw.println(oldDebug);
686                    pw.print("Verbose mode: "); pw.println(sVerbose);
687                    pw.print("Disabled users: "); pw.println(mDisabledUsers);
688                    pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
689                    final int size = mServicesCache.size();
690                    pw.print("Cached services: ");
691                    if (size == 0) {
692                        pw.println("none");
693                    } else {
694                        pw.println(size);
695                        for (int i = 0; i < size; i++) {
696                            pw.print("\nService at index "); pw.println(i);
697                            final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
698                            impl.dumpLocked("  ", pw);
699                        }
700                    }
701                    mUi.dump(pw);
702                }
703                if (showHistory) {
704                    pw.println("Requests history:");
705                    mRequestsHistory.reverseDump(fd, pw, args);
706                }
707            } finally {
708                setDebugLocked(oldDebug);
709            }
710        }
711
712        @Override
713        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
714                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
715            (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec(
716                    this, in, out, err, args, callback, resultReceiver);
717        }
718    }
719
720    private final class SettingsObserver extends ContentObserver {
721        SettingsObserver(Handler handler) {
722            super(handler);
723            ContentResolver resolver = mContext.getContentResolver();
724            resolver.registerContentObserver(Settings.Secure.getUriFor(
725                    Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL);
726            resolver.registerContentObserver(Settings.Secure.getUriFor(
727                    Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
728        }
729
730        @Override
731        public void onChange(boolean selfChange, Uri uri, int userId) {
732            if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId);
733            synchronized (mLock) {
734                updateCachedServiceLocked(userId);
735            }
736        }
737    }
738}
739