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