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