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