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