TrustAgentWrapper.java revision 8f21158fe64eb93ff005dc1b831b282b95531023
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                    // 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_SET_TRUST_AGENT_FEATURES_COMPLETED:
125                    IBinder token = (IBinder) msg.obj;
126                    boolean result = msg.arg1 != 0;
127                    if (mSetTrustAgentFeaturesToken == token) {
128                        mSetTrustAgentFeaturesToken = null;
129                        if (mTrustDisabledByDpm && result) {
130                            if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged "
131                                    + "enabled features: " + mName);
132                            mTrustDisabledByDpm = false;
133                            mTrustManagerService.updateTrust(mUserId);
134                        }
135                    } else {
136                        if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
137                                + "with obsolete token: " + mName);
138                    }
139                    break;
140                case MSG_MANAGING_TRUST:
141                    mManagingTrust = msg.arg1 != 0;
142                    if (!mManagingTrust) {
143                        mTrusted = false;
144                        mMessage = null;
145                    }
146                    mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
147                    mTrustManagerService.updateTrust(mUserId);
148                    break;
149            }
150        }
151    };
152
153    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
154
155        @Override
156        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
157            if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
158                        + ", initiatedByUser = " + initiatedByUser + ")");
159
160            Message msg = mHandler.obtainMessage(
161                    MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
162            msg.getData().putLong(DATA_DURATION, durationMs);
163            msg.sendToTarget();
164        }
165
166        @Override
167        public void revokeTrust() {
168            if (DEBUG) Slog.v(TAG, "revokeTrust()");
169            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
170        }
171
172        @Override
173        public void setManagingTrust(boolean managingTrust) {
174            if (DEBUG) Slog.v(TAG, "managingTrust()");
175            mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
176        }
177
178        @Override
179        public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) {
180            if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
181            mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
182                    result ? 1 : 0, 0, token).sendToTarget();
183        }
184    };
185
186    private final ServiceConnection mConnection = new ServiceConnection() {
187        @Override
188        public void onServiceConnected(ComponentName name, IBinder service) {
189            if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
190            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
191            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
192            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
193            setCallback(mCallback);
194            updateDevicePolicyFeatures();
195        }
196
197        @Override
198        public void onServiceDisconnected(ComponentName name) {
199            if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
200            mTrustAgentService = null;
201            mManagingTrust = false;
202            mSetTrustAgentFeaturesToken = null;
203            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
204            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
205            if (mBound) {
206                scheduleRestart();
207            }
208            // mTrustDisabledByDpm maintains state
209        }
210    };
211
212    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
213            Intent intent, UserHandle user) {
214        mContext = context;
215        mTrustManagerService = trustManagerService;
216        mUserId = user.getIdentifier();
217        mName = intent.getComponent();
218        // Schedules a restart for when connecting times out. If the connection succeeds,
219        // the restart is canceled in mCallback's onConnected.
220        scheduleRestart();
221        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
222        if (!mBound) {
223            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
224        }
225    }
226
227    private void onError(Exception e) {
228        Slog.w(TAG , "Remote Exception", e);
229    }
230
231    /**
232     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
233     */
234    public void onUnlockAttempt(boolean successful) {
235        try {
236            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
237        } catch (RemoteException e) {
238            onError(e);
239        }
240    }
241
242    private void setCallback(ITrustAgentServiceCallback callback) {
243        try {
244            if (mTrustAgentService != null) {
245                mTrustAgentService.setCallback(callback);
246            }
247        } catch (RemoteException e) {
248            onError(e);
249        }
250    }
251
252    boolean updateDevicePolicyFeatures() {
253        boolean trustDisabled = false;
254        if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")");
255        try {
256            if (mTrustAgentService != null) {
257                DevicePolicyManager dpm =
258                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
259
260                if ((dpm.getKeyguardDisabledFeatures(null)
261                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
262                    List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName);
263                    trustDisabled = true;
264                    if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = "
265                            + features);
266                    if (features != null && features.size() > 0) {
267                        Bundle bundle = new Bundle();
268                        bundle.putStringArrayList(TrustAgentService.KEY_FEATURES,
269                                (ArrayList<String>)features);
270                        if (DEBUG) {
271                            Slog.v(TAG, "TrustAgent " + mName.flattenToShortString()
272                                    + " disabled until it acknowledges "+ features);
273                        }
274                        mSetTrustAgentFeaturesToken = new Binder();
275                        mTrustAgentService.setTrustAgentFeaturesEnabled(bundle,
276                                mSetTrustAgentFeaturesToken);
277                    }
278                }
279            }
280        } catch (RemoteException e) {
281            onError(e);
282        }
283        if (mTrustDisabledByDpm != trustDisabled) {
284            mTrustDisabledByDpm = trustDisabled;
285            mTrustManagerService.updateTrust(mUserId);
286        }
287        return trustDisabled;
288    }
289
290    public boolean isTrusted() {
291        return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
292    }
293
294    public boolean isManagingTrust() {
295        return mManagingTrust && !mTrustDisabledByDpm;
296    }
297
298    public CharSequence getMessage() {
299        return mMessage;
300    }
301
302    public void unbind() {
303        if (!mBound) {
304            return;
305        }
306        if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
307        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
308        mContext.unbindService(mConnection);
309        mBound = false;
310        mTrustAgentService = null;
311        mSetTrustAgentFeaturesToken = null;
312        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
313        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
314    }
315
316    public boolean isConnected() {
317        return mTrustAgentService != null;
318    }
319
320    public boolean isBound() {
321        return mBound;
322    }
323
324    /**
325     * If not connected, returns the time at which the agent is restarted.
326     *
327     * @return restart time in uptime millis.
328     */
329    public long getScheduledRestartUptimeMillis() {
330        return mScheduledRestartUptimeMillis;
331    }
332
333    private void scheduleRestart() {
334        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
335        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
336        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
337    }
338}
339