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