1 /* 2 * Copyright (C) 2020 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 com.android.server.location.contexthub; 18 19 import android.Manifest; 20 import android.content.Context; 21 import android.hardware.contexthub.V1_0.AsyncEventType; 22 import android.hardware.contexthub.V1_0.ContextHubMsg; 23 import android.hardware.contexthub.V1_0.HostEndPoint; 24 import android.hardware.contexthub.V1_0.Result; 25 import android.hardware.contexthub.V1_2.HubAppInfo; 26 import android.hardware.location.ContextHubInfo; 27 import android.hardware.location.ContextHubTransaction; 28 import android.hardware.location.NanoAppBinary; 29 import android.hardware.location.NanoAppMessage; 30 import android.hardware.location.NanoAppRpcService; 31 import android.hardware.location.NanoAppState; 32 import android.util.Log; 33 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collection; 37 import java.util.HashMap; 38 import java.util.List; 39 40 /** 41 * A class encapsulating helper functions used by the ContextHubService class 42 */ 43 /* package */ class ContextHubServiceUtil { 44 private static final String TAG = "ContextHubServiceUtil"; 45 private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB; 46 47 /** 48 * A host endpoint that is reserved to identify a broadcasted message. 49 */ 50 private static final char HOST_ENDPOINT_BROADCAST = 0xFFFF; 51 52 /** 53 * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an 54 * ArrayList of HIDL ContextHub objects. 55 * 56 * @param hubList the ContextHub ArrayList 57 * @return the HashMap object 58 */ 59 /* package */ createContextHubInfoMap(List<ContextHubInfo> hubList)60 static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHubInfo> hubList) { 61 HashMap<Integer, ContextHubInfo> contextHubIdToInfoMap = new HashMap<>(); 62 for (ContextHubInfo contextHubInfo : hubList) { 63 contextHubIdToInfoMap.put(contextHubInfo.getId(), contextHubInfo); 64 } 65 66 return contextHubIdToInfoMap; 67 } 68 69 /** 70 * Copies a primitive byte array to a ArrayList<Byte>. 71 * 72 * @param inputArray the primitive byte array 73 * @param outputArray the ArrayList<Byte> array to append 74 */ 75 /* package */ copyToByteArrayList(byte[] inputArray, ArrayList<Byte> outputArray)76 static void copyToByteArrayList(byte[] inputArray, ArrayList<Byte> outputArray) { 77 outputArray.clear(); 78 outputArray.ensureCapacity(inputArray.length); 79 for (byte element : inputArray) { 80 outputArray.add(element); 81 } 82 } 83 84 /** 85 * Creates a byte array given a ArrayList<Byte> and copies its contents. 86 * 87 * @param array the ArrayList<Byte> object 88 * @return the byte array 89 */ 90 /* package */ createPrimitiveByteArray(ArrayList<Byte> array)91 static byte[] createPrimitiveByteArray(ArrayList<Byte> array) { 92 byte[] primitiveArray = new byte[array.size()]; 93 for (int i = 0; i < array.size(); i++) { 94 primitiveArray[i] = array.get(i); 95 } 96 97 return primitiveArray; 98 } 99 100 /** 101 * Creates a primitive integer array given a Collection<Integer>. 102 * 103 * @param collection the collection to iterate 104 * @return the primitive integer array 105 */ createPrimitiveIntArray(Collection<Integer> collection)106 static int[] createPrimitiveIntArray(Collection<Integer> collection) { 107 int[] primitiveArray = new int[collection.size()]; 108 109 int i = 0; 110 for (int contextHubId : collection) { 111 primitiveArray[i++] = contextHubId; 112 } 113 114 return primitiveArray; 115 } 116 117 /** 118 * Generates the Context Hub HAL's HIDL NanoAppBinary object from the client-facing 119 * android.hardware.location.NanoAppBinary object. 120 * 121 * @param nanoAppBinary the client-facing NanoAppBinary object 122 * @return the Context Hub HAL's HIDL NanoAppBinary object 123 */ 124 /* package */ createHidlNanoAppBinary( NanoAppBinary nanoAppBinary)125 static android.hardware.contexthub.V1_0.NanoAppBinary createHidlNanoAppBinary( 126 NanoAppBinary nanoAppBinary) { 127 android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary = 128 new android.hardware.contexthub.V1_0.NanoAppBinary(); 129 130 hidlNanoAppBinary.appId = nanoAppBinary.getNanoAppId(); 131 hidlNanoAppBinary.appVersion = nanoAppBinary.getNanoAppVersion(); 132 hidlNanoAppBinary.flags = nanoAppBinary.getFlags(); 133 hidlNanoAppBinary.targetChreApiMajorVersion = nanoAppBinary.getTargetChreApiMajorVersion(); 134 hidlNanoAppBinary.targetChreApiMinorVersion = nanoAppBinary.getTargetChreApiMinorVersion(); 135 136 // Log exceptions while processing the binary, but continue to pass down the binary 137 // since the error checking is deferred to the Context Hub. 138 try { 139 copyToByteArrayList(nanoAppBinary.getBinaryNoHeader(), hidlNanoAppBinary.customBinary); 140 } catch (IndexOutOfBoundsException e) { 141 Log.w(TAG, e.getMessage()); 142 } catch (NullPointerException e) { 143 Log.w(TAG, "NanoApp binary was null"); 144 } 145 146 return hidlNanoAppBinary; 147 } 148 149 /** 150 * Generates the Context Hub HAL's AIDL NanoAppBinary object from the client-facing 151 * android.hardware.location.NanoAppBinary object. 152 * 153 * @param nanoAppBinary the client-facing NanoAppBinary object 154 * @return the Context Hub HAL's AIDL NanoAppBinary object 155 */ 156 /* package */ createAidlNanoAppBinary( NanoAppBinary nanoAppBinary)157 static android.hardware.contexthub.NanoappBinary createAidlNanoAppBinary( 158 NanoAppBinary nanoAppBinary) { 159 android.hardware.contexthub.NanoappBinary aidlNanoAppBinary = 160 new android.hardware.contexthub.NanoappBinary(); 161 162 aidlNanoAppBinary.nanoappId = nanoAppBinary.getNanoAppId(); 163 aidlNanoAppBinary.nanoappVersion = nanoAppBinary.getNanoAppVersion(); 164 aidlNanoAppBinary.flags = nanoAppBinary.getFlags(); 165 aidlNanoAppBinary.targetChreApiMajorVersion = nanoAppBinary.getTargetChreApiMajorVersion(); 166 aidlNanoAppBinary.targetChreApiMinorVersion = nanoAppBinary.getTargetChreApiMinorVersion(); 167 // This explicit definition is required to avoid erroneous behavior at the binder. 168 aidlNanoAppBinary.customBinary = new byte[0]; 169 170 // Log exceptions while processing the binary, but continue to pass down the binary 171 // since the error checking is deferred to the Context Hub. 172 try { 173 aidlNanoAppBinary.customBinary = nanoAppBinary.getBinaryNoHeader(); 174 } catch (IndexOutOfBoundsException e) { 175 Log.w(TAG, e.getMessage()); 176 } catch (NullPointerException e) { 177 Log.w(TAG, "NanoApp binary was null"); 178 } 179 180 return aidlNanoAppBinary; 181 } 182 183 /** 184 * Generates a client-facing NanoAppState array from a HAL HubAppInfo array. 185 * 186 * @param nanoAppInfoList the array of HubAppInfo objects 187 * @return the corresponding array of NanoAppState objects 188 */ 189 /* package */ createNanoAppStateList( List<HubAppInfo> nanoAppInfoList)190 static List<NanoAppState> createNanoAppStateList( 191 List<HubAppInfo> nanoAppInfoList) { 192 ArrayList<NanoAppState> nanoAppStateList = new ArrayList<>(); 193 for (HubAppInfo appInfo : nanoAppInfoList) { 194 nanoAppStateList.add( 195 new NanoAppState(appInfo.info_1_0.appId, appInfo.info_1_0.version, 196 appInfo.info_1_0.enabled, appInfo.permissions)); 197 } 198 199 return nanoAppStateList; 200 } 201 202 /** 203 * Generates a client-facing NanoAppState array from a AIDL NanoappInfo array. 204 * 205 * @param nanoAppInfoList the array of NanoappInfo objects 206 * @return the corresponding array of NanoAppState objects 207 */ 208 /* package */ createNanoAppStateList( android.hardware.contexthub.NanoappInfo[] nanoAppInfoList)209 static List<NanoAppState> createNanoAppStateList( 210 android.hardware.contexthub.NanoappInfo[] nanoAppInfoList) { 211 ArrayList<NanoAppState> nanoAppStateList = new ArrayList<>(); 212 for (android.hardware.contexthub.NanoappInfo appInfo : nanoAppInfoList) { 213 ArrayList<NanoAppRpcService> rpcServiceList = new ArrayList<>(); 214 for (android.hardware.contexthub.NanoappRpcService service : appInfo.rpcServices) { 215 rpcServiceList.add(new NanoAppRpcService(service.id, service.version)); 216 } 217 nanoAppStateList.add( 218 new NanoAppState(appInfo.nanoappId, appInfo.nanoappVersion, 219 appInfo.enabled, new ArrayList<>(Arrays.asList(appInfo.permissions)), 220 rpcServiceList)); 221 } 222 223 return nanoAppStateList; 224 } 225 226 /** 227 * Creates a HIDL ContextHubMsg object to send to a nanoapp. 228 * 229 * @param hostEndPoint the ID of the client sending the message 230 * @param message the client-facing NanoAppMessage object describing the message 231 * @return the HIDL ContextHubMsg object 232 */ 233 /* package */ createHidlContextHubMessage(short hostEndPoint, NanoAppMessage message)234 static ContextHubMsg createHidlContextHubMessage(short hostEndPoint, NanoAppMessage message) { 235 ContextHubMsg hidlMessage = new ContextHubMsg(); 236 237 hidlMessage.appName = message.getNanoAppId(); 238 hidlMessage.hostEndPoint = hostEndPoint; 239 hidlMessage.msgType = message.getMessageType(); 240 copyToByteArrayList(message.getMessageBody(), hidlMessage.msg); 241 242 return hidlMessage; 243 } 244 245 /** 246 * Creates an AIDL ContextHubMessage object to send to a nanoapp. 247 * 248 * @param hostEndPoint the ID of the client sending the message 249 * @param message the client-facing NanoAppMessage object describing the message 250 * @return the AIDL ContextHubMessage object 251 */ 252 /* package */ createAidlContextHubMessage( short hostEndPoint, NanoAppMessage message)253 static android.hardware.contexthub.ContextHubMessage createAidlContextHubMessage( 254 short hostEndPoint, NanoAppMessage message) { 255 android.hardware.contexthub.ContextHubMessage aidlMessage = 256 new android.hardware.contexthub.ContextHubMessage(); 257 258 aidlMessage.nanoappId = message.getNanoAppId(); 259 aidlMessage.hostEndPoint = (char) hostEndPoint; 260 aidlMessage.messageType = message.getMessageType(); 261 aidlMessage.messageBody = message.getMessageBody(); 262 // This explicit definition is required to avoid erroneous behavior at the binder. 263 aidlMessage.permissions = new String[0]; 264 265 return aidlMessage; 266 } 267 268 /** 269 * Creates a client-facing NanoAppMessage object to send to a client. 270 * 271 * @param message the HIDL ContextHubMsg object from a nanoapp 272 * @return the NanoAppMessage object 273 */ 274 /* package */ createNanoAppMessage(ContextHubMsg message)275 static NanoAppMessage createNanoAppMessage(ContextHubMsg message) { 276 byte[] messageArray = createPrimitiveByteArray(message.msg); 277 278 return NanoAppMessage.createMessageFromNanoApp( 279 message.appName, message.msgType, messageArray, 280 message.hostEndPoint == HostEndPoint.BROADCAST); 281 } 282 283 /** 284 * Creates a client-facing NanoAppMessage object to send to a client. 285 * 286 * @param message the AIDL ContextHubMessage object from a nanoapp 287 * @return the NanoAppMessage object 288 */ 289 /* package */ createNanoAppMessage( android.hardware.contexthub.ContextHubMessage message)290 static NanoAppMessage createNanoAppMessage( 291 android.hardware.contexthub.ContextHubMessage message) { 292 return NanoAppMessage.createMessageFromNanoApp( 293 message.nanoappId, message.messageType, message.messageBody, 294 message.hostEndPoint == HOST_ENDPOINT_BROADCAST); 295 } 296 297 /** 298 * Checks for ACCESS_CONTEXT_HUB permissions. 299 * 300 * @param context the context of the service 301 */ 302 /* package */ checkPermissions(Context context)303 static void checkPermissions(Context context) { 304 context.enforceCallingOrSelfPermission(CONTEXT_HUB_PERMISSION, 305 "ACCESS_CONTEXT_HUB permission required to use Context Hub"); 306 } 307 308 /** 309 * Helper function to convert from the HAL Result enum error code to the 310 * ContextHubTransaction.Result type. 311 * 312 * @param halResult the Result enum error code 313 * @return the ContextHubTransaction.Result equivalent 314 */ 315 @ContextHubTransaction.Result 316 /* package */ toTransactionResult(int halResult)317 static int toTransactionResult(int halResult) { 318 switch (halResult) { 319 case Result.OK: 320 return ContextHubTransaction.RESULT_SUCCESS; 321 case Result.BAD_PARAMS: 322 return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS; 323 case Result.NOT_INIT: 324 return ContextHubTransaction.RESULT_FAILED_UNINITIALIZED; 325 case Result.TRANSACTION_PENDING: 326 return ContextHubTransaction.RESULT_FAILED_BUSY; 327 case Result.TRANSACTION_FAILED: 328 case Result.UNKNOWN_FAILURE: 329 default: /* fall through */ 330 return ContextHubTransaction.RESULT_FAILED_UNKNOWN; 331 } 332 } 333 334 /** 335 * Converts old list of HubAppInfo received from the HAL to V1.2 HubAppInfo objects. 336 * 337 * @param oldInfoList list of V1.0 HubAppInfo objects 338 * @return list of V1.2 HubAppInfo objects 339 */ 340 /* package */ toHubAppInfo_1_2( ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> oldInfoList)341 static ArrayList<HubAppInfo> toHubAppInfo_1_2( 342 ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> oldInfoList) { 343 ArrayList newAppInfo = new ArrayList<HubAppInfo>(); 344 for (android.hardware.contexthub.V1_0.HubAppInfo oldInfo : oldInfoList) { 345 HubAppInfo newInfo = new HubAppInfo(); 346 newInfo.info_1_0.appId = oldInfo.appId; 347 newInfo.info_1_0.version = oldInfo.version; 348 newInfo.info_1_0.memUsage = oldInfo.memUsage; 349 newInfo.info_1_0.enabled = oldInfo.enabled; 350 newInfo.permissions = new ArrayList<String>(); 351 newAppInfo.add(newInfo); 352 } 353 return newAppInfo; 354 } 355 356 /** 357 * Converts a HIDL AsyncEventType to the corresponding ContextHubService.CONTEXT_HUB_EVENT_*. 358 * 359 * @param hidlEventType The AsyncEventType value. 360 * @return The converted event type. 361 */ 362 /* package */ toContextHubEvent(int hidlEventType)363 static int toContextHubEvent(int hidlEventType) { 364 switch (hidlEventType) { 365 case AsyncEventType.RESTARTED: 366 return ContextHubService.CONTEXT_HUB_EVENT_RESTARTED; 367 default: 368 Log.e(TAG, "toContextHubEvent: Unknown event type: " + hidlEventType); 369 return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN; 370 } 371 } 372 373 /** 374 * Converts an AIDL AsyncEventType to the corresponding ContextHubService.CONTEXT_HUB_EVENT_*. 375 * 376 * @param aidlEventType The AsyncEventType value. 377 * @return The converted event type. 378 */ 379 /* package */ toContextHubEventFromAidl(int aidlEventType)380 static int toContextHubEventFromAidl(int aidlEventType) { 381 switch (aidlEventType) { 382 case android.hardware.contexthub.AsyncEventType.RESTARTED: 383 return ContextHubService.CONTEXT_HUB_EVENT_RESTARTED; 384 default: 385 Log.e(TAG, "toContextHubEventFromAidl: Unknown event type: " + aidlEventType); 386 return ContextHubService.CONTEXT_HUB_EVENT_UNKNOWN; 387 } 388 } 389 } 390