TrustAgentService.java revision 4f22777efb6dc99b61c664b39b4087fe89f0c050
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.app.Service;
22import android.content.ComponentName;
23import android.content.Intent;
24import android.content.pm.PackageManager;
25import android.content.pm.ServiceInfo;
26import android.os.Handler;
27import android.os.IBinder;
28import android.os.RemoteException;
29import android.util.Log;
30import android.util.Slog;
31
32/**
33 * A service that notifies the system about whether it believes the environment of the device
34 * to be trusted.
35 *
36 * <p>Trust agents may only be provided by the platform.</p>
37 *
38 * <p>To extend this class, you must declare the service in your manifest file with
39 * the {@link android.Manifest.permission#BIND_TRUST_AGENT} permission
40 * and include an intent filter with the {@link #SERVICE_INTERFACE} action. For example:</p>
41 * <pre>
42 * &lt;service android:name=".TrustAgent"
43 *          android:label="&#64;string/service_name"
44 *          android:permission="android.permission.BIND_TRUST_AGENT">
45 *     &lt;intent-filter>
46 *         &lt;action android:name="android.service.trust.TrustAgentService" />
47 *     &lt;/intent-filter>
48 *     &lt;meta-data android:name="android.service.trust.trustagent"
49 *          android:value="&#64;xml/trust_agent" />
50 * &lt;/service></pre>
51 *
52 * <p>The associated meta-data file can specify an activity that is accessible through Settings
53 * and should allow configuring the trust agent, as defined in
54 * {@link android.R.styleable#TrustAgent}. For example:</p>
55 *
56 * <pre>
57 * &lt;trust-agent xmlns:android="http://schemas.android.com/apk/res/android"
58 *          android:settingsActivity=".TrustAgentSettings" /></pre>
59 */
60public class TrustAgentService extends Service {
61    private final String TAG = TrustAgentService.class.getSimpleName() +
62            "[" + getClass().getSimpleName() + "]";
63
64    /**
65     * The {@link Intent} that must be declared as handled by the service.
66     */
67    @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
68    public static final String SERVICE_INTERFACE
69            = "android.service.trust.TrustAgentService";
70
71    /**
72     * The name of the {@code meta-data} tag pointing to additional configuration of the trust
73     * agent.
74     */
75    public static final String TRUST_AGENT_META_DATA = "android.service.trust.trustagent";
76
77    private static final int MSG_UNLOCK_ATTEMPT = 1;
78
79    private static final boolean DEBUG = false;
80
81    private ITrustAgentServiceCallback mCallback;
82
83    private Runnable mPendingGrantTrustTask;
84
85    // Lock used to access mPendingGrantTrustTask and mCallback.
86    private final Object mLock = new Object();
87
88    private Handler mHandler = new Handler() {
89        public void handleMessage(android.os.Message msg) {
90            switch (msg.what) {
91                case MSG_UNLOCK_ATTEMPT:
92                    onUnlockAttempt(msg.arg1 != 0);
93                    break;
94            }
95        };
96    };
97
98    @Override
99    public void onCreate() {
100        super.onCreate();
101        ComponentName component = new ComponentName(this, getClass());
102        try {
103            ServiceInfo serviceInfo = getPackageManager().getServiceInfo(component, 0 /* flags */);
104            if (!Manifest.permission.BIND_TRUST_AGENT.equals(serviceInfo.permission)) {
105                throw new IllegalStateException(component.flattenToShortString()
106                        + " is not declared with the permission "
107                        + "\"" + Manifest.permission.BIND_TRUST_AGENT + "\"");
108            }
109        } catch (PackageManager.NameNotFoundException e) {
110            Log.e(TAG, "Can't get ServiceInfo for " + component.toShortString());
111        }
112    }
113
114    /**
115     * Called when the user attempted to authenticate on the device.
116     *
117     * @param successful true if the attempt succeeded
118     */
119    public void onUnlockAttempt(boolean successful) {
120    }
121
122    private void onError(String msg) {
123        Slog.v(TAG, "Remote exception while " + msg);
124    }
125
126    /**
127     * Call to grant trust on the device.
128     *
129     * @param message describes why the device is trusted, e.g. "Trusted by location".
130     * @param durationMs amount of time in milliseconds to keep the device in a trusted state. Trust
131     *                   for this agent will automatically be revoked when the timeout expires.
132     * @param initiatedByUser indicates that the user has explicitly initiated an action that proves
133     *                        the user is about to use the device.
134     */
135    public final void grantTrust(
136            final CharSequence message, final long durationMs, final boolean initiatedByUser) {
137        synchronized (mLock) {
138            if (mCallback != null) {
139                try {
140                    mCallback.grantTrust(message.toString(), durationMs, initiatedByUser);
141                } catch (RemoteException e) {
142                    onError("calling enableTrust()");
143                }
144            } else {
145                // Remember trust has been granted so we can effectively grant it once the service
146                // is bound.
147                mPendingGrantTrustTask = new Runnable() {
148                    @Override
149                    public void run() {
150                        grantTrust(message, durationMs, initiatedByUser);
151                    }
152                };
153            }
154        }
155    }
156
157    /**
158     * Call to revoke trust on the device.
159     */
160    public final void revokeTrust() {
161        synchronized (mLock) {
162            if (mPendingGrantTrustTask != null) {
163                mPendingGrantTrustTask = null;
164            }
165            if (mCallback != null) {
166                try {
167                    mCallback.revokeTrust();
168                } catch (RemoteException e) {
169                    onError("calling revokeTrust()");
170                }
171            }
172        }
173    }
174
175    @Override
176    public final IBinder onBind(Intent intent) {
177        if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
178        return new TrustAgentServiceWrapper();
179    }
180
181    private final class TrustAgentServiceWrapper extends ITrustAgentService.Stub {
182        @Override
183        public void onUnlockAttempt(boolean successful) {
184            mHandler.obtainMessage(MSG_UNLOCK_ATTEMPT, successful ? 1 : 0, 0)
185                    .sendToTarget();
186        }
187
188        public void setCallback(ITrustAgentServiceCallback callback) {
189            synchronized (mLock) {
190                mCallback = callback;
191                if (mPendingGrantTrustTask != null) {
192                    mPendingGrantTrustTask.run();
193                    mPendingGrantTrustTask = null;
194                }
195            }
196        }
197    }
198
199}
200