Home | History | Annotate | Download | only in trust
      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 
     17 package com.android.server.trust;
     18 
     19 import android.annotation.TargetApi;
     20 import android.app.AlarmManager;
     21 import android.app.PendingIntent;
     22 import android.app.admin.DevicePolicyManager;
     23 import android.content.BroadcastReceiver;
     24 import android.content.ComponentName;
     25 import android.content.Context;
     26 import android.content.Intent;
     27 import android.content.IntentFilter;
     28 import android.content.ServiceConnection;
     29 import android.net.Uri;
     30 import android.os.Binder;
     31 import android.os.Build;
     32 import android.os.Handler;
     33 import android.os.IBinder;
     34 import android.os.Message;
     35 import android.os.PatternMatcher;
     36 import android.os.PersistableBundle;
     37 import android.os.RemoteException;
     38 import android.os.SystemClock;
     39 import android.os.UserHandle;
     40 import android.service.trust.ITrustAgentService;
     41 import android.service.trust.ITrustAgentServiceCallback;
     42 import android.service.trust.TrustAgentService;
     43 import android.util.Log;
     44 import android.util.Slog;
     45 import java.util.Collections;
     46 import java.util.List;
     47 
     48 /**
     49  * A wrapper around a TrustAgentService interface. Coordinates communication between
     50  * TrustManager and the actual TrustAgent.
     51  */
     52 @TargetApi(Build.VERSION_CODES.LOLLIPOP)
     53 public class TrustAgentWrapper {
     54     private static final String EXTRA_COMPONENT_NAME = "componentName";
     55     private static final String TRUST_EXPIRED_ACTION = "android.server.trust.TRUST_EXPIRED_ACTION";
     56     private static final String PERMISSION = android.Manifest.permission.PROVIDE_TRUST_AGENT;
     57     private static final boolean DEBUG = TrustManagerService.DEBUG;
     58     private static final String TAG = "TrustAgentWrapper";
     59 
     60     private static final int MSG_GRANT_TRUST = 1;
     61     private static final int MSG_REVOKE_TRUST = 2;
     62     private static final int MSG_TRUST_TIMEOUT = 3;
     63     private static final int MSG_RESTART_TIMEOUT = 4;
     64     private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5;
     65     private static final int MSG_MANAGING_TRUST = 6;
     66     private static final int MSG_ADD_ESCROW_TOKEN = 7;
     67     private static final int MSG_REMOVE_ESCROW_TOKEN = 8;
     68     private static final int MSG_ESCROW_TOKEN_STATE = 9;
     69     private static final int MSG_UNLOCK_USER = 10;
     70 
     71     /**
     72      * Time in uptime millis that we wait for the service connection, both when starting
     73      * and when the service disconnects.
     74      */
     75     private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000;
     76 
     77     /**
     78      * Long extra for {@link #MSG_GRANT_TRUST}
     79      */
     80     private static final String DATA_DURATION = "duration";
     81     private static final String DATA_ESCROW_TOKEN = "escrow_token";
     82     private static final String DATA_HANDLE = "handle";
     83     private static final String DATA_USER_ID = "user_id";
     84 
     85     private final TrustManagerService mTrustManagerService;
     86     private final int mUserId;
     87     private final Context mContext;
     88     private final ComponentName mName;
     89 
     90     private ITrustAgentService mTrustAgentService;
     91     private boolean mBound;
     92     private long mScheduledRestartUptimeMillis;
     93     private long mMaximumTimeToLock; // from DevicePolicyManager
     94     private boolean mPendingSuccessfulUnlock = false;
     95 
     96     // Trust state
     97     private boolean mTrusted;
     98     private CharSequence mMessage;
     99     private boolean mTrustDisabledByDpm;
    100     private boolean mManagingTrust;
    101     private IBinder mSetTrustAgentFeaturesToken;
    102     private AlarmManager mAlarmManager;
    103     private final Intent mAlarmIntent;
    104     private PendingIntent mAlarmPendingIntent;
    105 
    106     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    107         @Override
    108         public void onReceive(Context context, Intent intent) {
    109             ComponentName component = intent.getParcelableExtra(EXTRA_COMPONENT_NAME);
    110             if (TRUST_EXPIRED_ACTION.equals(intent.getAction())
    111                     && mName.equals(component)) {
    112                 mHandler.removeMessages(MSG_TRUST_TIMEOUT);
    113                 mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
    114             }
    115         }
    116     };
    117 
    118     private final Handler mHandler = new Handler() {
    119         @Override
    120         public void handleMessage(Message msg) {
    121             switch (msg.what) {
    122                 case MSG_GRANT_TRUST:
    123                     if (!isConnected()) {
    124                         Log.w(TAG, "Agent is not connected, cannot grant trust: "
    125                                 + mName.flattenToShortString());
    126                         return;
    127                     }
    128                     mTrusted = true;
    129                     mMessage = (CharSequence) msg.obj;
    130                     int flags = msg.arg1;
    131                     long durationMs = msg.getData().getLong(DATA_DURATION);
    132                     if (durationMs > 0) {
    133                         final long duration;
    134                         if (mMaximumTimeToLock != 0) {
    135                             // Enforce DevicePolicyManager timeout.  This is here as a safeguard to
    136                             // ensure trust agents are evaluating trust state at least as often as
    137                             // the policy dictates. Admins that want more guarantees should be using
    138                             // DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS.
    139                             duration = Math.min(durationMs, mMaximumTimeToLock);
    140                             if (DEBUG) {
    141                                 Slog.d(TAG, "DPM lock timeout in effect. Timeout adjusted from "
    142                                     + durationMs + " to " + duration);
    143                             }
    144                         } else {
    145                             duration = durationMs;
    146                         }
    147                         long expiration = SystemClock.elapsedRealtime() + duration;
    148                         mAlarmPendingIntent = PendingIntent.getBroadcast(mContext, 0, mAlarmIntent,
    149                                 PendingIntent.FLAG_CANCEL_CURRENT);
    150                         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, expiration,
    151                                 mAlarmPendingIntent);
    152                     }
    153                     mTrustManagerService.mArchive.logGrantTrust(mUserId, mName,
    154                             (mMessage != null ? mMessage.toString() : null),
    155                             durationMs, flags);
    156                     mTrustManagerService.updateTrust(mUserId, flags);
    157                     break;
    158                 case MSG_TRUST_TIMEOUT:
    159                     if (DEBUG) Slog.d(TAG, "Trust timed out : " + mName.flattenToShortString());
    160                     mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName);
    161                     onTrustTimeout();
    162                     // Fall through.
    163                 case MSG_REVOKE_TRUST:
    164                     mTrusted = false;
    165                     mMessage = null;
    166                     mHandler.removeMessages(MSG_TRUST_TIMEOUT);
    167                     if (msg.what == MSG_REVOKE_TRUST) {
    168                         mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName);
    169                     }
    170                     mTrustManagerService.updateTrust(mUserId, 0);
    171                     break;
    172                 case MSG_RESTART_TIMEOUT:
    173                     Slog.w(TAG, "Connection attempt to agent " + mName.flattenToShortString()
    174                             + " timed out, rebinding");
    175                     destroy();
    176                     mTrustManagerService.resetAgent(mName, mUserId);
    177                     break;
    178                 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED:
    179                     IBinder token = (IBinder) msg.obj;
    180                     boolean result = msg.arg1 != 0;
    181                     if (mSetTrustAgentFeaturesToken == token) {
    182                         mSetTrustAgentFeaturesToken = null;
    183                         if (mTrustDisabledByDpm && result) {
    184                             if (DEBUG) Slog.d(TAG, "Re-enabling agent because it acknowledged "
    185                                     + "enabled features: " + mName.flattenToShortString());
    186                             mTrustDisabledByDpm = false;
    187                             mTrustManagerService.updateTrust(mUserId, 0);
    188                         }
    189                     } else {
    190                         if (DEBUG) Slog.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED "
    191                                 + "with obsolete token: " + mName.flattenToShortString());
    192                     }
    193                     break;
    194                 case MSG_MANAGING_TRUST:
    195                     mManagingTrust = msg.arg1 != 0;
    196                     if (!mManagingTrust) {
    197                         mTrusted = false;
    198                         mMessage = null;
    199                     }
    200                     mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust);
    201                     mTrustManagerService.updateTrust(mUserId, 0);
    202                     break;
    203                 case MSG_ADD_ESCROW_TOKEN: {
    204                     byte[] eToken = msg.getData().getByteArray(DATA_ESCROW_TOKEN);
    205                     int userId = msg.getData().getInt(DATA_USER_ID);
    206                     long handle = mTrustManagerService.addEscrowToken(eToken, userId);
    207                     boolean resultDeliverred = false;
    208                     try {
    209                         if (mTrustAgentService != null) {
    210                             mTrustAgentService.onEscrowTokenAdded(
    211                                     eToken, handle, UserHandle.of(userId));
    212                             resultDeliverred = true;
    213                         }
    214                     } catch (RemoteException e) {
    215                         onError(e);
    216                     }
    217 
    218                     if (!resultDeliverred) {
    219                         mTrustManagerService.removeEscrowToken(handle, userId);
    220                     }
    221                     break;
    222                 }
    223                 case MSG_ESCROW_TOKEN_STATE: {
    224                     long handle = msg.getData().getLong(DATA_HANDLE);
    225                     int userId = msg.getData().getInt(DATA_USER_ID);
    226                     boolean active = mTrustManagerService.isEscrowTokenActive(handle, userId);
    227                     try {
    228                         if (mTrustAgentService != null) {
    229                             mTrustAgentService.onTokenStateReceived(handle,
    230                                     active ? TrustAgentService.TOKEN_STATE_ACTIVE
    231                                             : TrustAgentService.TOKEN_STATE_INACTIVE);
    232                         }
    233                     } catch (RemoteException e) {
    234                         onError(e);
    235                     }
    236                     break;
    237                 }
    238                 case MSG_REMOVE_ESCROW_TOKEN: {
    239                     long handle = msg.getData().getLong(DATA_HANDLE);
    240                     int userId = msg.getData().getInt(DATA_USER_ID);
    241                     boolean success = mTrustManagerService.removeEscrowToken(handle, userId);
    242                     try {
    243                         if (mTrustAgentService != null) {
    244                             mTrustAgentService.onEscrowTokenRemoved(handle, success);
    245                         }
    246                     } catch (RemoteException e) {
    247                         onError(e);
    248                     }
    249                     break;
    250                 }
    251                 case MSG_UNLOCK_USER: {
    252                     long handle = msg.getData().getLong(DATA_HANDLE);
    253                     int userId = msg.getData().getInt(DATA_USER_ID);
    254                     byte[] eToken = msg.getData().getByteArray(DATA_ESCROW_TOKEN);
    255                     mTrustManagerService.unlockUserWithToken(handle, eToken, userId);
    256                     break;
    257                 }
    258             }
    259         }
    260     };
    261 
    262     private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() {
    263 
    264         @Override
    265         public void grantTrust(CharSequence userMessage, long durationMs, int flags) {
    266             if (DEBUG) Slog.d(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs
    267                         + ", flags = " + flags + ")");
    268 
    269             Message msg = mHandler.obtainMessage(
    270                     MSG_GRANT_TRUST, flags, 0, userMessage);
    271             msg.getData().putLong(DATA_DURATION, durationMs);
    272             msg.sendToTarget();
    273         }
    274 
    275         @Override
    276         public void revokeTrust() {
    277             if (DEBUG) Slog.d(TAG, "revokeTrust()");
    278             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    279         }
    280 
    281         @Override
    282         public void setManagingTrust(boolean managingTrust) {
    283             if (DEBUG) Slog.d(TAG, "managingTrust()");
    284             mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget();
    285         }
    286 
    287         @Override
    288         public void onConfigureCompleted(boolean result, IBinder token) {
    289             if (DEBUG) Slog.d(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result);
    290             mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED,
    291                     result ? 1 : 0, 0, token).sendToTarget();
    292         }
    293 
    294         @Override
    295         public void addEscrowToken(byte[] token, int userId) {
    296             if (mContext.getResources()
    297                     .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
    298                 throw  new SecurityException("Escrow token API is not allowed.");
    299             }
    300 
    301             if (DEBUG) Slog.d(TAG, "adding escrow token for user " + userId);
    302             Message msg = mHandler.obtainMessage(MSG_ADD_ESCROW_TOKEN);
    303             msg.getData().putByteArray(DATA_ESCROW_TOKEN, token);
    304             msg.getData().putInt(DATA_USER_ID, userId);
    305             msg.sendToTarget();
    306         }
    307 
    308         @Override
    309         public void isEscrowTokenActive(long handle, int userId) {
    310             if (mContext.getResources()
    311                     .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
    312                 throw new SecurityException("Escrow token API is not allowed.");
    313             }
    314 
    315             if (DEBUG) Slog.d(TAG, "checking the state of escrow token on user " + userId);
    316             Message msg = mHandler.obtainMessage(MSG_ESCROW_TOKEN_STATE);
    317             msg.getData().putLong(DATA_HANDLE, handle);
    318             msg.getData().putInt(DATA_USER_ID, userId);
    319             msg.sendToTarget();
    320         }
    321 
    322         @Override
    323         public void removeEscrowToken(long handle, int userId) {
    324             if (mContext.getResources()
    325                     .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
    326                 throw new SecurityException("Escrow token API is not allowed.");
    327             }
    328 
    329             if (DEBUG) Slog.d(TAG, "removing escrow token on user " + userId);
    330             Message msg = mHandler.obtainMessage(MSG_REMOVE_ESCROW_TOKEN);
    331             msg.getData().putLong(DATA_HANDLE, handle);
    332             msg.getData().putInt(DATA_USER_ID, userId);
    333             msg.sendToTarget();
    334         }
    335 
    336         @Override
    337         public void unlockUserWithToken(long handle, byte[] token, int userId) {
    338             if (mContext.getResources()
    339                     .getBoolean(com.android.internal.R.bool.config_allowEscrowTokenForTrustAgent)) {
    340                 throw new SecurityException("Escrow token API is not allowed.");
    341             }
    342 
    343             if (DEBUG) Slog.d(TAG, "unlocking user " + userId);
    344             Message msg = mHandler.obtainMessage(MSG_UNLOCK_USER);
    345             msg.getData().putInt(DATA_USER_ID, userId);
    346             msg.getData().putLong(DATA_HANDLE, handle);
    347             msg.getData().putByteArray(DATA_ESCROW_TOKEN, token);
    348             msg.sendToTarget();
    349         }
    350     };
    351 
    352     private final ServiceConnection mConnection = new ServiceConnection() {
    353         @Override
    354         public void onServiceConnected(ComponentName name, IBinder service) {
    355             if (DEBUG) Slog.d(TAG, "TrustAgent started : " + name.flattenToString());
    356             mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    357             mTrustAgentService = ITrustAgentService.Stub.asInterface(service);
    358             mTrustManagerService.mArchive.logAgentConnected(mUserId, name);
    359             setCallback(mCallback);
    360             updateDevicePolicyFeatures();
    361 
    362             if (mPendingSuccessfulUnlock) {
    363                 onUnlockAttempt(true);
    364                 mPendingSuccessfulUnlock = false;
    365             }
    366 
    367             if (mTrustManagerService.isDeviceLockedInner(mUserId)) {
    368                 onDeviceLocked();
    369             } else {
    370                 onDeviceUnlocked();
    371             }
    372         }
    373 
    374         @Override
    375         public void onServiceDisconnected(ComponentName name) {
    376             if (DEBUG) Slog.d(TAG, "TrustAgent disconnected : " + name.flattenToShortString());
    377             mTrustAgentService = null;
    378             mManagingTrust = false;
    379             mSetTrustAgentFeaturesToken = null;
    380             mTrustManagerService.mArchive.logAgentDied(mUserId, name);
    381             mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    382             if (mBound) {
    383                 scheduleRestart();
    384             }
    385             // mTrustDisabledByDpm maintains state
    386         }
    387     };
    388 
    389     public TrustAgentWrapper(Context context, TrustManagerService trustManagerService,
    390             Intent intent, UserHandle user) {
    391         mContext = context;
    392         mTrustManagerService = trustManagerService;
    393         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
    394         mUserId = user.getIdentifier();
    395         mName = intent.getComponent();
    396 
    397         mAlarmIntent = new Intent(TRUST_EXPIRED_ACTION).putExtra(EXTRA_COMPONENT_NAME, mName);
    398         mAlarmIntent.setData(Uri.parse(mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME)));
    399         mAlarmIntent.setPackage(context.getPackageName());
    400 
    401         final IntentFilter alarmFilter = new IntentFilter(TRUST_EXPIRED_ACTION);
    402         alarmFilter.addDataScheme(mAlarmIntent.getScheme());
    403         final String pathUri = mAlarmIntent.toUri(Intent.URI_INTENT_SCHEME);
    404         alarmFilter.addDataPath(pathUri, PatternMatcher.PATTERN_LITERAL);
    405 
    406         // Schedules a restart for when connecting times out. If the connection succeeds,
    407         // the restart is canceled in mCallback's onConnected.
    408         scheduleRestart();
    409         mBound = context.bindServiceAsUser(intent, mConnection,
    410                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE, user);
    411         if (mBound) {
    412             mContext.registerReceiver(mBroadcastReceiver, alarmFilter, PERMISSION, null);
    413         } else {
    414             Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString());
    415         }
    416     }
    417 
    418     private void onError(Exception e) {
    419         Slog.w(TAG , "Exception ", e);
    420     }
    421 
    422     private void onTrustTimeout() {
    423         try {
    424             if (mTrustAgentService != null) mTrustAgentService.onTrustTimeout();
    425         } catch (RemoteException e) {
    426             onError(e);
    427         }
    428     }
    429 
    430     /**
    431      * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean)
    432      */
    433     public void onUnlockAttempt(boolean successful) {
    434         try {
    435             if (mTrustAgentService != null) {
    436                 mTrustAgentService.onUnlockAttempt(successful);
    437             } else {
    438                 mPendingSuccessfulUnlock = successful;
    439             }
    440         } catch (RemoteException e) {
    441             onError(e);
    442         }
    443     }
    444 
    445     /**
    446      * @see android.service.trust.TrustAgentService#onUnlockLockout(int)
    447      */
    448     public void onUnlockLockout(int timeoutMs) {
    449         try {
    450             if (mTrustAgentService != null) {
    451                 mTrustAgentService.onUnlockLockout(timeoutMs);
    452             }
    453         } catch (RemoteException e) {
    454             onError(e);
    455         }
    456     }
    457 
    458     /**
    459      * @see android.service.trust.TrustAgentService#onDeviceLocked()
    460      */
    461     public void onDeviceLocked() {
    462         try {
    463             if (mTrustAgentService != null) mTrustAgentService.onDeviceLocked();
    464         } catch (RemoteException e) {
    465             onError(e);
    466         }
    467     }
    468 
    469     /**
    470      * @see android.service.trust.TrustAgentService#onDeviceUnlocked()
    471      */
    472     public void onDeviceUnlocked() {
    473         try {
    474             if (mTrustAgentService != null) mTrustAgentService.onDeviceUnlocked();
    475         } catch (RemoteException e) {
    476             onError(e);
    477         }
    478     }
    479 
    480     private void setCallback(ITrustAgentServiceCallback callback) {
    481         try {
    482             if (mTrustAgentService != null) {
    483                 mTrustAgentService.setCallback(callback);
    484             }
    485         } catch (RemoteException e) {
    486             onError(e);
    487         }
    488     }
    489 
    490     boolean updateDevicePolicyFeatures() {
    491         boolean trustDisabled = false;
    492         if (DEBUG) Slog.d(TAG, "updateDevicePolicyFeatures(" + mName + ")");
    493         try {
    494             if (mTrustAgentService != null) {
    495                 DevicePolicyManager dpm =
    496                     (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
    497 
    498                 if ((dpm.getKeyguardDisabledFeatures(null, mUserId)
    499                         & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) {
    500                     List<PersistableBundle> config = dpm.getTrustAgentConfiguration(
    501                             null, mName, mUserId);
    502                     trustDisabled = true;
    503                     if (DEBUG) Slog.d(TAG, "Detected trust agents disabled. Config = " + config);
    504                     if (config != null && config.size() > 0) {
    505                         if (DEBUG) {
    506                             Slog.d(TAG, "TrustAgent " + mName.flattenToShortString()
    507                                     + " disabled until it acknowledges "+ config);
    508                         }
    509                         mSetTrustAgentFeaturesToken = new Binder();
    510                         mTrustAgentService.onConfigure(config, mSetTrustAgentFeaturesToken);
    511                     }
    512                 } else {
    513                     mTrustAgentService.onConfigure(Collections.EMPTY_LIST, null);
    514                 }
    515                 final long maxTimeToLock = dpm.getMaximumTimeToLockForUserAndProfiles(mUserId);
    516                 if (maxTimeToLock != mMaximumTimeToLock) {
    517                     // If the timeout changes, cancel the alarm and send a timeout event to have
    518                     // the agent re-evaluate trust.
    519                     mMaximumTimeToLock = maxTimeToLock;
    520                     if (mAlarmPendingIntent != null) {
    521                         mAlarmManager.cancel(mAlarmPendingIntent);
    522                         mAlarmPendingIntent = null;
    523                         mHandler.sendEmptyMessage(MSG_TRUST_TIMEOUT);
    524                     }
    525                 }
    526             }
    527         } catch (RemoteException e) {
    528             onError(e);
    529         }
    530         if (mTrustDisabledByDpm != trustDisabled) {
    531             mTrustDisabledByDpm = trustDisabled;
    532             mTrustManagerService.updateTrust(mUserId, 0);
    533         }
    534         return trustDisabled;
    535     }
    536 
    537     public boolean isTrusted() {
    538         return mTrusted && mManagingTrust && !mTrustDisabledByDpm;
    539     }
    540 
    541     public boolean isManagingTrust() {
    542         return mManagingTrust && !mTrustDisabledByDpm;
    543     }
    544 
    545     public CharSequence getMessage() {
    546         return mMessage;
    547     }
    548 
    549     public void destroy() {
    550         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    551 
    552         if (!mBound) {
    553             return;
    554         }
    555         if (DEBUG) Slog.d(TAG, "TrustAgent unbound : " + mName.flattenToShortString());
    556         mTrustManagerService.mArchive.logAgentStopped(mUserId, mName);
    557         mContext.unbindService(mConnection);
    558         mBound = false;
    559         mContext.unregisterReceiver(mBroadcastReceiver);
    560         mTrustAgentService = null;
    561         mSetTrustAgentFeaturesToken = null;
    562         mHandler.sendEmptyMessage(MSG_REVOKE_TRUST);
    563     }
    564 
    565     public boolean isConnected() {
    566         return mTrustAgentService != null;
    567     }
    568 
    569     public boolean isBound() {
    570         return mBound;
    571     }
    572 
    573     /**
    574      * If not connected, returns the time at which the agent is restarted.
    575      *
    576      * @return restart time in uptime millis.
    577      */
    578     public long getScheduledRestartUptimeMillis() {
    579         return mScheduledRestartUptimeMillis;
    580     }
    581 
    582     private void scheduleRestart() {
    583         mHandler.removeMessages(MSG_RESTART_TIMEOUT);
    584         mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS;
    585         mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis);
    586     }
    587 }
    588