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