TrustAgentWrapper.java revision 3c9a3501651aa8ad4f289e89119a6c0b4bdaf78a
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.admin.DevicePolicyManager; 20import android.content.ComponentName; 21import android.content.Context; 22import android.content.Intent; 23import android.content.ServiceConnection; 24import android.os.Binder; 25import android.os.Bundle; 26import android.os.Handler; 27import android.os.IBinder; 28import android.os.Message; 29import android.os.RemoteException; 30import android.os.SystemClock; 31import android.os.UserHandle; 32import android.util.Log; 33import android.util.Slog; 34import android.service.trust.ITrustAgentService; 35import android.service.trust.ITrustAgentServiceCallback; 36import android.service.trust.TrustAgentService; 37 38import java.util.ArrayList; 39import java.util.List; 40 41/** 42 * A wrapper around a TrustAgentService interface. Coordinates communication between 43 * TrustManager and the actual TrustAgent. 44 */ 45public class TrustAgentWrapper { 46 private static final boolean DEBUG = false; 47 private static final String TAG = "TrustAgentWrapper"; 48 49 private static final int MSG_GRANT_TRUST = 1; 50 private static final int MSG_REVOKE_TRUST = 2; 51 private static final int MSG_TRUST_TIMEOUT = 3; 52 private static final int MSG_RESTART_TIMEOUT = 4; 53 private static final int MSG_SET_TRUST_AGENT_FEATURES_COMPLETED = 5; 54 private static final int MSG_MANAGING_TRUST = 6; 55 56 /** 57 * Time in uptime millis that we wait for the service connection, both when starting 58 * and when the service disconnects. 59 */ 60 private static final long RESTART_TIMEOUT_MILLIS = 5 * 60000; 61 62 /** 63 * Long extra for {@link #MSG_GRANT_TRUST} 64 */ 65 private static final String DATA_DURATION = "duration"; 66 67 private final TrustManagerService mTrustManagerService; 68 private final int mUserId; 69 private final Context mContext; 70 private final ComponentName mName; 71 72 private ITrustAgentService mTrustAgentService; 73 private boolean mBound; 74 private long mScheduledRestartUptimeMillis; 75 76 // Trust state 77 private boolean mTrusted; 78 private CharSequence mMessage; 79 private boolean mTrustDisabledByDpm; 80 private boolean mManagingTrust; 81 private IBinder mSetTrustAgentFeaturesToken; 82 83 private final Handler mHandler = new Handler() { 84 @Override 85 public void handleMessage(Message msg) { 86 switch (msg.what) { 87 case MSG_GRANT_TRUST: 88 if (!isConnected()) { 89 Log.w(TAG, "Agent is not connected, cannot grant trust: " 90 + mName.flattenToShortString()); 91 return; 92 } 93 mTrusted = true; 94 mMessage = (CharSequence) msg.obj; 95 boolean initiatedByUser = msg.arg1 != 0; 96 long durationMs = msg.getData().getLong(DATA_DURATION); 97 if (durationMs > 0) { 98 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 99 mHandler.sendEmptyMessageDelayed(MSG_TRUST_TIMEOUT, durationMs); 100 } 101 mTrustManagerService.mArchive.logGrantTrust(mUserId, mName, 102 (mMessage != null ? mMessage.toString() : null), 103 durationMs, initiatedByUser); 104 mTrustManagerService.updateTrust(mUserId, initiatedByUser); 105 break; 106 case MSG_TRUST_TIMEOUT: 107 if (DEBUG) Slog.v(TAG, "Trust timed out : " + mName.flattenToShortString()); 108 mTrustManagerService.mArchive.logTrustTimeout(mUserId, mName); 109 // Fall through. 110 case MSG_REVOKE_TRUST: 111 mTrusted = false; 112 mMessage = null; 113 mHandler.removeMessages(MSG_TRUST_TIMEOUT); 114 if (msg.what == MSG_REVOKE_TRUST) { 115 mTrustManagerService.mArchive.logRevokeTrust(mUserId, mName); 116 } 117 mTrustManagerService.updateTrust(mUserId, false); 118 break; 119 case MSG_RESTART_TIMEOUT: 120 unbind(); 121 mTrustManagerService.resetAgent(mName, mUserId); 122 break; 123 case MSG_SET_TRUST_AGENT_FEATURES_COMPLETED: 124 IBinder token = (IBinder) msg.obj; 125 boolean result = msg.arg1 != 0; 126 if (mSetTrustAgentFeaturesToken == token) { 127 mSetTrustAgentFeaturesToken = null; 128 if (mTrustDisabledByDpm && result) { 129 if (DEBUG) Log.v(TAG, "Re-enabling agent because it acknowledged " 130 + "enabled features: " + mName); 131 mTrustDisabledByDpm = false; 132 mTrustManagerService.updateTrust(mUserId, false); 133 } 134 } else { 135 if (DEBUG) Log.w(TAG, "Ignoring MSG_SET_TRUST_AGENT_FEATURES_COMPLETED " 136 + "with obsolete token: " + mName); 137 } 138 break; 139 case MSG_MANAGING_TRUST: 140 mManagingTrust = msg.arg1 != 0; 141 if (!mManagingTrust) { 142 mTrusted = false; 143 mMessage = null; 144 } 145 mTrustManagerService.mArchive.logManagingTrust(mUserId, mName, mManagingTrust); 146 mTrustManagerService.updateTrust(mUserId, false); 147 break; 148 } 149 } 150 }; 151 152 private ITrustAgentServiceCallback mCallback = new ITrustAgentServiceCallback.Stub() { 153 154 @Override 155 public void grantTrust(CharSequence userMessage, long durationMs, boolean initiatedByUser) { 156 if (DEBUG) Slog.v(TAG, "enableTrust(" + userMessage + ", durationMs = " + durationMs 157 + ", initiatedByUser = " + initiatedByUser + ")"); 158 159 Message msg = mHandler.obtainMessage( 160 MSG_GRANT_TRUST, initiatedByUser ? 1 : 0, 0, userMessage); 161 msg.getData().putLong(DATA_DURATION, durationMs); 162 msg.sendToTarget(); 163 } 164 165 @Override 166 public void revokeTrust() { 167 if (DEBUG) Slog.v(TAG, "revokeTrust()"); 168 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 169 } 170 171 @Override 172 public void setManagingTrust(boolean managingTrust) { 173 if (DEBUG) Slog.v(TAG, "managingTrust()"); 174 mHandler.obtainMessage(MSG_MANAGING_TRUST, managingTrust ? 1 : 0, 0).sendToTarget(); 175 } 176 177 @Override 178 public void onSetTrustAgentFeaturesEnabledCompleted(boolean result, IBinder token) { 179 if (DEBUG) Slog.v(TAG, "onSetTrustAgentFeaturesEnabledCompleted(result=" + result); 180 mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_COMPLETED, 181 result ? 1 : 0, 0, token).sendToTarget(); 182 } 183 }; 184 185 private final ServiceConnection mConnection = new ServiceConnection() { 186 @Override 187 public void onServiceConnected(ComponentName name, IBinder service) { 188 if (DEBUG) Log.v(TAG, "TrustAgent started : " + name.flattenToString()); 189 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 190 mTrustAgentService = ITrustAgentService.Stub.asInterface(service); 191 mTrustManagerService.mArchive.logAgentConnected(mUserId, name); 192 setCallback(mCallback); 193 updateDevicePolicyFeatures(); 194 } 195 196 @Override 197 public void onServiceDisconnected(ComponentName name) { 198 if (DEBUG) Log.v(TAG, "TrustAgent disconnected : " + name.flattenToShortString()); 199 mTrustAgentService = null; 200 mManagingTrust = false; 201 mSetTrustAgentFeaturesToken = null; 202 mTrustManagerService.mArchive.logAgentDied(mUserId, name); 203 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 204 if (mBound) { 205 scheduleRestart(); 206 } 207 // mTrustDisabledByDpm maintains state 208 } 209 }; 210 211 public TrustAgentWrapper(Context context, TrustManagerService trustManagerService, 212 Intent intent, UserHandle user) { 213 mContext = context; 214 mTrustManagerService = trustManagerService; 215 mUserId = user.getIdentifier(); 216 mName = intent.getComponent(); 217 // Schedules a restart for when connecting times out. If the connection succeeds, 218 // the restart is canceled in mCallback's onConnected. 219 scheduleRestart(); 220 mBound = context.bindServiceAsUser(intent, mConnection, Context.BIND_AUTO_CREATE, user); 221 if (!mBound) { 222 Log.e(TAG, "Can't bind to TrustAgent " + mName.flattenToShortString()); 223 } 224 } 225 226 private void onError(Exception e) { 227 Slog.w(TAG , "Remote Exception", e); 228 } 229 230 /** 231 * @see android.service.trust.TrustAgentService#onUnlockAttempt(boolean) 232 */ 233 public void onUnlockAttempt(boolean successful) { 234 try { 235 if (mTrustAgentService != null) mTrustAgentService.onUnlockAttempt(successful); 236 } catch (RemoteException e) { 237 onError(e); 238 } 239 } 240 241 private void setCallback(ITrustAgentServiceCallback callback) { 242 try { 243 if (mTrustAgentService != null) { 244 mTrustAgentService.setCallback(callback); 245 } 246 } catch (RemoteException e) { 247 onError(e); 248 } 249 } 250 251 boolean updateDevicePolicyFeatures() { 252 boolean trustDisabled = false; 253 if (DEBUG) Slog.v(TAG, "updateDevicePolicyFeatures(" + mName + ")"); 254 try { 255 if (mTrustAgentService != null) { 256 DevicePolicyManager dpm = 257 (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); 258 259 if ((dpm.getKeyguardDisabledFeatures(null) 260 & DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS) != 0) { 261 List<String> features = dpm.getTrustAgentFeaturesEnabled(null, mName); 262 trustDisabled = true; 263 if (DEBUG) Slog.v(TAG, "Detected trust agents disabled. Features = " 264 + features); 265 if (features != null && features.size() > 0) { 266 Bundle bundle = new Bundle(); 267 bundle.putStringArrayList(TrustAgentService.KEY_FEATURES, 268 (ArrayList<String>)features); 269 if (DEBUG) { 270 Slog.v(TAG, "TrustAgent " + mName.flattenToShortString() 271 + " disabled until it acknowledges "+ features); 272 } 273 mSetTrustAgentFeaturesToken = new Binder(); 274 mTrustAgentService.setTrustAgentFeaturesEnabled(bundle, 275 mSetTrustAgentFeaturesToken); 276 } 277 } 278 } 279 } catch (RemoteException e) { 280 onError(e); 281 } 282 if (mTrustDisabledByDpm != trustDisabled) { 283 mTrustDisabledByDpm = trustDisabled; 284 mTrustManagerService.updateTrust(mUserId, false); 285 } 286 return trustDisabled; 287 } 288 289 public boolean isTrusted() { 290 return mTrusted && mManagingTrust && !mTrustDisabledByDpm; 291 } 292 293 public boolean isManagingTrust() { 294 return mManagingTrust && !mTrustDisabledByDpm; 295 } 296 297 public CharSequence getMessage() { 298 return mMessage; 299 } 300 301 public void unbind() { 302 if (!mBound) { 303 return; 304 } 305 if (DEBUG) Log.v(TAG, "TrustAgent unbound : " + mName.flattenToShortString()); 306 mTrustManagerService.mArchive.logAgentStopped(mUserId, mName); 307 mContext.unbindService(mConnection); 308 mBound = false; 309 mTrustAgentService = null; 310 mSetTrustAgentFeaturesToken = null; 311 mHandler.sendEmptyMessage(MSG_REVOKE_TRUST); 312 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 313 } 314 315 public boolean isConnected() { 316 return mTrustAgentService != null; 317 } 318 319 public boolean isBound() { 320 return mBound; 321 } 322 323 /** 324 * If not connected, returns the time at which the agent is restarted. 325 * 326 * @return restart time in uptime millis. 327 */ 328 public long getScheduledRestartUptimeMillis() { 329 return mScheduledRestartUptimeMillis; 330 } 331 332 private void scheduleRestart() { 333 mHandler.removeMessages(MSG_RESTART_TIMEOUT); 334 mScheduledRestartUptimeMillis = SystemClock.uptimeMillis() + RESTART_TIMEOUT_MILLIS; 335 mHandler.sendEmptyMessageAtTime(MSG_RESTART_TIMEOUT, mScheduledRestartUptimeMillis); 336 } 337} 338