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 71 @Override onCreate()72 public void onCreate() { 73 super.onCreate(); 74 mWrapper = new DisplayHashingServiceWrapper(); 75 mHandler = new Handler(Looper.getMainLooper(), null, true); 76 } 77 78 @NonNull 79 @Override onBind(@onNull Intent intent)80 public final IBinder onBind(@NonNull Intent intent) { 81 return mWrapper; 82 } 83 84 /** 85 * Generates the DisplayHash that can be used to validate that the system generated the 86 * token. 87 * 88 * @param salt The salt to use when generating the hmac. This should be unique to the 89 * caller so the token cannot be verified by any other process. 90 * @param buffer The buffer for the content to generate the hash for. 91 * @param bounds The size and position of the content in window space. 92 * @param hashAlgorithm The String for the hashing algorithm to use based values in 93 * {@link #getDisplayHashAlgorithms(RemoteCallback)}. 94 * @param callback The callback to invoke 95 * {@link DisplayHashResultCallback#onDisplayHashResult(DisplayHash)} 96 * if successfully generated a DisplayHash or {@link 97 * DisplayHashResultCallback#onDisplayHashError(int)} if failed. 98 */ onGenerateDisplayHash(@onNull byte[] salt, @NonNull HardwareBuffer buffer, @NonNull Rect bounds, @NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback)99 public abstract void onGenerateDisplayHash(@NonNull byte[] salt, 100 @NonNull HardwareBuffer buffer, @NonNull Rect bounds, 101 @NonNull String hashAlgorithm, @NonNull DisplayHashResultCallback callback); 102 103 /** 104 * Returns a map of supported algorithms and their {@link DisplayHashParams} 105 */ 106 @NonNull onGetDisplayHashAlgorithms()107 public abstract Map<String, DisplayHashParams> onGetDisplayHashAlgorithms(); 108 109 /** 110 * Call to verify that the DisplayHash passed in was generated by the system. 111 * 112 * @param salt The salt value to use when verifying the hmac. This should be the 113 * same value that was passed to 114 * {@link #onGenerateDisplayHash(byte[], 115 * HardwareBuffer, Rect, String, DisplayHashResultCallback)} to 116 * generate the token. 117 * @param displayHash The token to verify that it was generated by the system. 118 * @return a {@link VerifiedDisplayHash} if the provided display hash was originally generated 119 * by the system or null if the system did not generate the display hash. 120 */ 121 @Nullable onVerifyDisplayHash(@onNull byte[] salt, @NonNull DisplayHash displayHash)122 public abstract VerifiedDisplayHash onVerifyDisplayHash(@NonNull byte[] salt, 123 @NonNull DisplayHash displayHash); 124 verifyDisplayHash(byte[] salt, DisplayHash displayHash, RemoteCallback callback)125 private void verifyDisplayHash(byte[] salt, DisplayHash displayHash, 126 RemoteCallback callback) { 127 VerifiedDisplayHash verifiedDisplayHash = onVerifyDisplayHash(salt, 128 displayHash); 129 final Bundle data = new Bundle(); 130 data.putParcelable(EXTRA_VERIFIED_DISPLAY_HASH, verifiedDisplayHash); 131 callback.sendResult(data); 132 } 133 getDisplayHashAlgorithms(RemoteCallback callback)134 private void getDisplayHashAlgorithms(RemoteCallback callback) { 135 Map<String, DisplayHashParams> displayHashParams = onGetDisplayHashAlgorithms(); 136 final Bundle data = new Bundle(); 137 for (Map.Entry<String, DisplayHashParams> entry : displayHashParams.entrySet()) { 138 data.putParcelable(entry.getKey(), entry.getValue()); 139 } 140 callback.sendResult(data); 141 } 142 143 /** 144 * Call to get the interval required between display hash requests. Requests made faster than 145 * this will be throttled. 146 * 147 * @return the interval value required between requests. 148 */ onGetIntervalBetweenRequestsMillis()149 public abstract int onGetIntervalBetweenRequestsMillis(); 150 getDurationBetweenRequestsMillis(RemoteCallback callback)151 private void getDurationBetweenRequestsMillis(RemoteCallback callback) { 152 int durationBetweenRequestMillis = onGetIntervalBetweenRequestsMillis(); 153 Bundle data = new Bundle(); 154 data.putInt(EXTRA_INTERVAL_BETWEEN_REQUESTS, durationBetweenRequestMillis); 155 callback.sendResult(data); 156 } 157 158 private final class DisplayHashingServiceWrapper extends IDisplayHashingService.Stub { 159 @Override generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds, String hashAlgorithm, RemoteCallback callback)160 public void generateDisplayHash(byte[] salt, HardwareBuffer buffer, Rect bounds, 161 String hashAlgorithm, RemoteCallback callback) { 162 mHandler.sendMessage( 163 obtainMessage(DisplayHashingService::onGenerateDisplayHash, 164 DisplayHashingService.this, salt, buffer, bounds, 165 hashAlgorithm, new DisplayHashResultCallback() { 166 @Override 167 public void onDisplayHashResult( 168 @NonNull DisplayHash displayHash) { 169 Bundle result = new Bundle(); 170 result.putParcelable(EXTRA_DISPLAY_HASH, displayHash); 171 callback.sendResult(result); 172 } 173 174 @Override 175 public void onDisplayHashError(int errorCode) { 176 Bundle result = new Bundle(); 177 result.putInt(EXTRA_DISPLAY_HASH_ERROR_CODE, errorCode); 178 callback.sendResult(result); 179 } 180 })); 181 } 182 183 @Override verifyDisplayHash(byte[] salt, DisplayHash displayHash, RemoteCallback callback)184 public void verifyDisplayHash(byte[] salt, DisplayHash displayHash, 185 RemoteCallback callback) { 186 mHandler.sendMessage( 187 obtainMessage(DisplayHashingService::verifyDisplayHash, 188 DisplayHashingService.this, salt, displayHash, callback)); 189 } 190 191 @Override getDisplayHashAlgorithms(RemoteCallback callback)192 public void getDisplayHashAlgorithms(RemoteCallback callback) { 193 mHandler.sendMessage(obtainMessage(DisplayHashingService::getDisplayHashAlgorithms, 194 DisplayHashingService.this, callback)); 195 } 196 197 @Override getIntervalBetweenRequestsMillis(RemoteCallback callback)198 public void getIntervalBetweenRequestsMillis(RemoteCallback callback) { 199 mHandler.sendMessage( 200 obtainMessage(DisplayHashingService::getDurationBetweenRequestsMillis, 201 DisplayHashingService.this, callback)); 202 } 203 } 204 } 205