TrustAgentWrapper.java revision c5f95cea2639b698594a85acbde6a5519941d7b1
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.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.Handler;
24import android.os.IBinder;
25import android.os.Message;
26import android.os.RemoteException;
27import android.os.SystemClock;
28import android.os.UserHandle;
29import android.util.Log;
30import android.util.Slog;
31import android.service.trust.ITrustAgentService;
32import android.service.trust.ITrustAgentServiceCallback;
33
34/**
35 * A wrapper around a TrustAgentService interface. Coordinates communication between
36 * TrustManager and the actual TrustAgent.
37 */
38public class TrustAgentWrapper {
39    private static final boolean DEBUG = false;
40    private static final String TAG = "TrustAgentWrapper";
41
42    private static final int MSG_GRANT_TRUST = 1;
43    private static final int MSG_REVOKE_TRUST = 2;
44    private static final int MSG_TRUST_TIMEOUT = 3;
45    private static final int MSG_RESTART_TIMEOUT = 4;
46
47    /**
48     * Time in uptime millis that we wait for the service connection, both when starting
49     * and when the service disconnects.
50     */
51    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
52
53    /**
54     * Long extra for {@link #MSG_GRANT_TRUST}
55     */
56    private static final String DATA_DURATION = "duration";
57
58    private final TrustManagerService mTrustManagerService;
59    private final int mUserId;
60    private final Context mContext;
61    private final ComponentName mName;
62
63    private ITrustAgentService mTrustAgentService;
64    private boolean mBound;
65    private long mScheduledRestartUptimeMillis;
66
67    // Trust state
68    private boolean mTrusted;
69    private CharSequence mMessage;
70
71    private final Handler mHandler = new Handler() {
72        @Override
73        public void handleMessage(Message msg) {
74            switch (msg.what) {
75                case MSG_GRANT_TRUST:
76                    if (!isConnected()) {
77                        Log.w(TAG, "Agent is not connected, cannot grant trust: "
78                                + mName.flattenToShortString());
79                        return;
80                    }
81                    mTrusted = true;
82                    mMessage = (CharSequence) msg.obj;
83                    boolean initiatedByUser = msg.arg1 != 0;
84                    // TODO: Handle initiatedByUser.
85                    long durationMs = msg.getData().getLong(DATA_DURATION);
86                    if (durationMs > 0) {
87                        mHandler.removeMessages(MSG_TRUST_TIMEOUT);
88                        mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs);
89                    }
90                    mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
91                            (mMessage != null ? mMessage.toString() : null),
92                            durationMs, initiatedByUser);
93                    mTrustManagerService.updateTrust(mUserId);
94                    break;
95                case MSG_TRUST_TIMEOUT:
96                    if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
97                    mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
98                    // Fall through.
99                case MSG_REVOKE_TRUST:
100                    mTrusted = false;
101                    mMessage = null;
102                    mHandler.removeMessages(MSG_TRUST_TIMEOUT);
103                    if (msg.what == MSG_REVOKE_TRUST) {
104                        mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
105                    }
106                    mTrustManagerService.updateTrust(mUserId);
107                    break;
108                case MSG_RESTART_TIMEOUT:
109                    unbind();
110                    mTrustManagerService.resetAgent(mName, mUserId);
111                    break;
112            }
113        }
114    };
115
116    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
117
118        @Override
119        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
120            if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
121                        + ", initiatedByUser = " + initiatedByUser + ")");
122
123            Message msg = mHandler.obtainMessage(
124                    MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
125            msg.getData().putLong(DATA_DURATION, durationMs);
126            msg.sendToTarget();
127        }
128
129        @Override
130        public void revokeTrust() {
131            if (DEBUG) Slog.v(TAG, "revokeTrust()");
132            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
133        }
134    };
135
136    private final ServiceConnection mConnection = new ServiceConnection() {
137        @Override
138        public void onServiceConnected(ComponentName name, IBinder service) {
139            if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
140            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
141            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
142            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
143            setCallback(mCallback);
144        }
145
146        @Override
147        public void onServiceDisconnected(ComponentName name) {
148            if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
149            mTrustAgentService = null;
150            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
151            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
152            if (mBound) {
153                scheduleRestart();
154            }
155        }
156    };
157
158
159    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
160            Intent intent, UserHandle user) {
161        mContext = context;
162        mTrustManagerService = trustManagerService;
163        mUserId = user.getIdentifier();
164        mName = intent.getComponent();
165        // Schedules a restart for when connecting times out. If the connection succeeds,
166        // the restart is canceled in mCallback's onConnected.
167        scheduleRestart();
168        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
169        if (!mBound) {
170            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
171        }
172    }
173
174    private void onError(Exception e) {
175        Slog.w(TAG , "Remote Exception", e);
176    }
177
178    /**
179     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
180     */
181    public void onUnlockAttempt(boolean successful) {
182        try {
183            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
184        } catch (RemoteException e) {
185            onError(e);
186        }
187    }
188
189    private void setCallback(ITrustAgentServiceCallback callback) {
190        try {
191            if (mTrustAgentService != null) {
192                mTrustAgentService.setCallback(callback);
193            }
194        } catch (RemoteException e) {
195            onError(e);
196        }
197    }
198
199    public boolean isTrusted() {
200        return mTrusted;
201    }
202
203    public CharSequence getMessage() {
204        return mMessage;
205    }
206
207    public void unbind() {
208        if (!mBound) {
209            return;
210        }
211        if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
212        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
213        mContext.unbindService(mConnection);
214        mBound = false;
215        mTrustAgentService = null;
216        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
217        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
218    }
219
220    public boolean isConnected() {
221        return mTrustAgentService != null;
222    }
223
224    public boolean isBound() {
225        return mBound;
226    }
227
228    /**
229     * If not connected, returns the time at which the agent is restarted.
230     *
231     * @return restart time in uptime millis.
232     */
233    public long getScheduledRestartUptimeMillis() {
234        return mScheduledRestartUptimeMillis;
235    }
236
237    private void scheduleRestart() {
238        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
239        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
240        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
241    }
242}
243