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 static android.content.pm.PackageManager.PERMISSION_GRANTED; 20 21 import android.Manifest; 22 import android.content.Context; 23 import android.hardware.contexthub.V1_0.ContextHub; 24 import android.hardware.contexthub.V1_0.ContextHubMsg; 25 import android.hardware.contexthub.V1_0.HostEndPoint; 26 import android.hardware.contexthub.V1_0.Result; 27 import android.hardware.contexthub.V1_2.HubAppInfo; 28 import android.hardware.location.ContextHubInfo; 29 import android.hardware.location.ContextHubTransaction; 30 import android.hardware.location.NanoAppBinary; 31 import android.hardware.location.NanoAppMessage; 32 import android.hardware.location.NanoAppState; 33 import android.os.Binder; 34 import android.os.Build; 35 import android.util.Log; 36 37 import java.util.ArrayList; 38 import java.util.Collection; 39 import java.util.HashMap; 40 import java.util.HashSet; 41 import java.util.List; 42 import java.util.Set; 43 44 /** 45 * A class encapsulating helper functions used by the ContextHubService class 46 */ 47 /* package */ class ContextHubServiceUtil { 48 private static final String TAG = "ContextHubServiceUtil"; 49 private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE; 50 private static final String CONTEXT_HUB_PERMISSION = Manifest.permission.ACCESS_CONTEXT_HUB; 51 52 // A set of packages that have already been warned regarding the ACCESS_CONTEXT_HUB permission. 53 private static final Set<String> PERMISSION_WARNED_PACKAGES = new HashSet<String>(); 54 55 /** 56 * Creates a ConcurrentHashMap of the Context Hub ID to the ContextHubInfo object given an 57 * ArrayList of HIDL ContextHub objects. 58 * 59 * @param hubList the ContextHub ArrayList 60 * @return the HashMap object 61 */ 62 /* package */ createContextHubInfoMap(List<ContextHub> hubList)63 static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHub> hubList) { 64 HashMap<Integer, ContextHubInfo> contextHubIdToInfoMap = new HashMap<>(); 65 for (ContextHub contextHub : hubList) { 66 contextHubIdToInfoMap.put(contextHub.hubId, new ContextHubInfo(contextHub)); 67 } 68 69 return contextHubIdToInfoMap; 70 } 71 72 /** 73 * Copies a primitive byte array to a ArrayList<Byte>. 74 * 75 * @param inputArray the primitive byte array 76 * @param outputArray the ArrayList<Byte> array to append 77 */ 78 /* package */ copyToByteArrayList(byte[] inputArray, ArrayList<Byte> outputArray)79 static void copyToByteArrayList(byte[] inputArray, ArrayList<Byte> outputArray) { 80 outputArray.clear(); 81 outputArray.ensureCapacity(inputArray.length); 82 for (byte element : inputArray) { 83 outputArray.add(element); 84 } 85 } 86 87 /** 88 * Creates a byte array given a ArrayList<Byte> and copies its contents. 89 * 90 * @param array the ArrayList<Byte> object 91 * @return the byte array 92 */ 93 /* package */ createPrimitiveByteArray(ArrayList<Byte> array)94 static byte[] createPrimitiveByteArray(ArrayList<Byte> array) { 95 byte[] primitiveArray = new byte[array.size()]; 96 for (int i = 0; i < array.size(); i++) { 97 primitiveArray[i] = array.get(i); 98 } 99 100 return primitiveArray; 101 } 102 103 /** 104 * Creates a primitive integer array given a Collection<Integer>. 105 * 106 * @param collection the collection to iterate 107 * @return the primitive integer array 108 */ createPrimitiveIntArray(Collection<Integer> collection)109 static int[] createPrimitiveIntArray(Collection<Integer> collection) { 110 int[] primitiveArray = new int[collection.size()]; 111 112 int i = 0; 113 for (int contextHubId : collection) { 114 primitiveArray[i++] = contextHubId; 115 } 116 117 return primitiveArray; 118 } 119 120 /** 121 * Generates the Context Hub HAL's NanoAppBinary object from the client-facing 122 * android.hardware.location.NanoAppBinary object. 123 * 124 * @param nanoAppBinary the client-facing NanoAppBinary object 125 * @return the Context Hub HAL's NanoAppBinary object 126 */ 127 /* package */ createHidlNanoAppBinary( NanoAppBinary nanoAppBinary)128 static android.hardware.contexthub.V1_0.NanoAppBinary createHidlNanoAppBinary( 129 NanoAppBinary nanoAppBinary) { 130 android.hardware.contexthub.V1_0.NanoAppBinary hidlNanoAppBinary = 131 new android.hardware.contexthub.V1_0.NanoAppBinary(); 132 133 hidlNanoAppBinary.appId = nanoAppBinary.getNanoAppId(); 134 hidlNanoAppBinary.appVersion = nanoAppBinary.getNanoAppVersion(); 135 hidlNanoAppBinary.flags = nanoAppBinary.getFlags(); 136 hidlNanoAppBinary.targetChreApiMajorVersion = nanoAppBinary.getTargetChreApiMajorVersion(); 137 hidlNanoAppBinary.targetChreApiMinorVersion = nanoAppBinary.getTargetChreApiMinorVersion(); 138 139 // Log exceptions while processing the binary, but continue to pass down the binary 140 // since the error checking is deferred to the Context Hub. 141 try { 142 copyToByteArrayList(nanoAppBinary.getBinaryNoHeader(), hidlNanoAppBinary.customBinary); 143 } catch (IndexOutOfBoundsException e) { 144 Log.w(TAG, e.getMessage()); 145 } catch (NullPointerException e) { 146 Log.w(TAG, "NanoApp binary was null"); 147 } 148 149 return hidlNanoAppBinary; 150 } 151 152 /** 153 * Generates a client-facing NanoAppState array from a HAL HubAppInfo array. 154 * 155 * @param nanoAppInfoList the array of HubAppInfo objects 156 * @return the corresponding array of NanoAppState objects 157 */ 158 /* package */ createNanoAppStateList( List<HubAppInfo> nanoAppInfoList)159 static List<NanoAppState> createNanoAppStateList( 160 List<HubAppInfo> nanoAppInfoList) { 161 ArrayList<NanoAppState> nanoAppStateList = new ArrayList<>(); 162 for (HubAppInfo appInfo : nanoAppInfoList) { 163 nanoAppStateList.add( 164 new NanoAppState(appInfo.info_1_0.appId, appInfo.info_1_0.version, 165 appInfo.info_1_0.enabled, appInfo.permissions)); 166 } 167 168 return nanoAppStateList; 169 } 170 171 /** 172 * Creates a HIDL ContextHubMsg object to send to a nanoapp. 173 * 174 * @param hostEndPoint the ID of the client sending the message 175 * @param message the client-facing NanoAppMessage object describing the message 176 * @return the HIDL ContextHubMsg object 177 */ 178 /* package */ createHidlContextHubMessage(short hostEndPoint, NanoAppMessage message)179 static ContextHubMsg createHidlContextHubMessage(short hostEndPoint, NanoAppMessage message) { 180 ContextHubMsg hidlMessage = new ContextHubMsg(); 181 182 hidlMessage.appName = message.getNanoAppId(); 183 hidlMessage.hostEndPoint = hostEndPoint; 184 hidlMessage.msgType = message.getMessageType(); 185 copyToByteArrayList(message.getMessageBody(), hidlMessage.msg); 186 187 return hidlMessage; 188 } 189 190 /** 191 * Creates a client-facing NanoAppMessage object to send to a client. 192 * 193 * @param message the HIDL ContextHubMsg object from a nanoapp 194 * @return the NanoAppMessage object 195 */ 196 /* package */ createNanoAppMessage(ContextHubMsg message)197 static NanoAppMessage createNanoAppMessage(ContextHubMsg message) { 198 byte[] messageArray = createPrimitiveByteArray(message.msg); 199 200 return NanoAppMessage.createMessageFromNanoApp( 201 message.appName, message.msgType, messageArray, 202 message.hostEndPoint == HostEndPoint.BROADCAST); 203 } 204 205 /** 206 * Checks for location hardware permissions. 207 * 208 * @param context the context of the service 209 */ 210 /* package */ checkPermissions(Context context)211 static void checkPermissions(Context context) { 212 boolean hasLocationHardwarePermission = (context.checkCallingPermission(HARDWARE_PERMISSION) 213 == PERMISSION_GRANTED); 214 boolean hasAccessContextHubPermission = (context.checkCallingPermission( 215 CONTEXT_HUB_PERMISSION) == PERMISSION_GRANTED); 216 217 if (!hasLocationHardwarePermission && !hasAccessContextHubPermission) { 218 throw new SecurityException( 219 "LOCATION_HARDWARE or ACCESS_CONTEXT_HUB permission required to use Context " 220 + "Hub"); 221 } 222 223 if (!hasAccessContextHubPermission && !Build.IS_USER) { 224 String pkgName = context.getPackageManager().getNameForUid(Binder.getCallingUid()); 225 if (!PERMISSION_WARNED_PACKAGES.contains(pkgName)) { 226 Log.w(TAG, pkgName 227 + ": please use the ACCESS_CONTEXT_HUB permission rather than " 228 + "LOCATION_HARDWARE (will be removed for Context Hub APIs in T)"); 229 PERMISSION_WARNED_PACKAGES.add(pkgName); 230 } 231 } 232 } 233 234 /** 235 * Helper function to convert from the HAL Result enum error code to the 236 * ContextHubTransaction.Result type. 237 * 238 * @param halResult the Result enum error code 239 * @return the ContextHubTransaction.Result equivalent 240 */ 241 @ContextHubTransaction.Result 242 /* package */ toTransactionResult(int halResult)243 static int toTransactionResult(int halResult) { 244 switch (halResult) { 245 case Result.OK: 246 return ContextHubTransaction.RESULT_SUCCESS; 247 case Result.BAD_PARAMS: 248 return ContextHubTransaction.RESULT_FAILED_BAD_PARAMS; 249 case Result.NOT_INIT: 250 return ContextHubTransaction.RESULT_FAILED_UNINITIALIZED; 251 case Result.TRANSACTION_PENDING: 252 return ContextHubTransaction.RESULT_FAILED_BUSY; 253 case Result.TRANSACTION_FAILED: 254 case Result.UNKNOWN_FAILURE: 255 default: /* fall through */ 256 return ContextHubTransaction.RESULT_FAILED_UNKNOWN; 257 } 258 } 259 260 /** 261 * Converts old list of HubAppInfo received from the HAL to V1.2 HubAppInfo objects. 262 * 263 * @param oldInfoList list of V1.0 HubAppInfo objects 264 * @return list of V1.2 HubAppInfo objects 265 */ 266 /* package */ toHubAppInfo_1_2( ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> oldInfoList)267 static ArrayList<HubAppInfo> toHubAppInfo_1_2( 268 ArrayList<android.hardware.contexthub.V1_0.HubAppInfo> oldInfoList) { 269 ArrayList newAppInfo = new ArrayList<HubAppInfo>(); 270 for (android.hardware.contexthub.V1_0.HubAppInfo oldInfo : oldInfoList) { 271 HubAppInfo newInfo = new HubAppInfo(); 272 newInfo.info_1_0.appId = oldInfo.appId; 273 newInfo.info_1_0.version = oldInfo.version; 274 newInfo.info_1_0.memUsage = oldInfo.memUsage; 275 newInfo.info_1_0.enabled = oldInfo.enabled; 276 newInfo.permissions = new ArrayList<String>(); 277 newAppInfo.add(newInfo); 278 } 279 return newAppInfo; 280 } 281 } 282