TrustAgentWrapper.java revision 7861c663fd64af33ec2a4c5ad653c806dc8bd994
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 android.app.admin.DevicePolicyManager;
20import android.content.BroadcastReceiver;
21import android.content.ComponentName;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.ServiceConnection;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.IBinder;
29import android.os.Message;
30import android.os.RemoteException;
31import android.os.SystemClock;
32import android.os.UserHandle;
33import android.util.Log;
34import android.util.Slog;
35import android.service.trust.ITrustAgentService;
36import android.service.trust.ITrustAgentServiceCallback;
37import android.service.trust.TrustAgentService;
38
39import java.util.ArrayList;
40import java.util.List;
41
42/**
43 * A wrapper around a TrustAgentService interface. Coordinates communication between
44 * TrustManager and the actual TrustAgent.
45 */
46public class TrustAgentWrapper {
47    private static final boolean DEBUG = false;
48    private static final String TAG = "TrustAgentWrapper";
49
50    private static final int MSG_GRANT_TRUST = 1;
51    private static final int MSG_REVOKE_TRUST = 2;
52    private static final int MSG_TRUST_TIMEOUT = 3;
53    private static final int MSG_RESTART_TIMEOUT = 4;
54    private static final int MSG_DPM_CHANGED = 5;
55    private static final int MSG_MANAGING_TRUST = 6;
56
57    /**
58     * Time in uptime millis that we wait for the service connection, both when starting
59     * and when the service disconnects.
60     */
61    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
62
63    /**
64     * Long extra for {@link #MSG_GRANT_TRUST}
65     */
66    private static final String DATA_DURATION = "duration";
67
68    private final TrustManagerService mTrustManagerService;
69    private final int mUserId;
70    private final Context mContext;
71    private final ComponentName mName;
72
73    private ITrustAgentService mTrustAgentService;
74    private boolean mBound;
75    private long mScheduledRestartUptimeMillis;
76
77    // Trust state
78    private boolean mTrusted;
79    private CharSequence mMessage;
80    private boolean mTrustDisabledByDpm;
81    private boolean mManagingTrust;
82
83    private final Handler mHandler = new Handler() {
84        @Override
85        public void handleMessage(Message msg) {
86            switch (msg.what) {
87                case MSG_GRANT_TRUST:
88                    if (!isConnected()) {
89                        Log.w(TAG, "Agent is not connected, cannot grant trust: "
90                                + mName.flattenToShortString());
91                        return;
92                    }
93                    mTrusted = true;
94                    mMessage = (CharSequence) msg.obj;
95                    boolean initiatedByUser = msg.arg1 != 0;
96                    // TODO: Handle initiatedByUser.
97                    long durationMs = msg.getData().getLong(DATA_DURATION);
98                    if (durationMs > 0) {
99                        mHandler.removeMessages(MSG_TRUST_TIMEOUT);
100                        mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
101                    }
102                    mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
103                            (mMessage != null ? mMessage.toString() : null),
104                            durationMs, initiatedByUser);
105                    mTrustManagerService.updateTrust(mUserId);
106                    break;
107                case MSG_TRUST_TIMEOUT:
108                    if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
109                    mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
110                    // Fall through.
111                case MSG_REVOKE_TRUST:
112                    mTrusted = false;
113                    mMessage = null;
114                    mHandler.removeMessages(MSG_TRUST_TIMEOUT);
115                    if (msg.what == MSG_REVOKE_TRUST) {
116                        mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
117                    }
118                    mTrustManagerService.updateTrust(mUserId);
119                    break;
120                case MSG_RESTART_TIMEOUT:
121                    unbind();
122                    mTrustManagerService.resetAgent(mName, mUserId);
123                    break;
124                case MSG_DPM_CHANGED:
125                    updateDevicePolicyFeatures(mName);
126                    break;
127                case MSG_MANAGING_TRUST:
128                    mManagingTrust = msg.arg1 != 0;
129                    if (!mManagingTrust) {
130                        mTrusted = false;
131                        mMessage = null;
132                    }
133                    mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
134                    mTrustManagerService.updateTrust(mUserId);
135                    break;
136            }
137        }
138    };
139
140    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
141
142        @Override
143        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
144            if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
145                        + ", initiatedByUser = " + initiatedByUser + ")");
146
147            Message msg = mHandler.obtainMessage(
148                    MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
149            msg.getData().putLong(DATA_DURATION, durationMs);
150            msg.sendToTarget();
151        }
152
153        @Override
154        public void revokeTrust() {
155            if (DEBUG) Slog.v(TAG, "revokeTrust()");
156            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
157        }
158
159        @Override
160        public void setManagingTrust(boolean managingTrust) {
161            if (DEBUG) Slog.v(TAG, "managingTrust()");
162            mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
163        }
164    };
165
166    private final ServiceConnection mConnection = new ServiceConnection() {
167        @Override
168        public void onServiceConnected(ComponentName name, IBinder service) {
169            if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
170            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
171            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
172            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
173            setCallback(mCallback);
174            updateDevicePolicyFeatures(name);
175            watchForDpmChanges(true);
176        }
177
178        @Override
179        public void onServiceDisconnected(ComponentName name) {
180            if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
181            mTrustAgentService = null;
182            mManagingTrust = false;
183            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
184            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
185            if (mBound) {
186                scheduleRestart();
187            }
188            // mTrustDisabledByDpm maintains state
189            watchForDpmChanges(false);
190        }
191    };
192
193    private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
194
195        @Override
196        public void onReceive(Context context, Intent intent) {
197            if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
198                    .equals(intent.getAction())) {
199                mHandler.sendEmptyMessage(MSG_DPM_CHANGED);
200            }
201        }
202    };
203
204    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
205            Intent intent, UserHandle user) {
206        mContext = context;
207        mTrustManagerService = trustManagerService;
208        mUserId = user.getIdentifier();
209        mName = intent.getComponent();
210        // Schedules a restart for when connecting times out. If the connection succeeds,
211        // the restart is canceled in mCallback's onConnected.
212        scheduleRestart();
213        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
214        if (!mBound) {
215            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
216        }
217    }
218
219    private void onError(Exception e) {
220        Slog.w(TAG , "Remote Exception", e);
221    }
222
223    /**
224     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
225     */
226    public void onUnlockAttempt(boolean successful) {
227        try {
228            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
229        } catch (RemoteException e) {
230            onError(e);
231        }
232    }
233
234    private void setCallback(ITrustAgentServiceCallback callback) {
235        try {
236            if (mTrustAgentService != null) {
237                mTrustAgentService.setCallback(callback);
238            }
239        } catch (RemoteException e) {
240            onError(e);
241        }
242    }
243
244    private void watchForDpmChanges(boolean start) {
245        if (start) {
246            final IntentFilter filter = new IntentFilter();
247            filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
248            filter.addAction(Intent.ACTION_USER_REMOVED);
249            mContext.registerReceiver(mBroadcastReceiver, filter);
250        } else {
251            mContext.unregisterReceiver(mBroadcastReceiver);
252        }
253    }
254
255    private boolean updateDevicePolicyFeatures(ComponentName name) {
256        boolean trustDisabled = false;
257        if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + name + ")");
258        try {
259            if (mTrustAgentService != null) {
260                DevicePolicyManager dpm =
261                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
262                if (dpm != null) {
263                    // If trust disabled, only enable it if the options bundle is set and
264                    // accepted by the TrustAgent.
265                    if ((dpm.getKeyguardDisabledFeatures(null)
266                            & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
267                        List<String> features = dpm.getTrustAgentFeaturesEnabled(null, name);
268                        if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " + features);
269                        if (features != null && features.size() > 0) {
270                            Bundle bundle = new Bundle();
271                            bundle.putStringArrayList(TrustAgentService.KEY_FEATURES,
272                                    (ArrayList<String>)features);
273                            if (DEBUG) {
274                                Slog.v(TAG, "TrustAgent " + name.flattenToShortString()
275                                        + " disabled except "+ features);
276                            }
277                            trustDisabled = mTrustAgentService.setTrustAgentFeaturesEnabled(bundle);
278                        } else {
279                            if (DEBUG) Slog.v(TAG, "TrustAgent " + name + " disabled by flag");
280                            trustDisabled = true; // trust agent should be disabled
281                        }
282                    }
283                } else {
284                    Log.e(TAG, "Can't get DevicePolicyManagerService: is it running?",
285                            new IllegalStateException("Stack trace:"));
286                }
287            }
288        } catch (RemoteException e) {
289            onError(e);
290        }
291        if (mTrustDisabledByDpm != trustDisabled) {
292            mTrustDisabledByDpm = trustDisabled;
293            mTrustManagerService.updateTrust(mUserId);
294        }
295        return trustDisabled;
296    }
297
298    public boolean isTrusted() {
299        return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
300    }
301
302    public boolean isManagingTrust() {
303        return mManagingTrust && !mTrustDisabledByDpm;
304    }
305
306    public CharSequence getMessage() {
307        return mMessage;
308    }
309
310    public void unbind() {
311        if (!mBound) {
312            return;
313        }
314        if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
315        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
316        mContext.unbindService(mConnection);
317        mBound = false;
318        mTrustAgentService = null;
319        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
320        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
321    }
322
323    public boolean isConnected() {
324        return mTrustAgentService != null;
325    }
326
327    public boolean isBound() {
328        return mBound;
329    }
330
331    /**
332     * If not connected, returns the time at which the agent is restarted.
333     *
334     * @return restart time in uptime millis.
335     */
336    public long getScheduledRestartUptimeMillis() {
337        return mScheduledRestartUptimeMillis;
338    }
339
340    private void scheduleRestart() {
341        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
342        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
343        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
344    }
345}
346