TrustAgentWrapper.java revision 76b9b8b0ca537bad6c4da388d77a9e5dee023856
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.AlarmManager;
20import android.app.PendingIntent;
21import android.app.admin.DevicePolicyManager;
22import android.content.BroadcastReceiver;
23import android.content.ComponentName;
24import android.content.Context;
25import android.content.Intent;
26import android.content.IntentFilter;
27import android.content.ServiceConnection;
28import android.net.Uri;
29import android.os.Binder;
30import android.os.Bundle;
31import android.os.Handler;
32import android.os.IBinder;
33import android.os.Message;
34import android.os.PatternMatcher;
35import android.os.RemoteException;
36import android.os.SystemClock;
37import android.os.UserHandle;
38import android.util.Log;
39import android.util.Slog;
40import android.service.trust.ITrustAgentService;
41import android.service.trust.ITrustAgentServiceCallback;
42import android.service.trust.TrustAgentService;
43
44import java.util.ArrayList;
45import java.util.List;
46
47/**
48 * A wrapper around a TrustAgentService interface. Coordinates communication between
49 * TrustManager and the actual TrustAgent.
50 */
51public class TrustAgentWrapper {
52    private static final String EXTRA_COMPONENT_NAME = "componentName";
53    private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
54    private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT;
55    private static final boolean DEBUG = false;
56    private static final String TAG = "TrustAgentWrapper";
57
58    private static final int MSG_GRANT_TRUST = 1;
59    private static final int MSG_REVOKE_TRUST = 2;
60    private static final int MSG_TRUST_TIMEOUT = 3;
61    private static final int MSG_RESTART_TIMEOUT = 4;
62    private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5;
63    private static final int MSG_MANAGING_TRUST = 6;
64
65    /**
66     * Time in uptime millis that we wait for the service connection, both when starting
67     * and when the service disconnects.
68     */
69    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
70
71    /**
72     * Long extra for {@link #MSG_GRANT_TRUST}
73     */
74    private static final String DATA_DURATION = "duration";
75
76    private final TrustManagerService mTrustManagerService;
77    private final int mUserId;
78    private final Context mContext;
79    private final ComponentName mName;
80
81    private ITrustAgentService mTrustAgentService;
82    private boolean mBound;
83    private long mScheduledRestartUptimeMillis;
84    private long mMaximumTimeToLock; // from DevicePolicyManager
85
86    // Trust state
87    private boolean mTrusted;
88    private CharSequence mMessage;
89    private boolean mTrustDisabledByDpm;
90    private boolean mManagingTrust;
91    private IBinder mSetTrustAgentFeaturesToken;
92    private AlarmManager mAlarmManager;
93    private final Intent mAlarmIntent;
94    private PendingIntent mAlarmPendingIntent;
95
96    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
97        @Override
98        public void onReceive(Context context, Intent intent) {
99            ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
100            if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
101                    && mName.equals(component)) {
102                mHandler.removeMessages(MSG_TRUST_TIMEOUT);
103                mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
104            }
105        }
106    };
107
108    private final Handler mHandler = new Handler() {
109        @Override
110        public void handleMessage(Message msg) {
111            switch (msg.what) {
112                case MSG_GRANT_TRUST:
113                    if (!isConnected()) {
114                        Log.w(TAG, "Agent is not connected, cannot grant trust: "
115                                + mName.flattenToShortString());
116                        return;
117                    }
118                    mTrusted = true;
119                    mMessage = (CharSequence) msg.obj;
120                    boolean initiatedByUser = msg.arg1 != 0;
121                    long durationMs = msg.getData().getLong(DATA_DURATION);
122                    if (durationMs > 0) {
123                        final long duration;
124                        if (mMaximumTimeToLock != 0) {
125                            // Enforce DevicePolicyManager timeout.  This is here as a safeguard to
126                            // ensure trust agents are evaluating trust state at least as often as
127                            // the policy dictates. Admins that want more guarantees should be using
128                            // DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS.
129                            duration = Math.min(durationMs, mMaximumTimeToLock);
130                            if (DEBUG) {
131                                Log.v(TAG, "DPM lock timeout in effect. Timeout adjusted from "
132                                    + durationMs + " to " + duration);
133                            }
134                        } else {
135                            duration = durationMs;
136                        }
137                        long expiration = SystemClock.elapsedRealtime() + duration;
138                        mAlarmPendingIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
139                                PendingIntent.FLAG_CANCEL_CURRENT);
140                        mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration,
141                                mAlarmPendingIntent);
142                    }
143                    mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
144                            (mMessage != null ? mMessage.toString() : null),
145                            durationMs, initiatedByUser);
146                    mTrustManagerService.updateTrust(mUserId, initiatedByUser);
147                    break;
148                case MSG_TRUST_TIMEOUT:
149                    if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString());
150                    mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
151                    onTrustTimeout();
152                    // Fall through.
153                case MSG_REVOKE_TRUST:
154                    mTrusted = false;
155                    mMessage = null;
156                    mHandler.removeMessages(MSG_TRUST_TIMEOUT);
157                    if (msg.what == MSG_REVOKE_TRUST) {
158                        mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
159                    }
160                    mTrustManagerService.updateTrust(mUserId, false);
161                    break;
162                case MSG_RESTART_TIMEOUT:
163                    unbind();
164                    mTrustManagerService.resetAgent(mName, mUserId);
165                    break;
166                case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
167                    IBinder token = (IBinder) msg.obj;
168                    boolean result = msg.arg1 != 0;
169                    if (mSetTrustAgentFeaturesToken == token) {
170                        mSetTrustAgentFeaturesToken = null;
171                        if (mTrustDisabledByDpm && result) {
172                            if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged "
173                                    + "enabled features: " + mName);
174                            mTrustDisabledByDpm = false;
175                            mTrustManagerService.updateTrust(mUserId, false);
176                        }
177                    } else {
178                        if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
179                                + "with obsolete token: " + mName);
180                    }
181                    break;
182                case MSG_MANAGING_TRUST:
183                    mManagingTrust = msg.arg1 != 0;
184                    if (!mManagingTrust) {
185                        mTrusted = false;
186                        mMessage = null;
187                    }
188                    mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
189                    mTrustManagerService.updateTrust(mUserId, false);
190                    break;
191            }
192        }
193    };
194
195    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
196
197        @Override
198        public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) {
199            if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
200                        + ", initiatedByUser = " + initiatedByUser + ")");
201
202            Message msg = mHandler.obtainMessage(
203                    MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage);
204            msg.getData().putLong(DATA_DURATION, durationMs);
205            msg.sendToTarget();
206        }
207
208        @Override
209        public void revokeTrust() {
210            if (DEBUG) Slog.v(TAG, "revokeTrust()");
211            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
212        }
213
214        @Override
215        public void setManagingTrust(boolean managingTrust) {
216            if (DEBUG) Slog.v(TAG, "managingTrust()");
217            mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
218        }
219
220        @Override
221        public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) {
222            if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
223            mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
224                    result ? 1 : 0, 0, token).sendToTarget();
225        }
226    };
227
228    private final ServiceConnection mConnection = new ServiceConnection() {
229        @Override
230        public void onServiceConnected(ComponentName name, IBinder service) {
231            if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString());
232            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
233            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
234            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
235            setCallback(mCallback);
236            updateDevicePolicyFeatures();
237        }
238
239        @Override
240        public void onServiceDisconnected(ComponentName name) {
241            if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
242            mTrustAgentService = null;
243            mManagingTrust = false;
244            mSetTrustAgentFeaturesToken = null;
245            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
246            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
247            if (mBound) {
248                scheduleRestart();
249            }
250            // mTrustDisabledByDpm maintains state
251        }
252    };
253
254    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
255            Intent intent, UserHandle user) {
256        mContext = context;
257        mTrustManagerService = trustManagerService;
258        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
259        mUserId = user.getIdentifier();
260        mName = intent.getComponent();
261
262        mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
263        mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
264        mAlarmIntent.setPackage(context.getPackageName());
265
266        final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
267        alarmFilter.addDataScheme(mAlarmIntent.getScheme());
268        final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
269        alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
270        mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
271
272        // Schedules a restart for when connecting times out. If the connection succeeds,
273        // the restart is canceled in mCallback's onConnected.
274        scheduleRestart();
275        mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user);
276        if (!mBound) {
277            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
278        }
279    }
280
281    private void onError(Exception e) {
282        Slog.w(TAG , "Remote Exception", e);
283    }
284
285    private void onTrustTimeout() {
286        try {
287            if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
288        } catch (RemoteException e) {
289            onError(e);
290        }
291    }
292    /**
293     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
294     */
295    public void onUnlockAttempt(boolean successful) {
296        try {
297            if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful);
298        } catch (RemoteException e) {
299            onError(e);
300        }
301    }
302
303    private void setCallback(ITrustAgentServiceCallback callback) {
304        try {
305            if (mTrustAgentService != null) {
306                mTrustAgentService.setCallback(callback);
307            }
308        } catch (RemoteException e) {
309            onError(e);
310        }
311    }
312
313    boolean updateDevicePolicyFeatures() {
314        boolean trustDisabled = false;
315        if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")");
316        try {
317            if (mTrustAgentService != null) {
318                DevicePolicyManager dpm =
319                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
320
321                if ((dpm.getKeyguardDisabledFeatures(null)
322                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
323                    List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName);
324                    trustDisabled = true;
325                    if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = "
326                            + features);
327                    if (features != null && features.size() > 0) {
328                        Bundle bundle = new Bundle();
329                        bundle.putStringArrayList(TrustAgentService.KEY_FEATURES,
330                                (ArrayList<String>)features);
331                        if (DEBUG) {
332                            Slog.v(TAG, "TrustAgent " + mName.flattenToShortString()
333                                    + " disabled until it acknowledges "+ features);
334                        }
335                        mSetTrustAgentFeaturesToken = new Binder();
336                        mTrustAgentService.setTrustAgentFeaturesEnabled(bundle,
337                                mSetTrustAgentFeaturesToken);
338                    }
339                }
340                final long maxTimeToLock = dpm.getMaximumTimeToLock(null);
341                if (maxTimeToLock != mMaximumTimeToLock) {
342                    // If the timeout changes, cancel the alarm and send a timeout event to have
343                    // the agent re-evaluate trust.
344                    mMaximumTimeToLock = maxTimeToLock;
345                    if (mAlarmPendingIntent != null) {
346                        mAlarmManager.cancel(mAlarmPendingIntent);
347                        mAlarmPendingIntent = null;
348                        mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
349                    }
350                }
351            }
352        } catch (RemoteException e) {
353            onError(e);
354        }
355        if (mTrustDisabledByDpm != trustDisabled) {
356            mTrustDisabledByDpm = trustDisabled;
357            mTrustManagerService.updateTrust(mUserId, false);
358        }
359        return trustDisabled;
360    }
361
362    public boolean isTrusted() {
363        return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
364    }
365
366    public boolean isManagingTrust() {
367        return mManagingTrust && !mTrustDisabledByDpm;
368    }
369
370    public CharSequence getMessage() {
371        return mMessage;
372    }
373
374    public void unbind() {
375        if (!mBound) {
376            return;
377        }
378        if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
379        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
380        mContext.unbindService(mConnection);
381        mBound = false;
382        mTrustAgentService = null;
383        mSetTrustAgentFeaturesToken = null;
384        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
385        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
386    }
387
388    public boolean isConnected() {
389        return mTrustAgentService != null;
390    }
391
392    public boolean isBound() {
393        return mBound;
394    }
395
396    /**
397     * If not connected, returns the time at which the agent is restarted.
398     *
399     * @return restart time in uptime millis.
400     */
401    public long getScheduledRestartUptimeMillis() {
402        return mScheduledRestartUptimeMillis;
403    }
404
405    private void scheduleRestart() {
406        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
407        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
408        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
409    }
410}
411