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