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