TrustManagerService.java revision c5f95cea2639b698594a85acbde6a5519941d7b1
1/*
2 * Copyright (C) 2014 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.trust;
18
19import com.android.internal.content.PackageMonitor;
20import com.android.internal.widget.LockPatternUtils;
21import com.android.server.SystemService;
22
23import org.xmlpull.v1.XmlPullParser;
24import org.xmlpull.v1.XmlPullParserException;
25
26import android.Manifest;
27import android.app.ActivityManagerNative;
28import android.app.admin.DevicePolicyManager;
29import android.app.trust.ITrustListener;
30import android.app.trust.ITrustManager;
31import android.content.BroadcastReceiver;
32import android.content.ComponentName;
33import android.content.Context;
34import android.content.Intent;
35import android.content.IntentFilter;
36import android.content.pm.PackageManager;
37import android.content.pm.ResolveInfo;
38import android.content.pm.UserInfo;
39import android.content.res.Resources;
40import android.content.res.TypedArray;
41import android.content.res.XmlResourceParser;
42import android.graphics.drawable.Drawable;
43import android.os.DeadObjectException;
44import android.os.Handler;
45import android.os.IBinder;
46import android.os.Message;
47import android.os.RemoteException;
48import android.os.SystemClock;
49import android.os.UserHandle;
50import android.os.UserManager;
51import android.service.trust.TrustAgentService;
52import android.util.ArraySet;
53import android.util.AttributeSet;
54import android.util.Log;
55import android.util.Slog;
56import android.util.SparseBooleanArray;
57import android.util.Xml;
58
59import java.io.FileDescriptor;
60import java.io.IOException;
61import java.io.PrintWriter;
62import java.util.ArrayList;
63import java.util.List;
64
65/**
66 * Manages trust agents and trust listeners.
67 *
68 * It is responsible for binding to the enabled {@link android.service.trust.TrustAgentService}s
69 * of each user and notifies them about events that are relevant to them.
70 * It start and stops them based on the value of
71 * {@link com.android.internal.widget.LockPatternUtils#getEnabledTrustAgents(int)}.
72 *
73 * It also keeps a set of {@link android.app.trust.ITrustListener}s that are notified whenever the
74 * trust state changes for any user.
75 *
76 * Trust state and the setting of enabled agents is kept per user and each user has its own
77 * instance of a {@link android.service.trust.TrustAgentService}.
78 */
79public class TrustManagerService extends SystemService {
80
81    private static final boolean DEBUG = false;
82    private static final String TAG = "TrustManagerService";
83
84    private static final Intent TRUST_AGENT_INTENT =
85            new Intent(TrustAgentService.SERVICE_INTERFACE);
86    private static final String PERMISSION_PROVIDE_AGENT = Manifest.permission.PROVIDE_TRUST_AGENT;
87
88    private static final int MSG_REGISTER_LISTENER = 1;
89    private static final int MSG_UNREGISTER_LISTENER = 2;
90    private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
91    private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
92    private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
93
94    private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
95    private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
96    private final DevicePolicyReceiver mDevicePolicyReceiver = new DevicePolicyReceiver();
97    private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
98    /* package */ final TrustArchive mArchive = new TrustArchive();
99    private final Context mContext;
100
101    private UserManager mUserManager;
102
103    public TrustManagerService(Context context) {
104        super(context);
105        mContext = context;
106        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
107    }
108
109    @Override
110    public void onStart() {
111        publishBinderService(Context.TRUST_SERVICE, mService);
112    }
113
114    @Override
115    public void onBootPhase(int phase) {
116        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) {
117            mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
118            mDevicePolicyReceiver.register(mContext);
119            refreshAgentList();
120        }
121    }
122
123    // Agent management
124
125    private static final class AgentInfo {
126        CharSequence label;
127        Drawable icon;
128        ComponentName component; // service that implements ITrustAgent
129        ComponentName settings; // setting to launch to modify agent.
130        TrustAgentWrapper agent;
131        int userId;
132
133        @Override
134        public boolean equals(Object other) {
135            if (!(other instanceof AgentInfo)) {
136                return false;
137            }
138            AgentInfo o = (AgentInfo) other;
139            return component.equals(o.component) && userId == o.userId;
140        }
141
142        @Override
143        public int hashCode() {
144            return component.hashCode() * 31 + userId;
145        }
146    }
147
148    private void updateTrustAll() {
149        List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
150        for (UserInfo userInfo : userInfos) {
151            updateTrust(userInfo.id);
152        }
153    }
154
155    public void updateTrust(int userId) {
156        dispatchOnTrustChanged(aggregateIsTrusted(userId), userId);
157    }
158
159    protected void refreshAgentList() {
160        if (DEBUG) Slog.d(TAG, "refreshAgentList()");
161        PackageManager pm = mContext.getPackageManager();
162
163        List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
164        LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
165
166        ArraySet<AgentInfo> obsoleteAgents = new ArraySet<>();
167        obsoleteAgents.addAll(mActiveAgents);
168
169        for (UserInfo userInfo : userInfos) {
170            int disabledFeatures = lockPatternUtils.getDevicePolicyManager()
171                    .getKeyguardDisabledFeatures(null, userInfo.id);
172            boolean disableTrustAgents =
173                    (disabledFeatures & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0;
174
175            List<ComponentName> enabledAgents = lockPatternUtils.getEnabledTrustAgents(userInfo.id);
176            if (disableTrustAgents || enabledAgents == null) {
177                continue;
178            }
179            List<ResolveInfo> resolveInfos = pm.queryIntentServicesAsUser(TRUST_AGENT_INTENT,
180                    PackageManager.GET_META_DATA, userInfo.id);
181            for (ResolveInfo resolveInfo : resolveInfos) {
182                if (resolveInfo.serviceInfo == null) continue;
183
184                String packageName = resolveInfo.serviceInfo.packageName;
185                if (pm.checkPermission(PERMISSION_PROVIDE_AGENT, packageName)
186                        != PackageManager.PERMISSION_GRANTED) {
187                    Log.w(TAG, "Skipping agent because package " + packageName
188                            + " does not have permission " + PERMISSION_PROVIDE_AGENT + ".");
189                    continue;
190                }
191
192                ComponentName name = getComponentName(resolveInfo);
193                if (!enabledAgents.contains(name)) continue;
194
195                AgentInfo agentInfo = new AgentInfo();
196                agentInfo.component = name;
197                agentInfo.userId = userInfo.id;
198                if (!mActiveAgents.contains(agentInfo)) {
199                    agentInfo.label = resolveInfo.loadLabel(pm);
200                    agentInfo.icon = resolveInfo.loadIcon(pm);
201                    agentInfo.settings = getSettingsComponentName(pm, resolveInfo);
202                    agentInfo.agent = new TrustAgentWrapper(mContext, this,
203                            new Intent().setComponent(name), userInfo.getUserHandle());
204                    mActiveAgents.add(agentInfo);
205                } else {
206                    obsoleteAgents.remove(agentInfo);
207                }
208            }
209        }
210
211        boolean trustMayHaveChanged = false;
212        for (int i = 0; i < obsoleteAgents.size(); i++) {
213            AgentInfo info = obsoleteAgents.valueAt(i);
214            if (info.agent.isTrusted()) {
215                trustMayHaveChanged = true;
216            }
217            info.agent.unbind();
218            mActiveAgents.remove(info);
219        }
220
221        if (trustMayHaveChanged) {
222            updateTrustAll();
223        }
224    }
225
226    private void removeAgentsOfPackage(String packageName) {
227        boolean trustMayHaveChanged = false;
228        for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
229            AgentInfo info = mActiveAgents.valueAt(i);
230            if (packageName.equals(info.component.getPackageName())) {
231                Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
232                if (info.agent.isTrusted()) {
233                    trustMayHaveChanged = true;
234                }
235                info.agent.unbind();
236                mActiveAgents.removeAt(i);
237            }
238        }
239        if (trustMayHaveChanged) {
240            updateTrustAll();
241        }
242    }
243
244    public void resetAgent(ComponentName name, int userId) {
245        boolean trustMayHaveChanged = false;
246        for (int i = mActiveAgents.size() - 1; i >= 0; i--) {
247            AgentInfo info = mActiveAgents.valueAt(i);
248            if (name.equals(info.component) && userId == info.userId) {
249                Log.i(TAG, "Resetting agent " + info.component.flattenToShortString());
250                if (info.agent.isTrusted()) {
251                    trustMayHaveChanged = true;
252                }
253                info.agent.unbind();
254                mActiveAgents.removeAt(i);
255            }
256        }
257        if (trustMayHaveChanged) {
258            updateTrust(userId);
259        }
260        refreshAgentList();
261    }
262
263    private ComponentName getSettingsComponentName(PackageManager pm, ResolveInfo resolveInfo) {
264        if (resolveInfo == null || resolveInfo.serviceInfo == null
265                || resolveInfo.serviceInfo.metaData == null) return null;
266        String cn = null;
267        XmlResourceParser parser = null;
268        Exception caughtException = null;
269        try {
270            parser = resolveInfo.serviceInfo.loadXmlMetaData(pm,
271                    TrustAgentService.TRUST_AGENT_META_DATA);
272            if (parser == null) {
273                Slog.w(TAG, "Can't find " + TrustAgentService.TRUST_AGENT_META_DATA + " meta-data");
274                return null;
275            }
276            Resources res = pm.getResourcesForApplication(resolveInfo.serviceInfo.applicationInfo);
277            AttributeSet attrs = Xml.asAttributeSet(parser);
278            int type;
279            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
280                    && type != XmlPullParser.START_TAG) {
281                // Drain preamble.
282            }
283            String nodeName = parser.getName();
284            if (!"trust-agent".equals(nodeName)) {
285                Slog.w(TAG, "Meta-data does not start with trust-agent tag");
286                return null;
287            }
288            TypedArray sa = res
289                    .obtainAttributes(attrs, com.android.internal.R.styleable.TrustAgent);
290            cn = sa.getString(com.android.internal.R.styleable.TrustAgent_settingsActivity);
291            sa.recycle();
292        } catch (PackageManager.NameNotFoundException e) {
293            caughtException = e;
294        } catch (IOException e) {
295            caughtException = e;
296        } catch (XmlPullParserException e) {
297            caughtException = e;
298        } finally {
299            if (parser != null) parser.close();
300        }
301        if (caughtException != null) {
302            Slog.w(TAG, "Error parsing : " + resolveInfo.serviceInfo.packageName, caughtException);
303            return null;
304        }
305        if (cn == null) {
306            return null;
307        }
308        if (cn.indexOf('/') < 0) {
309            cn = resolveInfo.serviceInfo.packageName + "/" + cn;
310        }
311        return ComponentName.unflattenFromString(cn);
312    }
313
314    private ComponentName getComponentName(ResolveInfo resolveInfo) {
315        if (resolveInfo == null || resolveInfo.serviceInfo == null) return null;
316        return new ComponentName(resolveInfo.serviceInfo.packageName, resolveInfo.serviceInfo.name);
317    }
318
319    // Agent dispatch and aggregation
320
321    private boolean aggregateIsTrusted(int userId) {
322        if (!mUserHasAuthenticatedSinceBoot.get(userId)) {
323            return false;
324        }
325        for (int i = 0; i < mActiveAgents.size(); i++) {
326            AgentInfo info = mActiveAgents.valueAt(i);
327            if (info.userId == userId) {
328                if (info.agent.isTrusted()) {
329                    return true;
330                }
331            }
332        }
333        return false;
334    }
335
336    private void dispatchUnlockAttempt(boolean successful, int userId) {
337        for (int i = 0; i < mActiveAgents.size(); i++) {
338            AgentInfo info = mActiveAgents.valueAt(i);
339            if (info.userId == userId) {
340                info.agent.onUnlockAttempt(successful);
341            }
342        }
343
344        if (successful && !mUserHasAuthenticatedSinceBoot.get(userId)) {
345            mUserHasAuthenticatedSinceBoot.put(userId, true);
346            updateTrust(userId);
347        }
348    }
349
350
351    private void requireCredentialEntry(int userId) {
352        if (userId == UserHandle.USER_ALL) {
353            mUserHasAuthenticatedSinceBoot.clear();
354            updateTrustAll();
355        } else {
356            mUserHasAuthenticatedSinceBoot.put(userId, false);
357            updateTrust(userId);
358        }
359    }
360
361    // Listeners
362
363    private void addListener(ITrustListener listener) {
364        for (int i = 0; i < mTrustListeners.size(); i++) {
365            if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
366                return;
367            }
368        }
369        mTrustListeners.add(listener);
370    }
371
372    private void removeListener(ITrustListener listener) {
373        for (int i = 0; i < mTrustListeners.size(); i++) {
374            if (mTrustListeners.get(i).asBinder() == listener.asBinder()) {
375                mTrustListeners.get(i);
376                return;
377            }
378        }
379    }
380
381    private void dispatchOnTrustChanged(boolean enabled, int userId) {
382        for (int i = 0; i < mTrustListeners.size(); i++) {
383            try {
384                mTrustListeners.get(i).onTrustChanged(enabled, userId);
385            } catch (DeadObjectException e) {
386                if (DEBUG) Slog.d(TAG, "Removing dead TrustListener.");
387                mTrustListeners.remove(i);
388                i--;
389            } catch (RemoteException e) {
390                Slog.e(TAG, "Exception while notifying TrustListener.", e);
391            }
392        }
393    }
394
395    // Plumbing
396
397    private final IBinder mService = new ITrustManager.Stub() {
398        @Override
399        public void reportUnlockAttempt(boolean authenticated, int userId) throws RemoteException {
400            enforceReportPermission();
401            mHandler.obtainMessage(MSG_DISPATCH_UNLOCK_ATTEMPT, authenticated ? 1 : 0, userId)
402                    .sendToTarget();
403        }
404
405        @Override
406        public void reportEnabledTrustAgentsChanged(int userId) throws RemoteException {
407            enforceReportPermission();
408            // coalesce refresh messages.
409            mHandler.removeMessages(MSG_ENABLED_AGENTS_CHANGED);
410            mHandler.sendEmptyMessage(MSG_ENABLED_AGENTS_CHANGED);
411        }
412
413        @Override
414        public void reportRequireCredentialEntry(int userId) throws RemoteException {
415            enforceReportPermission();
416            if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
417                mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget();
418            } else {
419                throw new IllegalArgumentException(
420                        "userId must be an explicit user id or USER_ALL");
421            }
422        }
423
424        @Override
425        public void registerTrustListener(ITrustListener trustListener) throws RemoteException {
426            enforceListenerPermission();
427            mHandler.obtainMessage(MSG_REGISTER_LISTENER, trustListener).sendToTarget();
428        }
429
430        @Override
431        public void unregisterTrustListener(ITrustListener trustListener) throws RemoteException {
432            enforceListenerPermission();
433            mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget();
434        }
435
436        private void enforceReportPermission() {
437            mContext.enforceCallingOrSelfPermission(
438                    Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
439        }
440
441        private void enforceListenerPermission() {
442            mContext.enforceCallingPermission(Manifest.permission.TRUST_LISTENER,
443                    "register trust listener");
444        }
445
446        @Override
447        protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) {
448            mContext.enforceCallingPermission(Manifest.permission.DUMP,
449                    "dumping TrustManagerService");
450            final UserInfo currentUser;
451            final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */);
452            try {
453                currentUser = ActivityManagerNative.getDefault().getCurrentUser();
454            } catch (RemoteException e) {
455                throw new RuntimeException(e);
456            }
457            mHandler.runWithScissors(new Runnable() {
458                @Override
459                public void run() {
460                    fout.println("Trust manager state:");
461                    for (UserInfo user : userInfos) {
462                        dumpUser(fout, user, user.id == currentUser.id);
463                    }
464                }
465            }, 1500);
466        }
467
468        private void dumpUser(PrintWriter fout, UserInfo user, boolean isCurrent) {
469            fout.printf(" User \"%s\" (id=%d, flags=%#x)",
470                    user.name, user.id, user.flags);
471            if (isCurrent) {
472                fout.print(" (current)");
473            }
474            fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
475            fout.println();
476            fout.println("   Enabled agents:");
477            boolean duplicateSimpleNames = false;
478            ArraySet<String> simpleNames = new ArraySet<String>();
479            for (AgentInfo info : mActiveAgents) {
480                if (info.userId != user.id) { continue; }
481                boolean trusted = info.agent.isTrusted();
482                fout.print("    "); fout.println(info.component.flattenToShortString());
483                fout.print("     bound=" + dumpBool(info.agent.isBound()));
484                fout.print(", connected=" + dumpBool(info.agent.isConnected()));
485                fout.println(", trusted=" + dumpBool(trusted));
486                if (trusted) {
487                    fout.println("      message=\"" + info.agent.getMessage() + "\"");
488                }
489                if (!info.agent.isConnected()) {
490                    String restartTime = TrustArchive.formatDuration(
491                            info.agent.getScheduledRestartUptimeMillis()
492                                    - SystemClock.uptimeMillis());
493                    fout.println("      restartScheduledAt=" + restartTime);
494                }
495                if (!simpleNames.add(TrustArchive.getSimpleName(info.component))) {
496                    duplicateSimpleNames = true;
497                }
498            }
499            fout.println("   Events:");
500            mArchive.dump(fout, 50, user.id, "    " /* linePrefix */, duplicateSimpleNames);
501            fout.println();
502        }
503
504        private String dumpBool(boolean b) {
505            return b ? "1" : "0";
506        }
507    };
508
509    private final Handler mHandler = new Handler() {
510        @Override
511        public void handleMessage(Message msg) {
512            switch (msg.what) {
513                case MSG_REGISTER_LISTENER:
514                    addListener((ITrustListener) msg.obj);
515                    break;
516                case MSG_UNREGISTER_LISTENER:
517                    removeListener((ITrustListener) msg.obj);
518                    break;
519                case MSG_DISPATCH_UNLOCK_ATTEMPT:
520                    dispatchUnlockAttempt(msg.arg1 != 0, msg.arg2);
521                    break;
522                case MSG_ENABLED_AGENTS_CHANGED:
523                    refreshAgentList();
524                    break;
525                case MSG_REQUIRE_CREDENTIAL_ENTRY:
526                    requireCredentialEntry(msg.arg1);
527                    break;
528            }
529        }
530    };
531
532    private final PackageMonitor mPackageMonitor = new PackageMonitor() {
533        @Override
534        public void onSomePackagesChanged() {
535            refreshAgentList();
536        }
537
538        @Override
539        public boolean onPackageChanged(String packageName, int uid, String[] components) {
540            // We're interested in all changes, even if just some components get enabled / disabled.
541            return true;
542        }
543
544        @Override
545        public void onPackageDisappeared(String packageName, int reason) {
546            removeAgentsOfPackage(packageName);
547        }
548    };
549
550    private class DevicePolicyReceiver extends BroadcastReceiver {
551
552        @Override
553        public void onReceive(Context context, Intent intent) {
554            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(
555                    intent.getAction())) {
556                refreshAgentList();
557            }
558        }
559
560        public void register(Context context) {
561            context.registerReceiverAsUser(this,
562                    UserHandle.ALL,
563                    new IntentFilter(
564                            DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
565                    null /* permission */,
566                    null /* scheduler */);
567        }
568    }
569}
570