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