blob: b65e24e3b81e08fde9bf0f7e3bdf3681e52d73c5 [file] [log] [blame]
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -08001/*
2 * Copyright (C) 2016 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
17package android.hardware.location;
18
destradaa8bad3fe2016-03-15 12:33:40 -070019import android.Manifest;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080020import android.content.Context;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080021import android.os.RemoteException;
22import android.util.Log;
23
24import java.util.ArrayList;
25import java.util.HashMap;
26
27/**
28 * @hide
29 */
Peng Xu9ff7d222016-02-11 13:02:05 -080030public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080031
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070032 public static final String CONTEXTHUB_SERVICE = "contexthub_service";
33
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080034 private static final String TAG = "ContextHubService";
destradaa8bad3fe2016-03-15 12:33:40 -070035 private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
36 private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
37 + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080038
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070039
40 public static final int ANY_HUB = -1;
41 public static final int MSG_LOAD_NANO_APP = 5;
42 public static final int MSG_UNLOAD_NANO_APP = 2;
43
44 private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
45 private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
46 private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
47 private static final int PRE_LOADED_APP_MEM_REQ = 0;
48
49 private static final int MSG_HEADER_SIZE = 4;
50 private static final int MSG_FIELD_TYPE = 0;
51 private static final int MSG_FIELD_VERSION = 1;
52 private static final int MSG_FIELD_HUB_HANDLE = 2;
53 private static final int MSG_FIELD_APP_INSTANCE = 3;
54
55 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080056
Peng Xu9ff7d222016-02-11 13:02:05 -080057 private final Context mContext;
58
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080059 private HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash;
Peng Xu9ff7d222016-02-11 13:02:05 -080060 private ContextHubInfo[] mContextHubInfo;
61 private IContextHubCallback mCallback;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080062
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070063 private native int nativeSendMessage(int[] header, byte[] data);
64 private native ContextHubInfo[] nativeInitialize();
65
66
Peng Xu9ff7d222016-02-11 13:02:05 -080067 public ContextHubService(Context context) {
68 mContext = context;
69 mContextHubInfo = nativeInitialize();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070070 mNanoAppHash = new HashMap<Integer, NanoAppInstanceInfo>();
Peng Xu9ff7d222016-02-11 13:02:05 -080071
72 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070073 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Peng Xu9ff7d222016-02-11 13:02:05 -080074 + ", name: " + mContextHubInfo[i].getName());
75 }
76 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080077
Peng Xu9ff7d222016-02-11 13:02:05 -080078 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070079 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -070080 checkPermissions();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070081 synchronized(this) {
82 mCallback = callback;
Peng Xu9ff7d222016-02-11 13:02:05 -080083 }
Peng Xu9ff7d222016-02-11 13:02:05 -080084 return 0;
85 }
86
87 @Override
88 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -070089 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -080090 int [] returnArray = new int[mContextHubInfo.length];
91
92 for (int i = 0; i < returnArray.length; ++i) {
93 returnArray[i] = i + 1; //valid handles from 1...n
94 Log.d(TAG, String.format("Hub %s is mapped to %d",
95 mContextHubInfo[i].getName(), returnArray[i]));
96 }
97
98 return returnArray;
99 }
100
101 @Override
102 public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700103 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800104 contextHubHandle -= 1;
105 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
106 return null; // null means fail
107 }
108
109 return mContextHubInfo[contextHubHandle];
110 }
111
112 @Override
113 public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700114 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800115 contextHubHandle -= 1;
116
117 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
118 return -1; // negative handle are invalid, means failed
119 }
120
121 // Call Native interface here
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700122 int[] msgHeader = new int[MSG_HEADER_SIZE];
123 msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
124 msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
125 msgHeader[MSG_FIELD_VERSION] = 0;
126 msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
Peng Xu9ff7d222016-02-11 13:02:05 -0800127
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700128 if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
129 return -1;
130 }
131 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
132 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800133 }
134
destradaa8bad3fe2016-03-15 12:33:40 -0700135 @Override
136 public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
137 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800138 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
139 if (info == null) {
destradaa8bad3fe2016-03-15 12:33:40 -0700140 return -1; //means failed
Peng Xu9ff7d222016-02-11 13:02:05 -0800141 }
142
143 // Call Native interface here
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700144 int[] msgHeader = new int[MSG_HEADER_SIZE];
145 msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
146 msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
147 msgHeader[MSG_FIELD_VERSION] = 0;
148 msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
Peng Xu9ff7d222016-02-11 13:02:05 -0800149
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700150 if(nativeSendMessage(msgHeader, null) != 0) {
151 return -1;
152 }
153
154 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
155 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700156 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800157
158 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700159 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
160 throws RemoteException {
161 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800162 // This assumes that all the nanoAppInfo is current. This is reasonable
163 // for the use cases for tightly controlled nanoApps.
164 if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
165 return mNanoAppHash.get(nanoAppInstanceHandle);
166 } else {
167 return null;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800168 }
169 }
170
171 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800172 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700173 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800174 ArrayList<Integer> foundInstances = new ArrayList<Integer>();
175
176 for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
177 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
178
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700179 if (filter.testMatch(info)){
Peng Xu9ff7d222016-02-11 13:02:05 -0800180 foundInstances.add(nanoAppInstance);
181 }
182 }
183
184 int[] retArray = new int[foundInstances.size()];
185 for (int i = 0; i < foundInstances.size(); i++) {
186 retArray[i] = foundInstances.get(i).intValue();
187 }
188
189 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800190 }
191
192 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700193 public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
194 throws RemoteException {
195 checkPermissions();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700196
197 int[] msgHeader = new int[MSG_HEADER_SIZE];
198 msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
199 msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
200 msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
201 msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
Peng Xu9ff7d222016-02-11 13:02:05 -0800202
203 return nativeSendMessage(msgHeader, msg.getData());
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800204 }
destradaa8bad3fe2016-03-15 12:33:40 -0700205
206 private void checkPermissions() {
207 mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
208 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000209
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700210 private int onMessageReceipt(int[] header, byte[] data) {
211 if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
212 return -1;
213 }
214
215 synchronized(this) {
216 if (mCallback != null) {
217 ContextHubMessage msg = new ContextHubMessage(header[MSG_FIELD_TYPE],
218 header[MSG_FIELD_VERSION],
219 data);
220
221 try {
222 mCallback.onMessageReceipt(header[MSG_FIELD_HUB_HANDLE],
223 header[MSG_FIELD_APP_INSTANCE],
224 msg);
225 } catch (Exception e) {
226 Log.w(TAG, "Exception " + e + " when calling remote callback");
227 return -1;
228 }
229 } else {
230 Log.d(TAG, "Message Callback is NULL");
231 }
232 }
233
234 return 0;
235 }
236
237 private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
238 // App Id encodes vendor & version
239 NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
240
241 appInfo.setAppId(appId);
242 appInfo.setAppVersion(appVersion);
243 appInfo.setName(PRE_LOADED_APP_NAME);
244 appInfo.setContexthubId(hubHandle);
245 appInfo.setHandle(appInstanceHandle);
246 appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
247 appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
248 appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
249 appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
250
251 mNanoAppHash.put(appInstanceHandle, appInfo);
252 Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
253 + " version " + appVersion);
254
255 return 0;
256 }
257}