• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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