TrustAgentService.java revision 8f21158fe64eb93ff005dc1b831b282b95531023
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 android.service.trust;
18
19import android.Manifest;
20import android.annotation.SdkConstant;
21import android.annotation.SystemApi;
22import android.app.Service;
23import android.app.admin.DevicePolicyManager;
24import android.content.ComponentName;
25import android.content.Intent;
26import android.content.pm.PackageManager;
27import android.content.pm.ServiceInfo;
28import android.os.Bundle;
29import android.os.Handler;
30import android.os.IBinder;
31import android.os.Message;
32import android.os.RemoteException;
33import android.util.Log;
34import android.util.Slog;
35
36/**
37 * A service that notifies the system about whether it believes the environment of the device
38 * to be trusted.
39 *
40 * <p>Trust agents may only be provided by the platform.</p>
41 *
42 * <p>To extend this class, you must declare the service in your manifest file with
43 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
44 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
45 * <pre>
46 * &lt;service android:name=".TrustAgent"
47 *          android:label="&#64;string/service_name"
48 *          android:permission="android.permission.BIND_TRUST_AGENT">
49 *     &lt;intent-filter>
50 *         &lt;action android:name="android.service.trust.TrustAgentService" />
51 *     &lt;/intent-filter>
52 *     &lt;meta-data android:name="android.service.trust.trustagent"
53 *          android:value="&#64;xml/trust_agent" />
54 * &lt;/service></pre>
55 *
56 * <p>The associated meta-data file can specify an activity that is accessible through Settings
57 * and should allow configuring the trust agent, as defined in
58 * {@link android.R.styleable#TrustAgent}. For example:</p>
59 *
60 * <pre>
61 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
62 *          android:settingsActivity=".TrustAgentSettings" /></pre>
63 *
64 * @hide
65 */
66@SystemApi
67public class TrustAgentService extends Service {
68    private final String TAG = TrustAgentService.class.getSimpleName() +
69            "[" + getClass().getSimpleName() + "]";
70    private static final boolean DEBUG = false;
71
72    // Temporary workaround to allow current trust agent implementations to continue working.
73    // This and the code guarded by this should be removed before shipping.
74    // If true, calls setManagingTrust(true) after onCreate, if it wasn't already set.
75    // TODO: Remove this once all agents are updated.
76    private static final boolean SET_MANAGED_FOR_LEGACY_AGENTS = true;
77
78    /**
79     * The {@link Intent} that must be declared as handled by the service.
80     */
81    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
82    public static final String SERVICE_INTERFACE
83            = "android.service.trust.TrustAgentService";
84
85    /**
86     * The name of the {@code meta-data} tag pointing to additional configuration of the trust
87     * agent.
88     */
89    public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
90
91    /**
92     * A white list of features that the given trust agent should support when otherwise disabled
93     * by device policy.
94     */
95    public static final String KEY_FEATURES = "trust_agent_features";
96
97    private static final int MSG_UNLOCK_ATTEMPT = 1;
98    private static final int MSG_SET_TRUST_AGENT_FEATURES_ENABLED = 2;
99
100    private ITrustAgentServiceCallback mCallback;
101
102    private Runnable mPendingGrantTrustTask;
103
104    private boolean mManagingTrust;
105
106    // Lock used to access mPendingGrantTrustTask and mCallback.
107    private final Object mLock = new Object();
108
109    private Handler mHandler = new Handler() {
110        public void handleMessage(android.os.Message msg) {
111            switch (msg.what) {
112                case MSG_UNLOCK_ATTEMPT:
113                    onUnlockAttempt(msg.arg1 != 0);
114                    break;
115                case MSG_SET_TRUST_AGENT_FEATURES_ENABLED:
116                    Bundle features = msg.peekData();
117                    IBinder token = (IBinder) msg.obj;
118                    boolean result = onSetTrustAgentFeaturesEnabled(features);
119                    try {
120                        synchronized (mLock) {
121                            mCallback.onSetTrustAgentFeaturesEnabledCompleted(result, token);
122                        }
123                    } catch (RemoteException e) {
124                        onError("calling onSetTrustAgentFeaturesEnabledCompleted()");
125                    }
126                    break;
127            }
128        }
129    };
130
131    @Override
132    public void onCreate() {
133        // TODO: Remove this once all agents are updated.
134        if (SET_MANAGED_FOR_LEGACY_AGENTS) {
135            setManagingTrust(true);
136        }
137
138        super.onCreate();
139        ComponentName component = new ComponentName(this, getClass());
140        try {
141            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
142            if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
143                throw new IllegalStateException(component.flattenToShortString()
144                        + " is not declared with the permission "
145                        + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
146            }
147        } catch (PackageManager.NameNotFoundException e) {
148            Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
149        }
150    }
151
152    /**
153     * Called when the user attempted to authenticate on the device.
154     *
155     * @param successful true if the attempt succeeded
156     */
157    public void onUnlockAttempt(boolean successful) {
158    }
159
160    private void onError(String msg) {
161        Slog.v(TAG, "Remote exception while " + msg);
162    }
163
164    /**
165     * Called when device policy wants to restrict features in the TrustAgent in response to
166     * {@link DevicePolicyManager#setTrustAgentFeaturesEnabled(ComponentName, ComponentName, java.util.List) }.
167     * TrustAgents that support this feature should overload this method and return 'true'.
168     *
169     * The list of options can be obtained by calling
170     * options.getStringArrayList({@link #KEY_FEATURES}). Presence of a feature string in the list
171     * means it should be enabled ("white-listed"). Absence of the feature means it should be
172     * disabled. An empty list means all features should be disabled.
173     *
174     * This function is only called if {@link DevicePolicyManager#KEYGUARD_DISABLE_TRUST_AGENTS} is
175     * set.
176     *
177     * @param options Option feature bundle.
178     * @return true if the {@link #TrustAgentService()} supports this feature.
179     */
180    public boolean onSetTrustAgentFeaturesEnabled(Bundle options) {
181        return false;
182    }
183
184    /**
185     * Call to grant trust on the device.
186     *
187     * @param message describes why the device is trusted, e.g. "Trusted by location".
188     * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
189     *                   for this agent will automatically be revoked when the timeout expires.
190     * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
191     *                        the user is about to use the device.
192     * @throws IllegalStateException if the agent is not currently managing trust.
193     */
194    public final void grantTrust(
195            final CharSequence message, final long durationMs, final boolean initiatedByUser) {
196        synchronized (mLock) {
197            if (!mManagingTrust) {
198                throw new IllegalStateException("Cannot grant trust if agent is not managing trust."
199                        + " Call setManagingTrust(true) first.");
200            }
201            if (mCallback != null) {
202                try {
203                    mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
204                } catch (RemoteException e) {
205                    onError("calling enableTrust()");
206                }
207            } else {
208                // Remember trust has been granted so we can effectively grant it once the service
209                // is bound.
210                mPendingGrantTrustTask = new Runnable() {
211                    @Override
212                    public void run() {
213                        grantTrust(message, durationMs, initiatedByUser);
214                    }
215                };
216            }
217        }
218    }
219
220    /**
221     * Call to revoke trust on the device.
222     */
223    public final void revokeTrust() {
224        synchronized (mLock) {
225            if (mPendingGrantTrustTask != null) {
226                mPendingGrantTrustTask = null;
227            }
228            if (mCallback != null) {
229                try {
230                    mCallback.revokeTrust();
231                } catch (RemoteException e) {
232                    onError("calling revokeTrust()");
233                }
234            }
235        }
236    }
237
238    /**
239     * Call to notify the system if the agent is ready to manage trust.
240     *
241     * This property is not persistent across recreating the service and defaults to false.
242     * Therefore this method is typically called when initializing the agent in {@link #onCreate}.
243     *
244     * @param managingTrust indicates if the agent would like to manage trust.
245     */
246    public final void setManagingTrust(boolean managingTrust) {
247        synchronized (mLock) {
248            if (mManagingTrust != managingTrust) {
249                mManagingTrust = managingTrust;
250                if (mCallback != null) {
251                    try {
252                        mCallback.setManagingTrust(managingTrust);
253                    } catch (RemoteException e) {
254                        onError("calling setManagingTrust()");
255                    }
256                }
257            }
258        }
259    }
260
261    @Override
262    public final IBinder onBind(Intent intent) {
263        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
264        return new TrustAgentServiceWrapper();
265    }
266
267    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
268        @Override
269        public void onUnlockAttempt(boolean successful) {
270            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
271                    .sendToTarget();
272        }
273
274        @Override
275        public void setCallback(ITrustAgentServiceCallback callback) {
276            synchronized (mLock) {
277                mCallback = callback;
278                // The managingTrust property is false implicitly on the server-side, so we only
279                // need to set it here if the agent has decided to manage trust.
280                if (mManagingTrust) {
281                    try {
282                        mCallback.setManagingTrust(mManagingTrust);
283                    } catch (RemoteException e ) {
284                        onError("calling setManagingTrust()");
285                    }
286                }
287                if (mPendingGrantTrustTask != null) {
288                    mPendingGrantTrustTask.run();
289                    mPendingGrantTrustTask = null;
290                }
291            }
292        }
293
294        @Override
295        public void setTrustAgentFeaturesEnabled(Bundle features, IBinder token) {
296            Message msg = mHandler.obtainMessage(MSG_SET_TRUST_AGENT_FEATURES_ENABLED, token);
297            msg.setData(features);
298            msg.sendToTarget();
299        }
300    }
301
302}
303