1 /*
2  * Copyright (C) 2021 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 android.service.displayhash;
18 
19 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
20 
21 import android.annotation.NonNull;
22 import android.annotation.Nullable;
23 import android.annotation.SystemApi;
24 import android.app.Service;
25 import android.content.Intent;
26 import android.graphics.Rect;
27 import android.hardware.HardwareBuffer;
28 import android.os.Bundle;
29 import android.os.Handler;
30 import android.os.IBinder;
31 import android.os.Looper;
32 import android.os.RemoteCallback;
33 import android.view.displayhash.DisplayHash;
34 import android.view.displayhash.DisplayHashResultCallback;
35 import android.view.displayhash.VerifiedDisplayHash;
36 
37 import java.util.Map;
38 
39 /**
40  * A service that handles generating and verify {@link DisplayHash}.
41  *
42  * The service will generate a DisplayHash based on arguments passed in. Then later that
43  * same DisplayHash can be verified to determine that it was created by the system.
44  *
45  * @hide
46  */
47 @SystemApi
48 public abstract class DisplayHashingService extends Service {
49 
50     /** @hide **/
51     public static final String EXTRA_VERIFIED_DISPLAY_HASH =
52             "android.service.displayhash.extra.VERIFIED_DISPLAY_HASH";
53 
54     /** @hide **/
55     public static final String EXTRA_INTERVAL_BETWEEN_REQUESTS =
56             "android.service.displayhash.extra.INTERVAL_BETWEEN_REQUESTS";
57 
58     /**
59      * The {@link Intent} action that must be declared as handled by a service in its manifest
60      * for the system to recognize it as a DisplayHash providing service.
61      *
62      * @hide
63      */
64     @SystemApi
65     public static final String SERVICE_INTERFACE =
66             "android.service.displayhash.DisplayHashingService";
67 
68     private DisplayHashingServiceWrapper mWrapper;
69     private Handler mHandler;
70 
DisplayHashingService()71     public DisplayHashingService() {
72     }
73 
74     @Override
onCreate()75     public void onCreate() {
76         super.onCreate();
77         mWrapper = new DisplayHashingServiceWrapper();
78         mHandler = new Handler(Looper.getMainLooper(), null, true);
79     }
80 
81     @NonNull
82     @Override
onBind(@onNull Intent intent)83     public final IBinder onBind(@NonNull Intent intent) {
84         return mWrapper;
85     }
86 
87     /**
88      * Generates the DisplayHash that can be used to validate that the system generated the
89      * token.
90      *
91      * @param salt          The salt to use when generating the hmac. This should be unique to the
92      *                      caller so the token cannot be verified by any other process.
93      * @param buffer        The buffer for the content to generate the hash for.
94      * @param bounds        The size and position of the content in window space.
95      * @param hashAlgorithm The String for the hashing algorithm to use based values in
96      *                      {@link #getDisplayHashAlgorithms(RemoteCallback)}.
97      * @param callback      The callback to invoke
98      *                      {@link DisplayHashResultCallback#onDisplayHashResult(DisplayHash)}
99      *                      if successfully generated a DisplayHash or {@link
100      *                      DisplayHashResultCallback#onDisplayHashError(int)} if failed.
101      */
onGenerateDisplayHash(@onNull byte[] salt, @NonNull HardwareBuffer buffer, @NonNull Rect bounds, @NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback)102     public abstract void onGenerateDisplayHash(@NonNull byte[] salt,
103             @NonNull HardwareBuffer buffer, @NonNull Rect bounds,
104             @NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback);
105 
106     /**
107      * Returns a map of supported algorithms and their {@link DisplayHashParams}
108      */
109     @NonNull
onGetDisplayHashAlgorithms()110     public abstract Map<String, DisplayHashParams> onGetDisplayHashAlgorithms();
111 
112     /**
113      * Call to verify that the DisplayHash passed in was generated by the system.
114      *
115      * @param salt        The salt value to use when verifying the hmac. This should be the
116      *                    same value that was passed to
117      *                    {@link #onGenerateDisplayHash(byte[],
118      *                    HardwareBuffer, Rect, String, DisplayHashResultCallback)} to
119      *                    generate the token.
120      * @param displayHash The token to verify that it was generated by the system.
121      * @return a {@link VerifiedDisplayHash} if the provided display hash was originally generated
122      * by the system or null if the system did not generate the display hash.
123      */
124     @Nullable
onVerifyDisplayHash(@onNull byte[] salt, @NonNull DisplayHash displayHash)125     public abstract VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[] salt,
126             @NonNull DisplayHash displayHash);
127 
verifyDisplayHash(byte[] salt, DisplayHash displayHash, RemoteCallback callback)128     private void verifyDisplayHash(byte[] salt, DisplayHash displayHash,
129             RemoteCallback callback) {
130         VerifiedDisplayHash verifiedDisplayHash = onVerifyDisplayHash(salt,
131                 displayHash);
132         final Bundle data = new Bundle();
133         data.putParcelable(EXTRA_VERIFIED_DISPLAY_HASH, verifiedDisplayHash);
134         callback.sendResult(data);
135     }
136 
getDisplayHashAlgorithms(RemoteCallback callback)137     private void getDisplayHashAlgorithms(RemoteCallback callback) {
138         Map<String, DisplayHashParams> displayHashParams = onGetDisplayHashAlgorithms();
139         final Bundle data = new Bundle();
140         for (Map.Entry<String, DisplayHashParams> entry : displayHashParams.entrySet()) {
141             data.putParcelable(entry.getKey(), entry.getValue());
142         }
143         callback.sendResult(data);
144     }
145 
146     /**
147      * Call to get the interval required between display hash requests. Requests made faster than
148      * this will be throttled.
149      *
150      * @return the interval value required between requests.
151      */
onGetIntervalBetweenRequestsMillis()152     public abstract int onGetIntervalBetweenRequestsMillis();
153 
getDurationBetweenRequestsMillis(RemoteCallback callback)154     private void getDurationBetweenRequestsMillis(RemoteCallback callback) {
155         int durationBetweenRequestMillis = onGetIntervalBetweenRequestsMillis();
156         Bundle data = new Bundle();
157         data.putInt(EXTRA_INTERVAL_BETWEEN_REQUESTS, durationBetweenRequestMillis);
158         callback.sendResult(data);
159     }
160 
161     private final class DisplayHashingServiceWrapper extends IDisplayHashingService.Stub {
162         @Override
generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds, String hashAlgorithm, RemoteCallback callback)163         public void generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds,
164                 String hashAlgorithm, RemoteCallback callback) {
165             mHandler.sendMessage(
166                     obtainMessage(DisplayHashingService::onGenerateDisplayHash,
167                             DisplayHashingService.this, salt, buffer, bounds,
168                             hashAlgorithm, new DisplayHashResultCallback() {
169                                 @Override
170                                 public void onDisplayHashResult(
171                                         @NonNull DisplayHash displayHash) {
172                                     Bundle result = new Bundle();
173                                     result.putParcelable(EXTRA_DISPLAY_HASH, displayHash);
174                                     callback.sendResult(result);
175                                 }
176 
177                                 @Override
178                                 public void onDisplayHashError(int errorCode) {
179                                     Bundle result = new Bundle();
180                                     result.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode);
181                                     callback.sendResult(result);
182                                 }
183                             }));
184         }
185 
186         @Override
verifyDisplayHash(byte[] salt, DisplayHash displayHash, RemoteCallback callback)187         public void verifyDisplayHash(byte[] salt, DisplayHash displayHash,
188                 RemoteCallback callback) {
189             mHandler.sendMessage(
190                     obtainMessage(DisplayHashingService::verifyDisplayHash,
191                             DisplayHashingService.this, salt, displayHash, callback));
192         }
193 
194         @Override
getDisplayHashAlgorithms(RemoteCallback callback)195         public void getDisplayHashAlgorithms(RemoteCallback callback) {
196             mHandler.sendMessage(obtainMessage(DisplayHashingService::getDisplayHashAlgorithms,
197                     DisplayHashingService.this, callback));
198         }
199 
200         @Override
getIntervalBetweenRequestsMillis(RemoteCallback callback)201         public void getIntervalBetweenRequestsMillis(RemoteCallback callback) {
202             mHandler.sendMessage(
203                     obtainMessage(DisplayHashingService::getDurationBetweenRequestsMillis,
204                             DisplayHashingService.this, callback));
205         }
206     }
207 }
208