2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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
17 package com.android.server.trust;
19 import com.android.internal.content.PackageMonitor;
20 import com.android.internal.widget.LockPatternUtils;
21 import com.android.server.SystemService;
23 import org.xmlpull.v1.XmlPullParser;
24 import org.xmlpull.v1.XmlPullParserException;
26 import android.Manifest;
27 import android.app.ActivityManagerNative;
28 import android.app.admin.DevicePolicyManager;
29 import android.app.trust.ITrustListener;
30 import android.app.trust.ITrustManager;
31 import android.content.BroadcastReceiver;
32 import android.content.ComponentName;
33 import android.content.Context;
34 import android.content.Intent;
35 import android.content.IntentFilter;
36 import android.content.pm.ApplicationInfo;
37 import android.content.pm.PackageManager;
38 import android.content.pm.ResolveInfo;
39 import android.content.pm.UserInfo;
40 import android.content.res.Resources;
41 import android.content.res.TypedArray;
42 import android.content.res.XmlResourceParser;
43 import android.graphics.drawable.Drawable;
44 import android.os.DeadObjectException;
45 import android.os.Handler;
46 import android.os.IBinder;
47 import android.os.Message;
48 import android.os.RemoteException;
49 import android.os.SystemClock;
50 import android.os.UserHandle;
51 import android.os.UserManager;
52 import android.provider.Settings;
53 import android.service.trust.TrustAgentService;
54 import android.util.ArraySet;
55 import android.util.AttributeSet;
56 import android.util.Log;
57 import android.util.Slog;
58 import android.util.SparseBooleanArray;
59 import android.util.Xml;
61 import java.io.FileDescriptor;
62 import java.io.IOException;
63 import java.io.PrintWriter;
64 import java.util.ArrayList;
65 import java.util.List;
68 * Manages trust agents and trust listeners.
70 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s
71 * of each user and notifies them about events that are relevant to them.
72 * It start and stops them based on the value of
73 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}.
75 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the
76 * trust state changes for any user.
78 * Trust state and the setting of enabled agents is kept per user and each user has its own
79 * instance of a {@link android.service.trust.TrustAgentService}.
81 public class TrustManagerService extends SystemService {
83 private static final boolean DEBUG = false;
84 private static final String TAG = "TrustManagerService";
86 private static final Intent TRUST_AGENT_INTENT =
87 new Intent(TrustAgentService.SERVICE_INTERFACE);
88 private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT;
90 private static final int MSG_REGISTER_LISTENER = 1;
91 private static final int MSG_UNREGISTER_LISTENER = 2;
92 private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
93 private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
94 private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
96 private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
97 private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
98 private final Receiver mReceiver = new Receiver();
99 private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
100 /* package */ final TrustArchive mArchive = new TrustArchive();
101 private final Context mContext;
102 private final LockPatternUtils mLockPatternUtils;
104 private UserManager mUserManager;
106 public TrustManagerService(Context context) {
109 mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
110 mLockPatternUtils = new LockPatternUtils(context);
114 public void onStart() {
115 publishBinderService(Context.TRUST_SERVICE, mService);
119 public void onBootPhase(int phase) {
120 if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
121 mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
122 mReceiver.register(mContext);
123 refreshAgentList(UserHandle.USER_ALL);
124 } else if (phase == SystemService.PHASE_BOOT_COMPLETED && !isSafeMode()) {
125 maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER);
131 private static final class AgentInfo {
134 ComponentName component; // service that implements ITrustAgent
135 ComponentName settings; // setting to launch to modify agent.
136 TrustAgentWrapper agent;
140 public boolean equals(Object other) {
141 if (!(other instanceof AgentInfo)) {
144 AgentInfo o = (AgentInfo) other;
145 return component.equals(o.component) && userId == o.userId;
149 public int hashCode() {
150 return component.hashCode() * 31 + userId;
154 private void updateTrustAll() {
155 List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
156 for (UserInfo userInfo : userInfos) {
157 updateTrust(userInfo.id, false);
161 public void updateTrust(int userId, boolean initiatedByUser) {
162 dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId);
163 dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser);
166 void refreshAgentList(int userId) {
167 if (DEBUG) Slog.d(TAG, "refreshAgentList()");
168 if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) {
169 Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle,"
170 + " must be USER_ALL or a specific user.", new Throwable("here"));
171 userId = UserHandle.USER_ALL;
173 PackageManager pm = mContext.getPackageManager();
175 List<UserInfo> userInfos;
176 if (userId == UserHandle.USER_ALL) {
177 userInfos = mUserManager.getUsers(true /* excludeDying */);
179 userInfos = new ArrayList<>();
180 userInfos.add(mUserManager.getUserInfo(userId));
182 LockPatternUtils lockPatternUtils = mLockPatternUtils;
184 ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
185 obsoleteAgents.addAll(mActiveAgents);
187 for (UserInfo userInfo : userInfos) {
188 if (!userInfo.supportsSwitchTo()) continue;
189 if (lockPatternUtils.getKeyguardStoredPasswordQuality(userInfo.id)
190 == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) continue;
191 if (!mUserHasAuthenticatedSinceBoot.get(userInfo.id)) continue;
192 DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
193 int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
194 final boolean disableTrustAgents =
195 (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
197 List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
198 if (enabledAgents == null) {
201 List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userInfo.id);
202 for (ResolveInfo resolveInfo : resolveInfos) {
203 ComponentName name = getComponentName(resolveInfo);
205 if (!enabledAgents.contains(name)) continue;
206 if (disableTrustAgents) {
207 List<String> features =
208 dpm.getTrustAgentFeaturesEnabled(null /* admin */, name);
209 // Disable agent if no features are enabled.
210 if (features == null || features.isEmpty()) continue;
213 AgentInfo agentInfo = new AgentInfo();
214 agentInfo.component = name;
215 agentInfo.userId = userInfo.id;
216 if (!mActiveAgents.contains(agentInfo)) {
217 agentInfo.label = resolveInfo.loadLabel(pm);
218 agentInfo.icon = resolveInfo.loadIcon(pm);
219 agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
220 agentInfo.agent = new TrustAgentWrapper(mContext, this,
221 new Intent().setComponent(name), userInfo.getUserHandle());
222 mActiveAgents.add(agentInfo);
224 obsoleteAgents.remove(agentInfo);
229 boolean trustMayHaveChanged = false;
230 for (int i = 0; i < obsoleteAgents.size(); i++) {
231 AgentInfo info = obsoleteAgents.valueAt(i);
232 if (userId == UserHandle.USER_ALL || userId == info.userId) {
233 if (info.agent.isManagingTrust()) {
234 trustMayHaveChanged = true;
237 mActiveAgents.remove(info);
241 if (trustMayHaveChanged) {
246 void updateDevicePolicyFeatures() {
247 for (int i = 0; i < mActiveAgents.size(); i++) {
248 AgentInfo info = mActiveAgents.valueAt(i);
249 if (info.agent.isConnected()) {
250 info.agent.updateDevicePolicyFeatures();
255 private void removeAgentsOfPackage(String packageName) {
256 boolean trustMayHaveChanged = false;
257 for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
258 AgentInfo info = mActiveAgents.valueAt(i);
259 if (packageName.equals(info.component.getPackageName())) {
260 Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
261 if (info.agent.isManagingTrust()) {
262 trustMayHaveChanged = true;
265 mActiveAgents.removeAt(i);
268 if (trustMayHaveChanged) {
273 public void resetAgent(ComponentName name, int userId) {
274 boolean trustMayHaveChanged = false;
275 for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
276 AgentInfo info = mActiveAgents.valueAt(i);
277 if (name.equals(info.component) && userId == info.userId) {
278 Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
279 if (info.agent.isManagingTrust()) {
280 trustMayHaveChanged = true;
283 mActiveAgents.removeAt(i);
286 if (trustMayHaveChanged) {
287 updateTrust(userId, false);
289 refreshAgentList(userId);
292 private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
293 if (resolveInfo == null || resolveInfo.serviceInfo == null
294 || resolveInfo.serviceInfo.metaData == null) return null;
296 XmlResourceParser parser = null;
297 Exception caughtException = null;
299 parser = resolveInfo.serviceInfo.loadXmlMetaData(pm,
300 TrustAgentService.TRUST_AGENT_META_DATA);
301 if (parser == null) {
302 Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data");
305 Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
306 AttributeSet attrs = Xml.asAttributeSet(parser);
308 while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
309 && type != XmlPullParser.START_TAG) {
312 String nodeName = parser.getName();
313 if (!"trust-agent".equals(nodeName)) {
314 Slog.w(TAG, "Meta-data does not start with trust-agent tag");
318 .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
319 cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
321 } catch (PackageManager.NameNotFoundException e) {
323 } catch (IOException e) {
325 } catch (XmlPullParserException e) {
328 if (parser != null) parser.close();
330 if (caughtException != null) {
331 Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
337 if (cn.indexOf('/') < 0) {
338 cn = resolveInfo.serviceInfo.packageName + "/" + cn;
340 return ComponentName.unflattenFromString(cn);
343 private ComponentName getComponentName(ResolveInfo resolveInfo) {
344 if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
345 return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
348 private void maybeEnableFactoryTrustAgents(LockPatternUtils utils, int userId) {
349 if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
350 Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
353 PackageManager pm = mContext.getPackageManager();
354 List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
355 ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
356 for (ResolveInfo resolveInfo : resolveInfos) {
357 ComponentName componentName = getComponentName(resolveInfo);
358 int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
359 if ((applicationInfoFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
360 Log.i(TAG, "Leaving agent " + componentName + " disabled because package "
361 + "is not a system package.");
364 discoveredAgents.add(componentName);
367 List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
368 if (previouslyEnabledAgents != null) {
369 discoveredAgents.addAll(previouslyEnabledAgents);
371 utils.setEnabledTrustAgents(discoveredAgents, userId);
372 Settings.Secure.putIntForUser(mContext.getContentResolver(),
373 Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
376 private List<ResolveInfo> resolveAllowedTrustAgents(PackageManager pm, int userId) {
377 List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
378 0 /* flags */, userId);
379 ArrayList<ResolveInfo> allowedAgents = new ArrayList<>(resolveInfos.size());
380 for (ResolveInfo resolveInfo : resolveInfos) {
381 if (resolveInfo.serviceInfo == null) continue;
382 if (resolveInfo.serviceInfo.applicationInfo == null) continue;
383 String packageName = resolveInfo.serviceInfo.packageName;
384 if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
385 != PackageManager.PERMISSION_GRANTED) {
386 ComponentName name = getComponentName(resolveInfo);
387 Log.w(TAG, "Skipping agent " + name + " because package does not have"
388 + " permission " + PERMISSION_PROVIDE_AGENT + ".");
391 allowedAgents.add(resolveInfo);
393 return allowedAgents;
396 // Agent dispatch and aggregation
398 private boolean aggregateIsTrusted(int userId) {
399 if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
402 for (int i = 0; i < mActiveAgents.size(); i++) {
403 AgentInfo info = mActiveAgents.valueAt(i);
404 if (info.userId == userId) {
405 if (info.agent.isTrusted()) {
413 private boolean aggregateIsTrustManaged(int userId) {
414 if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
417 for (int i = 0; i < mActiveAgents.size(); i++) {
418 AgentInfo info = mActiveAgents.valueAt(i);
419 if (info.userId == userId) {
420 if (info.agent.isManagingTrust()) {
428 private void dispatchUnlockAttempt(boolean successful, int userId) {
429 for (int i = 0; i < mActiveAgents.size(); i++) {
430 AgentInfo info = mActiveAgents.valueAt(i);
431 if (info.userId == userId) {
432 info.agent.onUnlockAttempt(successful);
437 updateUserHasAuthenticated(userId);
441 private void updateUserHasAuthenticated(int userId) {
442 if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
443 mUserHasAuthenticatedSinceBoot.put(userId, true);
444 refreshAgentList(userId);
449 private void requireCredentialEntry(int userId) {
450 if (userId == UserHandle.USER_ALL) {
451 mUserHasAuthenticatedSinceBoot.clear();
452 refreshAgentList(UserHandle.USER_ALL);
454 mUserHasAuthenticatedSinceBoot.put(userId, false);
455 refreshAgentList(userId);
461 private void addListener(ITrustListener listener) {
462 for (int i = 0; i < mTrustListeners.size(); i++) {
463 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
467 mTrustListeners.add(listener);
471 private void removeListener(ITrustListener listener) {
472 for (int i = 0; i < mTrustListeners.size(); i++) {
473 if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
474 mTrustListeners.remove(i);
480 private void dispatchOnTrustChanged(boolean enabled, int userId, boolean initiatedByUser) {
481 if (!enabled) initiatedByUser = false;
482 for (int i = 0; i < mTrustListeners.size(); i++) {
484 mTrustListeners.get(i).onTrustChanged(enabled, userId, initiatedByUser);
485 } catch (DeadObjectException e) {
486 Slog.d(TAG, "Removing dead TrustListener.");
487 mTrustListeners.remove(i);
489 } catch (RemoteException e) {
490 Slog.e(TAG, "Exception while notifying TrustListener.", e);
495 private void dispatchOnTrustManagedChanged(boolean managed, int userId) {
496 for (int i = 0; i < mTrustListeners.size(); i++) {
498 mTrustListeners.get(i).onTrustManagedChanged(managed, userId);
499 } catch (DeadObjectException e) {
500 Slog.d(TAG, "Removing dead TrustListener.");
501 mTrustListeners.remove(i);
503 } catch (RemoteException e) {
504 Slog.e(TAG, "Exception while notifying TrustListener.", e);
511 private final IBinder mService = new ITrustManager.Stub() {
513 public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException {
514 enforceReportPermission();
515 mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId)
520 public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
521 enforceReportPermission();
522 // coalesce refresh messages.
523 mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED);
524 mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED);
528 public void reportRequireCredentialEntry(int userId) throws RemoteException {
529 enforceReportPermission();
530 if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
531 mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget();
533 throw new IllegalArgumentException(
534 "userId must be an explicit user id or USER_ALL");
539 public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
540 enforceListenerPermission();
541 mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
545 public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException {
546 enforceListenerPermission();
547 mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
550 private void enforceReportPermission() {
551 mContext.enforceCallingOrSelfPermission(
552 Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
555 private void enforceListenerPermission() {
556 mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
557 "register trust listener");
561 protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) {
562 mContext.enforceCallingPermission(Manifest.permission.DUMP,
563 "dumping TrustManagerService");
564 final UserInfo currentUser;
565 final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
567 currentUser = ActivityManagerNative.getDefault().getCurrentUser();
568 } catch (RemoteException e) {
569 throw new RuntimeException(e);
571 mHandler.runWithScissors(new Runnable() {
574 fout.println("Trust manager state:");
575 for (UserInfo user : userInfos) {
576 dumpUser(fout, user, user.id == currentUser.id);
582 private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) {
583 fout.printf(" User \"%s\" (id=%d, flags=%#x)",
584 user.name, user.id, user.flags);
586 fout.print(" (current)");
588 fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
589 fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
591 fout.println(" Enabled agents:");
592 boolean duplicateSimpleNames = false;
593 ArraySet<String> simpleNames = new ArraySet<String>();
594 for (AgentInfo info : mActiveAgents) {
595 if (info.userId != user.id) { continue; }
596 boolean trusted = info.agent.isTrusted();
597 fout.print(" "); fout.println(info.component.flattenToShortString());
598 fout.print(" bound=" + dumpBool(info.agent.isBound()));
599 fout.print(", connected=" + dumpBool(info.agent.isConnected()));
600 fout.print(", managingTrust=" + dumpBool(info.agent.isManagingTrust()));
601 fout.print(", trusted=" + dumpBool(trusted));
604 fout.println(" message=\"" + info.agent.getMessage() + "\"");
606 if (!info.agent.isConnected()) {
607 String restartTime = TrustArchive.formatDuration(
608 info.agent.getScheduledRestartUptimeMillis()
609 - SystemClock.uptimeMillis());
610 fout.println(" restartScheduledAt=" + restartTime);
612 if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) {
613 duplicateSimpleNames = true;
616 fout.println(" Events:");
617 mArchive.dump(fout, 50, user.id, " " /* linePrefix */, duplicateSimpleNames);
621 private String dumpBool(boolean b) {
622 return b ? "1" : "0";
626 private final Handler mHandler = new Handler() {
628 public void handleMessage(Message msg) {
630 case MSG_REGISTER_LISTENER:
631 addListener((ITrustListener) msg.obj);
633 case MSG_UNREGISTER_LISTENER:
634 removeListener((ITrustListener) msg.obj);
636 case MSG_DISPATCH_UNLOCK_ATTEMPT:
637 dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
639 case MSG_ENABLED_AGENTS_CHANGED:
640 refreshAgentList(UserHandle.USER_ALL);
642 case MSG_REQUIRE_CREDENTIAL_ENTRY:
643 requireCredentialEntry(msg.arg1);
649 private final PackageMonitor mPackageMonitor = new PackageMonitor() {
651 public void onSomePackagesChanged() {
652 refreshAgentList(UserHandle.USER_ALL);
656 public boolean onPackageChanged(String packageName, int uid, String[] components) {
657 // We're interested in all changes, even if just some components get enabled / disabled.
662 public void onPackageDisappeared(String packageName, int reason) {
663 removeAgentsOfPackage(packageName);
667 private class Receiver extends BroadcastReceiver {
670 public void onReceive(Context context, Intent intent) {
671 String action = intent.getAction();
672 if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
673 refreshAgentList(getSendingUserId());
674 updateDevicePolicyFeatures();
675 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
676 updateUserHasAuthenticated(getSendingUserId());
677 } else if (Intent.ACTION_USER_ADDED.equals(action)) {
678 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -100);
680 maybeEnableFactoryTrustAgents(mLockPatternUtils, userId);
682 Log.wtf(TAG, "EXTRA_USER_HANDLE missing or invalid, value=" + userId);
687 public void register(Context context) {
688 IntentFilter filter = new IntentFilter();
689 filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
690 filter.addAction(Intent.ACTION_USER_PRESENT);
691 filter.addAction(Intent.ACTION_USER_ADDED);
692 context.registerReceiverAsUser(this,
695 null /* permission */,
696 null /* scheduler */);