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 onSwitchUser(int userHandle) {
274        if (sDebug) Slog.d(TAG, "Hiding UI when user switched");
275        mUi.hideAll(null);
276    }
277
278    @Override
279    public void onCleanupUser(int userId) {
280        synchronized (mLock) {
281            removeCachedServiceLocked(userId);
282        }
283    }
284
285    /**
286     * Gets the service instance for an user.
287     *
288     * @return service instance.
289     */
290    @NonNull
291    AutofillManagerServiceImpl getServiceForUserLocked(int userId) {
292        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
293                Binder.getCallingUid(), userId, false, false, null, null);
294        AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
295        if (service == null) {
296            service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
297                    resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
298            mServicesCache.put(userId, service);
299        }
300        return service;
301    }
302
303    /**
304     * Peeks the service instance for a user.
305     *
306     * @return service instance or {@code null} if not already present
307     */
308    @Nullable
309    AutofillManagerServiceImpl peekServiceForUserLocked(int userId) {
310        final int resolvedUserId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
311                Binder.getCallingUid(), userId, false, false, null, null);
312        return mServicesCache.get(resolvedUserId);
313    }
314
315    // Called by Shell command.
316    void destroySessions(int userId, IResultReceiver receiver) {
317        Slog.i(TAG, "destroySessions() for userId " + userId);
318        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
319
320        synchronized (mLock) {
321            if (userId != UserHandle.USER_ALL) {
322                AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
323                if (service != null) {
324                    service.destroySessionsLocked();
325                }
326            } else {
327                final int size = mServicesCache.size();
328                for (int i = 0; i < size; i++) {
329                    mServicesCache.valueAt(i).destroySessionsLocked();
330                }
331            }
332        }
333
334        try {
335            receiver.send(0, new Bundle());
336        } catch (RemoteException e) {
337            // Just ignore it...
338        }
339    }
340
341    // Called by Shell command.
342    void listSessions(int userId, IResultReceiver receiver) {
343        Slog.i(TAG, "listSessions() for userId " + userId);
344        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
345
346        final Bundle resultData = new Bundle();
347        final ArrayList<String> sessions = new ArrayList<>();
348
349        synchronized (mLock) {
350            if (userId != UserHandle.USER_ALL) {
351                AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
352                if (service != null) {
353                    service.listSessionsLocked(sessions);
354                }
355            } else {
356                final int size = mServicesCache.size();
357                for (int i = 0; i < size; i++) {
358                    mServicesCache.valueAt(i).listSessionsLocked(sessions);
359                }
360            }
361        }
362
363        resultData.putStringArrayList(RECEIVER_BUNDLE_EXTRA_SESSIONS, sessions);
364        try {
365            receiver.send(0, resultData);
366        } catch (RemoteException e) {
367            // Just ignore it...
368        }
369    }
370
371    // Called by Shell command.
372    void reset() {
373        Slog.i(TAG, "reset()");
374        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
375
376        synchronized (mLock) {
377            final int size = mServicesCache.size();
378            for (int i = 0; i < size; i++) {
379                mServicesCache.valueAt(i).destroyLocked();
380            }
381            mServicesCache.clear();
382        }
383    }
384
385    // Called by Shell command.
386    void setLogLevel(int level) {
387        Slog.i(TAG, "setLogLevel(): " + level);
388        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
389
390        boolean debug = false;
391        boolean verbose = false;
392        if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
393            debug = verbose = true;
394        } else if (level == AutofillManager.FLAG_ADD_CLIENT_DEBUG) {
395            debug = true;
396        }
397        synchronized (mLock) {
398            setDebugLocked(debug);
399            setVerboseLocked(verbose);
400        }
401    }
402
403    // Called by Shell command.
404    int getLogLevel() {
405        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
406
407        synchronized (mLock) {
408            if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
409            if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
410            return 0;
411        }
412    }
413
414    // Called by Shell command.
415    public int getMaxPartitions() {
416        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
417
418        synchronized (mLock) {
419            return sPartitionMaxCount;
420        }
421    }
422
423    // Called by Shell command.
424    public void setMaxPartitions(int max) {
425        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
426        Slog.i(TAG, "setMaxPartitions(): " + max);
427        synchronized (mLock) {
428            sPartitionMaxCount = max;
429        }
430    }
431
432    private void setDebugLocked(boolean debug) {
433        com.android.server.autofill.Helper.sDebug = debug;
434        android.view.autofill.Helper.sDebug = debug;
435    }
436
437
438    private void setVerboseLocked(boolean verbose) {
439        com.android.server.autofill.Helper.sVerbose = verbose;
440        android.view.autofill.Helper.sVerbose = verbose;
441    }
442
443    /**
444     * Removes a cached service for a given user.
445     */
446    private void removeCachedServiceLocked(int userId) {
447        final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
448        if (service != null) {
449            mServicesCache.delete(userId);
450            service.destroyLocked();
451        }
452    }
453
454    /**
455     * Updates a cached service for a given user.
456     */
457    private void updateCachedServiceLocked(int userId) {
458        updateCachedServiceLocked(userId, mDisabledUsers.get(userId));
459    }
460
461    /**
462     * Updates a cached service for a given user.
463     */
464    private void updateCachedServiceLocked(int userId, boolean disabled) {
465        AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
466        if (service != null) {
467            service.updateLocked(disabled);
468            if (!service.isEnabled()) {
469                removeCachedServiceLocked(userId);
470            }
471        }
472    }
473
474    private final class LocalService extends AutofillManagerInternal {
475
476        @Override
477        public void onBackKeyPressed() {
478            if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
479            mUi.hideAll(null);
480        }
481    }
482
483    final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
484        @Override
485        public int addClient(IAutoFillManagerClient client, int userId) {
486            synchronized (mLock) {
487                int flags = 0;
488                if (getServiceForUserLocked(userId).addClientLocked(client)) {
489                    flags |= AutofillManager.FLAG_ADD_CLIENT_ENABLED;
490                }
491                if (sDebug) {
492                    flags |= AutofillManager.FLAG_ADD_CLIENT_DEBUG;
493                }
494                if (sVerbose) {
495                    flags |= AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
496                }
497                return flags;
498            }
499        }
500
501        @Override
502        public void setAuthenticationResult(Bundle data, int sessionId, int authenticationId,
503                int userId) {
504            synchronized (mLock) {
505                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
506                service.setAuthenticationResultLocked(data, sessionId, authenticationId,
507                        getCallingUid());
508            }
509        }
510
511        @Override
512        public void setHasCallback(int sessionId, int userId, boolean hasIt) {
513            synchronized (mLock) {
514                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
515                service.setHasCallback(sessionId, getCallingUid(), hasIt);
516            }
517        }
518
519        @Override
520        public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
521                Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
522                String packageName) {
523
524            activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
525            appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
526            autofillId = Preconditions.checkNotNull(autofillId, "autoFillId");
527            packageName = Preconditions.checkNotNull(packageName, "packageName");
528
529            Preconditions.checkArgument(userId == UserHandle.getUserId(getCallingUid()), "userId");
530
531            try {
532                mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, userId);
533            } catch (PackageManager.NameNotFoundException e) {
534                throw new IllegalArgumentException(packageName + " is not a valid package", e);
535            }
536
537            synchronized (mLock) {
538                final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
539                return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
540                        autofillId, bounds, value, hasCallback, flags, packageName);
541            }
542        }
543
544        @Override
545        public FillEventHistory getFillEventHistory() throws RemoteException {
546            UserHandle user = getCallingUserHandle();
547            int uid = getCallingUid();
548
549            synchronized (mLock) {
550                AutofillManagerServiceImpl service = peekServiceForUserLocked(user.getIdentifier());
551                if (service != null) {
552                    return service.getFillEventHistory(uid);
553                }
554            }
555
556            return null;
557        }
558
559        @Override
560        public boolean restoreSession(int sessionId, IBinder activityToken, IBinder appCallback)
561                throws RemoteException {
562            activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
563            appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
564
565            synchronized (mLock) {
566                final AutofillManagerServiceImpl service = mServicesCache.get(
567                        UserHandle.getCallingUserId());
568                if (service != null) {
569                    return service.restoreSession(sessionId, getCallingUid(), activityToken,
570                            appCallback);
571                }
572            }
573
574            return false;
575        }
576
577        @Override
578        public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
579                AutofillValue value, int action, int flags, int userId) {
580            synchronized (mLock) {
581                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
582                if (service != null) {
583                    service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
584                            value, action, flags);
585                }
586            }
587        }
588
589        @Override
590        public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
591                AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
592                boolean hasCallback, int flags, String packageName, int sessionId, int action) {
593            boolean restart = false;
594            synchronized (mLock) {
595                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
596                if (service != null) {
597                    restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId,
598                            bounds, value, action, flags);
599                }
600            }
601            if (restart) {
602                return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
603                        hasCallback, flags, packageName);
604            }
605
606            // Nothing changed...
607            return sessionId;
608        }
609
610        @Override
611        public void finishSession(int sessionId, int userId) {
612            synchronized (mLock) {
613                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
614                if (service != null) {
615                    service.finishSessionLocked(sessionId, getCallingUid());
616                }
617            }
618        }
619
620        @Override
621        public void cancelSession(int sessionId, int userId) {
622            synchronized (mLock) {
623                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
624                if (service != null) {
625                    service.cancelSessionLocked(sessionId, getCallingUid());
626                }
627            }
628        }
629
630        @Override
631        public void disableOwnedAutofillServices(int userId) {
632            synchronized (mLock) {
633                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
634                if (service != null) {
635                    service.disableOwnedAutofillServicesLocked(Binder.getCallingUid());
636                }
637            }
638        }
639
640        @Override
641        public boolean isServiceSupported(int userId) {
642            synchronized (mLock) {
643                return !mDisabledUsers.get(userId);
644            }
645        }
646
647        @Override
648        public boolean isServiceEnabled(int userId, String packageName) {
649            synchronized (mLock) {
650                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
651                if (service == null) return false;
652                return Objects.equals(packageName, service.getPackageName());
653            }
654        }
655
656        @Override
657        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
658            if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
659
660            boolean showHistory = true;
661            boolean uiOnly = false;
662            if (args != null) {
663                for (String arg : args) {
664                    switch(arg) {
665                        case "--no-history":
666                            showHistory = false;
667                            break;
668                        case "--ui-only":
669                            uiOnly = true;
670                            break;
671                        case "--help":
672                            pw.println("Usage: dumpsys autofill [--ui-only|--no-history]");
673                            return;
674                        default:
675                            Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
676                    }
677                }
678            }
679
680            if (uiOnly) {
681                mUi.dump(pw);
682                return;
683            }
684
685            boolean oldDebug = sDebug;
686            try {
687                synchronized (mLock) {
688                    oldDebug = sDebug;
689                    setDebugLocked(true);
690                    pw.print("Debug mode: "); pw.println(oldDebug);
691                    pw.print("Verbose mode: "); pw.println(sVerbose);
692                    pw.print("Disabled users: "); pw.println(mDisabledUsers);
693                    pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount);
694                    final int size = mServicesCache.size();
695                    pw.print("Cached services: ");
696                    if (size == 0) {
697                        pw.println("none");
698                    } else {
699                        pw.println(size);
700                        for (int i = 0; i < size; i++) {
701                            pw.print("\nService at index "); pw.println(i);
702                            final AutofillManagerServiceImpl impl = mServicesCache.valueAt(i);
703                            impl.dumpLocked("  ", pw);
704                        }
705                    }
706                    mUi.dump(pw);
707                }
708                if (showHistory) {
709                    pw.println("Requests history:");
710                    mRequestsHistory.reverseDump(fd, pw, args);
711                }
712            } finally {
713                setDebugLocked(oldDebug);
714            }
715        }
716
717        @Override
718        public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
719                String[] args, ShellCallback callback, ResultReceiver resultReceiver) {
720            (new AutofillManagerServiceShellCommand(AutofillManagerService.this)).exec(
721                    this, in, out, err, args, callback, resultReceiver);
722        }
723    }
724
725    private final class SettingsObserver extends ContentObserver {
726        SettingsObserver(Handler handler) {
727            super(handler);
728            ContentResolver resolver = mContext.getContentResolver();
729            resolver.registerContentObserver(Settings.Secure.getUriFor(
730                    Settings.Secure.AUTOFILL_SERVICE), false, this, UserHandle.USER_ALL);
731            resolver.registerContentObserver(Settings.Secure.getUriFor(
732                    Settings.Secure.USER_SETUP_COMPLETE), false, this, UserHandle.USER_ALL);
733        }
734
735        @Override
736        public void onChange(boolean selfChange, Uri uri, int userId) {
737            if (sVerbose) Slog.v(TAG, "onChange(): uri=" + uri + ", userId=" + userId);
738            synchronized (mLock) {
739                updateCachedServiceLocked(userId);
740            }
741        }
742    }
743}
744