blob: 8176189dffa009d61de2306af69ac1831bdf9ebc [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 Joshi6239cc62016-04-04 16:19:29 -070021import android.content.pm.PackageManager;
destradaa78cebca2016-04-14 18:40:14 -070022import android.os.RemoteCallbackList;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080023import android.os.RemoteException;
24import android.util.Log;
25
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070026import java.io.FileDescriptor;
27import java.io.PrintWriter;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080028import java.util.ArrayList;
29import java.util.HashMap;
30
31/**
32 * @hide
33 */
Peng Xu9ff7d222016-02-11 13:02:05 -080034public class ContextHubService extends IContextHubService.Stub {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070035 public static final String CONTEXTHUB_SERVICE = "contexthub_service";
36
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080037 private static final String TAG = "ContextHubService";
destradaa8bad3fe2016-03-15 12:33:40 -070038 private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
39 private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070040 + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080041
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070042
43 public static final int ANY_HUB = -1;
Ashutosh Joshicafdee92016-04-04 16:19:29 -070044 public static final int MSG_LOAD_NANO_APP = 3;
45 public static final int MSG_UNLOAD_NANO_APP = 4;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070046
47 private static final String PRE_LOADED_GENERIC_UNKNOWN = "Preloaded app, unknown";
48 private static final String PRE_LOADED_APP_NAME = PRE_LOADED_GENERIC_UNKNOWN;
49 private static final String PRE_LOADED_APP_PUBLISHER = PRE_LOADED_GENERIC_UNKNOWN;
50 private static final int PRE_LOADED_APP_MEM_REQ = 0;
51
52 private static final int MSG_HEADER_SIZE = 4;
53 private static final int MSG_FIELD_TYPE = 0;
54 private static final int MSG_FIELD_VERSION = 1;
55 private static final int MSG_FIELD_HUB_HANDLE = 2;
56 private static final int MSG_FIELD_APP_INSTANCE = 3;
57
58 private static final int OS_APP_INSTANCE = -1;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080059
Peng Xu9ff7d222016-02-11 13:02:05 -080060 private final Context mContext;
destradaa78cebca2016-04-14 18:40:14 -070061 private final HashMap<Integer, NanoAppInstanceInfo> mNanoAppHash = new HashMap<>();
62 private final ContextHubInfo[] mContextHubInfo;
63 private final RemoteCallbackList<IContextHubCallback> mCallbacksList =
64 new RemoteCallbackList<>();
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080065
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070066 private native int nativeSendMessage(int[] header, byte[] data);
67 private native ContextHubInfo[] nativeInitialize();
68
Peng Xu9ff7d222016-02-11 13:02:05 -080069 public ContextHubService(Context context) {
70 mContext = context;
71 mContextHubInfo = nativeInitialize();
72
73 for (int i = 0; i < mContextHubInfo.length; i++) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070074 Log.d(TAG, "ContextHub[" + i + "] id: " + mContextHubInfo[i].getId()
Peng Xu9ff7d222016-02-11 13:02:05 -080075 + ", name: " + mContextHubInfo[i].getName());
76 }
77 }
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -080078
Peng Xu9ff7d222016-02-11 13:02:05 -080079 @Override
Ashutosh Joshib741e3b2016-03-29 09:19:56 -070080 public int registerCallback(IContextHubCallback callback) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -070081 checkPermissions();
destradaa78cebca2016-04-14 18:40:14 -070082 mCallbacksList.register(callback);
Peng Xu9ff7d222016-02-11 13:02:05 -080083 return 0;
84 }
85
86 @Override
87 public int[] getContextHubHandles() throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -070088 checkPermissions();
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070089 int[] returnArray = new int[mContextHubInfo.length];
Peng Xu9ff7d222016-02-11 13:02:05 -080090
91 for (int i = 0; i < returnArray.length; ++i) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -070092 returnArray[i] = i;
Peng Xu9ff7d222016-02-11 13:02:05 -080093 Log.d(TAG, String.format("Hub %s is mapped to %d",
94 mContextHubInfo[i].getName(), returnArray[i]));
95 }
96
97 return returnArray;
98 }
99
100 @Override
101 public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700102 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800103 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
104 return null; // null means fail
105 }
106
107 return mContextHubInfo[contextHubHandle];
108 }
109
110 @Override
111 public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700112 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800113
114 if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700115 Log.e(TAG, "Invalid contextHubhandle " + contextHubHandle);
116 return -1;
Peng Xu9ff7d222016-02-11 13:02:05 -0800117 }
118
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700119 int[] msgHeader = new int[MSG_HEADER_SIZE];
120 msgHeader[MSG_FIELD_HUB_HANDLE] = contextHubHandle;
121 msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
122 msgHeader[MSG_FIELD_VERSION] = 0;
123 msgHeader[MSG_FIELD_TYPE] = MSG_LOAD_NANO_APP;
Peng Xu9ff7d222016-02-11 13:02:05 -0800124
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700125 if (nativeSendMessage(msgHeader, app.getAppBinary()) != 0) {
126 return -1;
127 }
128 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
129 return 0;
Peng Xu9ff7d222016-02-11 13:02:05 -0800130 }
131
destradaa8bad3fe2016-03-15 12:33:40 -0700132 @Override
133 public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
134 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800135 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
136 if (info == null) {
destradaa8bad3fe2016-03-15 12:33:40 -0700137 return -1; //means failed
Peng Xu9ff7d222016-02-11 13:02:05 -0800138 }
139
140 // Call Native interface here
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700141 int[] msgHeader = new int[MSG_HEADER_SIZE];
142 msgHeader[MSG_FIELD_HUB_HANDLE] = ANY_HUB;
143 msgHeader[MSG_FIELD_APP_INSTANCE] = OS_APP_INSTANCE;
144 msgHeader[MSG_FIELD_VERSION] = 0;
145 msgHeader[MSG_FIELD_TYPE] = MSG_UNLOAD_NANO_APP;
Peng Xu9ff7d222016-02-11 13:02:05 -0800146
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700147 if (nativeSendMessage(msgHeader, null) != 0) {
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700148 return -1;
149 }
150
151 // Do not add an entry to mNanoAppInstance Hash yet. The HAL may reject the app
152 return 0;
destradaa8bad3fe2016-03-15 12:33:40 -0700153 }
Peng Xu9ff7d222016-02-11 13:02:05 -0800154
155 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700156 public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700157 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700158 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800159 // This assumes that all the nanoAppInfo is current. This is reasonable
160 // for the use cases for tightly controlled nanoApps.
161 if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
162 return mNanoAppHash.get(nanoAppInstanceHandle);
163 } else {
164 return null;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800165 }
166 }
167
168 @Override
Peng Xu9ff7d222016-02-11 13:02:05 -0800169 public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700170 checkPermissions();
Peng Xu9ff7d222016-02-11 13:02:05 -0800171 ArrayList<Integer> foundInstances = new ArrayList<Integer>();
172
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700173 for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800174 NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstance);
175
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700176 if (filter.testMatch(info)) {
Peng Xu9ff7d222016-02-11 13:02:05 -0800177 foundInstances.add(nanoAppInstance);
178 }
179 }
180
181 int[] retArray = new int[foundInstances.size()];
182 for (int i = 0; i < foundInstances.size(); i++) {
183 retArray[i] = foundInstances.get(i).intValue();
184 }
185
186 return retArray;
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800187 }
188
189 @Override
destradaa8bad3fe2016-03-15 12:33:40 -0700190 public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700191 throws RemoteException {
destradaa8bad3fe2016-03-15 12:33:40 -0700192 checkPermissions();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700193
194 int[] msgHeader = new int[MSG_HEADER_SIZE];
195 msgHeader[MSG_FIELD_HUB_HANDLE] = hubHandle;
196 msgHeader[MSG_FIELD_APP_INSTANCE] = nanoAppHandle;
197 msgHeader[MSG_FIELD_VERSION] = msg.getVersion();
198 msgHeader[MSG_FIELD_TYPE] = msg.getMsgType();
Peng Xu9ff7d222016-02-11 13:02:05 -0800199
200 return nativeSendMessage(msgHeader, msg.getData());
Ashutosh Joshi1d1ac542016-01-18 17:19:27 -0800201 }
destradaa8bad3fe2016-03-15 12:33:40 -0700202
Ashutosh Joshi6239cc62016-04-04 16:19:29 -0700203 @Override
204 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
205 if (mContext.checkCallingOrSelfPermission("android.permission.DUMP")
206 != PackageManager.PERMISSION_GRANTED) {
207 pw.println("Permission Denial: can't dump contexthub_service");
208 return;
209 }
210
211 pw.println("Dumping ContextHub Service");
212
213 pw.println("");
214 // dump ContextHubInfo
215 pw.println("=================== CONTEXT HUBS ====================");
216 for (int i = 0; i < mContextHubInfo.length; i++) {
217 pw.println("Handle " + i + " : " + mContextHubInfo[i].toString());
218 }
219 pw.println("");
220 pw.println("=================== NANOAPPS ====================");
221 // Dump nanoAppHash
222 for (Integer nanoAppInstance: mNanoAppHash.keySet()) {
223 pw.println(nanoAppInstance + " : " + mNanoAppHash.get(nanoAppInstance).toString());
224 }
225
226 // dump eventLog
227 }
228
destradaa8bad3fe2016-03-15 12:33:40 -0700229 private void checkPermissions() {
230 mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
231 }
Ashutosh Joshi2c697fb2016-04-01 20:48:13 +0000232
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700233 private int onMessageReceipt(int[] header, byte[] data) {
234 if (header == null || data == null || header.length < MSG_HEADER_SIZE) {
235 return -1;
236 }
destradaa78cebca2016-04-14 18:40:14 -0700237 int callbacksCount = mCallbacksList.beginBroadcast();
238 if (callbacksCount < 1) {
239 Log.v(TAG, "No message callbacks registered.");
240 return 0;
241 }
242 ContextHubMessage message =
243 new ContextHubMessage(header[MSG_FIELD_TYPE], header[MSG_FIELD_VERSION], data);
244 for (int i = 0; i < callbacksCount; ++i) {
245 IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
246 try {
247 callback.onMessageReceipt(
248 header[MSG_FIELD_HUB_HANDLE],
249 header[MSG_FIELD_APP_INSTANCE],
250 message);
251 } catch (RemoteException e) {
252 Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
253 continue;
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700254 }
255 }
destradaa78cebca2016-04-14 18:40:14 -0700256 mCallbacksList.finishBroadcast();
Ashutosh Joshib741e3b2016-03-29 09:19:56 -0700257 return 0;
258 }
259
260 private int addAppInstance(int hubHandle, int appInstanceHandle, long appId, int appVersion) {
261 // App Id encodes vendor & version
262 NanoAppInstanceInfo appInfo = new NanoAppInstanceInfo();
263
264 appInfo.setAppId(appId);
265 appInfo.setAppVersion(appVersion);
266 appInfo.setName(PRE_LOADED_APP_NAME);
267 appInfo.setContexthubId(hubHandle);
268 appInfo.setHandle(appInstanceHandle);
269 appInfo.setPublisher(PRE_LOADED_APP_PUBLISHER);
270 appInfo.setNeededExecMemBytes(PRE_LOADED_APP_MEM_REQ);
271 appInfo.setNeededReadMemBytes(PRE_LOADED_APP_MEM_REQ);
272 appInfo.setNeededWriteMemBytes(PRE_LOADED_APP_MEM_REQ);
273
274 mNanoAppHash.put(appInstanceHandle, appInfo);
275 Log.d(TAG, "Added app instance " + appInstanceHandle + " with id " + appId
276 + " version " + appVersion);
277
278 return 0;
279 }
280}