TrustAgentWrapper.java revision 327323d2b337077433fe02438a79cc98e91799e3
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.Handler;
31import android.os.IBinder;
32import android.os.Message;
33import android.os.PatternMatcher;
34import android.os.PersistableBundle;
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;
42
43import java.util.Collections;
44import java.util.List;
45
46/**
47 * A wrapper around a TrustAgentService interface. Coordinates communication between
48 * TrustManager and the actual TrustAgent.
49 */
50public class TrustAgentWrapper {
51    private static final String EXTRA_COMPONENT_NAME = "componentName";
52    private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
53    private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT;
54    private static final boolean DEBUG = TrustManagerService.DEBUG;
55    private static final String TAG = "TrustAgentWrapper";
56
57    private static final int MSG_GRANT_TRUST = 1;
58    private static final int MSG_REVOKE_TRUST = 2;
59    private static final int MSG_TRUST_TIMEOUT = 3;
60    private static final int MSG_RESTART_TIMEOUT = 4;
61    private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5;
62    private static final int MSG_MANAGING_TRUST = 6;
63
64    /**
65     * Time in uptime millis that we wait for the service connection, both when starting
66     * and when the service disconnects.
67     */
68    private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
69
70    /**
71     * Long extra for {@link #MSG_GRANT_TRUST}
72     */
73    private static final String DATA_DURATION = "duration";
74
75    private final TrustManagerService mTrustManagerService;
76    private final int mUserId;
77    private final Context mContext;
78    private final ComponentName mName;
79
80    private ITrustAgentService mTrustAgentService;
81    private boolean mBound;
82    private long mScheduledRestartUptimeMillis;
83    private long mMaximumTimeToLock; // from DevicePolicyManager
84    private boolean mPendingSuccessfulUnlock = false;
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                    int flags = msg.arg1;
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                                Slog.d(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, flags);
146                    mTrustManagerService.updateTrust(mUserId, flags);
147                    break;
148                case MSG_TRUST_TIMEOUT:
149                    if (DEBUG) Slog.d(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, 0);
161                    break;
162                case MSG_RESTART_TIMEOUT:
163                    Slog.w(TAG, "Connection attempt to agent " + mName.flattenToShortString()
164                            + " timed out, rebinding");
165                    destroy();
166                    mTrustManagerService.resetAgent(mName, mUserId);
167                    break;
168                case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
169                    IBinder token = (IBinder) msg.obj;
170                    boolean result = msg.arg1 != 0;
171                    if (mSetTrustAgentFeaturesToken == token) {
172                        mSetTrustAgentFeaturesToken = null;
173                        if (mTrustDisabledByDpm && result) {
174                            if (DEBUG) Slog.d(TAG, "Re-enabling agent because it acknowledged "
175                                    + "enabled features: " + mName.flattenToShortString());
176                            mTrustDisabledByDpm = false;
177                            mTrustManagerService.updateTrust(mUserId, 0);
178                        }
179                    } else {
180                        if (DEBUG) Slog.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
181                                + "with obsolete token: " + mName.flattenToShortString());
182                    }
183                    break;
184                case MSG_MANAGING_TRUST:
185                    mManagingTrust = msg.arg1 != 0;
186                    if (!mManagingTrust) {
187                        mTrusted = false;
188                        mMessage = null;
189                    }
190                    mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
191                    mTrustManagerService.updateTrust(mUserId, 0);
192                    break;
193            }
194        }
195    };
196
197    private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
198
199        @Override
200        public void grantTrust(CharSequence userMessage, long durationMs, int flags) {
201            if (DEBUG) Slog.d(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
202                        + ", flags = " + flags + ")");
203
204            Message msg = mHandler.obtainMessage(
205                    MSG_GRANT_TRUST, flags, 0, userMessage);
206            msg.getData().putLong(DATA_DURATION, durationMs);
207            msg.sendToTarget();
208        }
209
210        @Override
211        public void revokeTrust() {
212            if (DEBUG) Slog.d(TAG, "revokeTrust()");
213            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
214        }
215
216        @Override
217        public void setManagingTrust(boolean managingTrust) {
218            if (DEBUG) Slog.d(TAG, "managingTrust()");
219            mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
220        }
221
222        @Override
223        public void onConfigureCompleted(boolean result, IBinder token) {
224            if (DEBUG) Slog.d(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
225            mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
226                    result ? 1 : 0, 0, token).sendToTarget();
227        }
228    };
229
230    private final ServiceConnection mConnection = new ServiceConnection() {
231        @Override
232        public void onServiceConnected(ComponentName name, IBinder service) {
233            if (DEBUG) Slog.d(TAG, "TrustAgent started : " + name.flattenToString());
234            mHandler.removeMessages(MSG_RESTART_TIMEOUT);
235            mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
236            mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
237            setCallback(mCallback);
238            updateDevicePolicyFeatures();
239
240            if (mPendingSuccessfulUnlock) {
241                onUnlockAttempt(true);
242                mPendingSuccessfulUnlock = false;
243            }
244
245            if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
246                onDeviceLocked();
247            } else {
248                onDeviceUnlocked();
249            }
250        }
251
252        @Override
253        public void onServiceDisconnected(ComponentName name) {
254            if (DEBUG) Slog.d(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
255            mTrustAgentService = null;
256            mManagingTrust = false;
257            mSetTrustAgentFeaturesToken = null;
258            mTrustManagerService.mArchive.logAgentDied(mUserId, name);
259            mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
260            if (mBound) {
261                scheduleRestart();
262            }
263            // mTrustDisabledByDpm maintains state
264        }
265    };
266
267    public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
268            Intent intent, UserHandle user) {
269        mContext = context;
270        mTrustManagerService = trustManagerService;
271        mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
272        mUserId = user.getIdentifier();
273        mName = intent.getComponent();
274
275        mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
276        mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
277        mAlarmIntent.setPackage(context.getPackageName());
278
279        final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
280        alarmFilter.addDataScheme(mAlarmIntent.getScheme());
281        final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
282        alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
283
284        // Schedules a restart for when connecting times out. If the connection succeeds,
285        // the restart is canceled in mCallback's onConnected.
286        scheduleRestart();
287        mBound = context.bindServiceAsUser(intent, mConnection,
288                Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, user);
289        if (mBound) {
290            mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
291        } else {
292            Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
293        }
294    }
295
296    private void onError(Exception e) {
297        Slog.w(TAG , "Remote Exception", e);
298    }
299
300    private void onTrustTimeout() {
301        try {
302            if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
303        } catch (RemoteException e) {
304            onError(e);
305        }
306    }
307
308    /**
309     * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
310     */
311    public void onUnlockAttempt(boolean successful) {
312        try {
313            if (mTrustAgentService != null) {
314                mTrustAgentService.onUnlockAttempt(successful);
315            } else {
316                mPendingSuccessfulUnlock = successful;
317            }
318        } catch (RemoteException e) {
319            onError(e);
320        }
321    }
322
323    /**
324     * @see android.service.trust.TrustAgentService#onUnlockLockout(int)
325     */
326    public void onUnlockLockout(int timeoutMs) {
327        try {
328            if (mTrustAgentService != null) {
329                mTrustAgentService.onUnlockLockout(timeoutMs);
330            }
331        } catch (RemoteException e) {
332            onError(e);
333        }
334    }
335
336    /**
337     * @see android.service.trust.TrustAgentService#onDeviceLocked()
338     */
339    public void onDeviceLocked() {
340        try {
341            if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
342        } catch (RemoteException e) {
343            onError(e);
344        }
345    }
346
347    /**
348     * @see android.service.trust.TrustAgentService#onDeviceUnlocked()
349     */
350    public void onDeviceUnlocked() {
351        try {
352            if (mTrustAgentService != null) mTrustAgentService.onDeviceUnlocked();
353        } catch (RemoteException e) {
354            onError(e);
355        }
356    }
357
358    private void setCallback(ITrustAgentServiceCallback callback) {
359        try {
360            if (mTrustAgentService != null) {
361                mTrustAgentService.setCallback(callback);
362            }
363        } catch (RemoteException e) {
364            onError(e);
365        }
366    }
367
368    boolean updateDevicePolicyFeatures() {
369        boolean trustDisabled = false;
370        if (DEBUG) Slog.d(TAG, "updateDevicePolicyFeatures(" + mName + ")");
371        try {
372            if (mTrustAgentService != null) {
373                DevicePolicyManager dpm =
374                    (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
375
376                if ((dpm.getKeyguardDisabledFeatures(null, mUserId)
377                        & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
378                    List<PersistableBundle> config = dpm.getTrustAgentConfiguration(
379                            null, mName, mUserId);
380                    trustDisabled = true;
381                    if (DEBUG) Slog.d(TAG, "Detected trust agents disabled. Config = " + config);
382                    if (config != null && config.size() > 0) {
383                        if (DEBUG) {
384                            Slog.d(TAG, "TrustAgent " + mName.flattenToShortString()
385                                    + " disabled until it acknowledges "+ config);
386                        }
387                        mSetTrustAgentFeaturesToken = new Binder();
388                        mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
389                    }
390                } else {
391                    mTrustAgentService.onConfigure(Collections.EMPTY_LIST, null);
392                }
393                final long maxTimeToLock = dpm.getMaximumTimeToLockForUserAndProfiles(mUserId);
394                if (maxTimeToLock != mMaximumTimeToLock) {
395                    // If the timeout changes, cancel the alarm and send a timeout event to have
396                    // the agent re-evaluate trust.
397                    mMaximumTimeToLock = maxTimeToLock;
398                    if (mAlarmPendingIntent != null) {
399                        mAlarmManager.cancel(mAlarmPendingIntent);
400                        mAlarmPendingIntent = null;
401                        mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
402                    }
403                }
404            }
405        } catch (RemoteException e) {
406            onError(e);
407        }
408        if (mTrustDisabledByDpm != trustDisabled) {
409            mTrustDisabledByDpm = trustDisabled;
410            mTrustManagerService.updateTrust(mUserId, 0);
411        }
412        return trustDisabled;
413    }
414
415    public boolean isTrusted() {
416        return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
417    }
418
419    public boolean isManagingTrust() {
420        return mManagingTrust && !mTrustDisabledByDpm;
421    }
422
423    public CharSequence getMessage() {
424        return mMessage;
425    }
426
427    public void destroy() {
428        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
429
430        if (!mBound) {
431            return;
432        }
433        if (DEBUG) Slog.d(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
434        mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
435        mContext.unbindService(mConnection);
436        mBound = false;
437        mContext.unregisterReceiver(mBroadcastReceiver);
438        mTrustAgentService = null;
439        mSetTrustAgentFeaturesToken = null;
440        mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
441    }
442
443    public boolean isConnected() {
444        return mTrustAgentService != null;
445    }
446
447    public boolean isBound() {
448        return mBound;
449    }
450
451    /**
452     * If not connected, returns the time at which the agent is restarted.
453     *
454     * @return restart time in uptime millis.
455     */
456    public long getScheduledRestartUptimeMillis() {
457        return mScheduledRestartUptimeMillis;
458    }
459
460    private void scheduleRestart() {
461        mHandler.removeMessages(MSG_RESTART_TIMEOUT);
462        mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
463        mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
464    }
465}
466