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