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