blob: e27eb65eccfc31eed308bcc8591f3bcb76395a0e [file] [log] [blame]
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -08001/*
2 * Copyright 2017 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 com.android.server.location;
18
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +000019import static android.content.pm.PackageManager.PERMISSION_GRANTED;
20
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -070021import android.Manifest;
Arthur Ishiguroa7c37972018-10-01 15:42:27 -070022import android.app.PendingIntent;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080023import android.content.Context;
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -070024import android.content.Intent;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080025import android.hardware.contexthub.V1_0.ContextHubMsg;
26import android.hardware.contexthub.V1_0.IContexthub;
27import android.hardware.contexthub.V1_0.Result;
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -070028import android.hardware.location.ContextHubInfo;
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -070029import android.hardware.location.ContextHubManager;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080030import android.hardware.location.ContextHubTransaction;
31import android.hardware.location.IContextHubClient;
32import android.hardware.location.IContextHubClientCallback;
33import android.hardware.location.NanoAppMessage;
Arthur Ishiguro672d8a72019-12-02 15:16:08 -080034import android.os.Binder;
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080035import android.os.IBinder;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080036import android.os.RemoteException;
37import android.util.Log;
Mike Maac0cae72020-01-15 17:26:24 -080038import android.util.proto.ProtoOutputStream;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080039
Arthur Ishiguro672d8a72019-12-02 15:16:08 -080040import java.util.concurrent.atomic.AtomicBoolean;
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -070041import java.util.function.Supplier;
42
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080043/**
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080044 * A class that acts as a broker for the ContextHubClient, which handles messaging and life-cycle
45 * notification callbacks. This class implements the IContextHubClient object, and the implemented
46 * APIs must be thread-safe.
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080047 *
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -080048 * TODO: Consider refactoring this class via inheritance
49 *
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080050 * @hide
51 */
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080052public class ContextHubClientBroker extends IContextHubClient.Stub
53 implements IBinder.DeathRecipient {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080054 private static final String TAG = "ContextHubClientBroker";
55
56 /*
57 * The context of the service.
58 */
59 private final Context mContext;
60
61 /*
62 * The proxy to talk to the Context Hub HAL.
63 */
64 private final IContexthub mContextHubProxy;
65
66 /*
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080067 * The manager that registered this client.
68 */
69 private final ContextHubClientManager mClientManager;
70
71 /*
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -070072 * The object describing the hub that this client is attached to.
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080073 */
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -070074 private final ContextHubInfo mAttachedContextHubInfo;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080075
76 /*
77 * The host end point ID of this client.
78 */
79 private final short mHostEndPointId;
80
81 /*
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -070082 * The remote callback interface for this client. This will be set to null whenever the
83 * client connection is closed (either explicitly or via binder death).
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080084 */
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -070085 private IContextHubClientCallback mCallbackInterface = null;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -080086
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080087 /*
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -070088 * True if the client is still registered with the Context Hub Service, false otherwise.
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080089 */
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -070090 private boolean mRegistered = true;
Arthur Ishiguro49e030f2017-11-16 11:54:42 -080091
Arthur Ishiguro661f5022018-10-10 12:17:29 -070092 /*
93 * Internal interface used to invoke client callbacks.
94 */
95 private interface CallbackConsumer {
96 void accept(IContextHubClientCallback callback) throws RemoteException;
97 }
98
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -070099 /*
100 * The PendingIntent registered with this client.
101 */
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800102 private final PendingIntentRequest mPendingIntentRequest;
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -0700103
104 /*
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800105 * The host package associated with this client.
106 */
107 private final String mPackage;
108
109 /*
110 * True if a PendingIntent has been cancelled.
111 */
112 private AtomicBoolean mIsPendingIntentCancelled = new AtomicBoolean(false);
113
114 /*
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +0000115 * True if the application creating the client has the ACCESS_CONTEXT_HUB permission.
116 */
117 private final boolean mHasAccessContextHubPermission;
118
119 /*
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -0700120 * Helper class to manage registered PendingIntent requests from the client.
121 */
122 private class PendingIntentRequest {
123 /*
124 * The PendingIntent object to request, null if there is no open request.
125 */
126 private PendingIntent mPendingIntent;
127
128 /*
129 * The ID of the nanoapp the request is for, invalid if there is no open request.
130 */
131 private long mNanoAppId;
132
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800133 private boolean mValid = false;
134
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -0700135 PendingIntentRequest() {}
136
137 PendingIntentRequest(PendingIntent pendingIntent, long nanoAppId) {
138 mPendingIntent = pendingIntent;
139 mNanoAppId = nanoAppId;
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800140 mValid = true;
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -0700141 }
142
143 public long getNanoAppId() {
144 return mNanoAppId;
145 }
146
147 public PendingIntent getPendingIntent() {
148 return mPendingIntent;
149 }
150
151 public boolean hasPendingIntent() {
152 return mPendingIntent != null;
153 }
154
155 public void clear() {
156 mPendingIntent = null;
157 }
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800158
159 public boolean isValid() {
160 return mValid;
161 }
Arthur Ishiguro32c2bc62018-10-16 10:26:11 -0700162 }
163
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800164 /* package */ ContextHubClientBroker(
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800165 Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
Arthur Ishigurob5492862018-11-13 10:51:15 -0800166 ContextHubInfo contextHubInfo, short hostEndPointId,
167 IContextHubClientCallback callback) {
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800168 mContext = context;
169 mContextHubProxy = contextHubProxy;
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800170 mClientManager = clientManager;
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -0700171 mAttachedContextHubInfo = contextHubInfo;
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800172 mHostEndPointId = hostEndPointId;
Arthur Ishigurob5492862018-11-13 10:51:15 -0800173 mCallbackInterface = callback;
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800174 mPendingIntentRequest = new PendingIntentRequest();
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800175 mPackage = mContext.getPackageManager().getNameForUid(Binder.getCallingUid());
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +0000176
177 mHasAccessContextHubPermission = context.checkCallingPermission(
178 Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800179 }
180
181 /* package */ ContextHubClientBroker(
182 Context context, IContexthub contextHubProxy, ContextHubClientManager clientManager,
183 ContextHubInfo contextHubInfo, short hostEndPointId, PendingIntent pendingIntent,
184 long nanoAppId) {
185 mContext = context;
186 mContextHubProxy = contextHubProxy;
187 mClientManager = clientManager;
188 mAttachedContextHubInfo = contextHubInfo;
189 mHostEndPointId = hostEndPointId;
190 mPendingIntentRequest = new PendingIntentRequest(pendingIntent, nanoAppId);
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800191 mPackage = pendingIntent.getCreatorPackage();
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +0000192
193 mHasAccessContextHubPermission = context.checkCallingPermission(
194 Manifest.permission.ACCESS_CONTEXT_HUB) == PERMISSION_GRANTED;
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800195 }
196
197 /**
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800198 * Sends from this client to a nanoapp.
199 *
200 * @param message the message to send
201 * @return the error code of sending the message
202 */
203 @ContextHubTransaction.Result
204 @Override
205 public int sendMessageToNanoApp(NanoAppMessage message) {
206 ContextHubServiceUtil.checkPermissions(mContext);
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800207
208 int result;
Arthur Ishiguroa96fbfe2018-11-13 10:00:35 -0800209 if (isRegistered()) {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700210 ContextHubMsg messageToNanoApp =
211 ContextHubServiceUtil.createHidlContextHubMessage(mHostEndPointId, message);
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800212
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -0700213 int contextHubId = mAttachedContextHubInfo.getId();
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800214 try {
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -0700215 result = mContextHubProxy.sendMessageToHub(contextHubId, messageToNanoApp);
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800216 } catch (RemoteException e) {
217 Log.e(TAG, "RemoteException in sendMessageToNanoApp (target hub ID = "
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -0700218 + contextHubId + ")", e);
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800219 result = Result.UNKNOWN_FAILURE;
220 }
221 } else {
222 Log.e(TAG, "Failed to send message to nanoapp: client connection is closed");
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800223 result = Result.UNKNOWN_FAILURE;
224 }
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800225
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800226 return ContextHubServiceUtil.toTransactionResult(result);
227 }
228
229 /**
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800230 * Closes the connection for this client with the service.
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800231 *
232 * If the client has a PendingIntent registered, this method also unregisters it.
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800233 */
234 @Override
235 public void close() {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700236 synchronized (this) {
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800237 mPendingIntentRequest.clear();
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800238 }
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800239 onClientExit();
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800240 }
241
242 /**
243 * Invoked when the underlying binder of this broker has died at the client process.
244 */
Arthur Ishiguro9f6284e2018-10-10 11:09:02 -0700245 @Override
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800246 public void binderDied() {
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800247 onClientExit();
Arthur Ishiguro49e030f2017-11-16 11:54:42 -0800248 }
249
250 /**
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800251 * @return the ID of the context hub this client is attached to
252 */
253 /* package */ int getAttachedContextHubId() {
Arthur Ishiguro622ebcb2018-10-17 14:02:27 -0700254 return mAttachedContextHubInfo.getId();
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800255 }
256
257 /**
258 * @return the host endpoint ID of this client
259 */
260 /* package */ short getHostEndPointId() {
261 return mHostEndPointId;
262 }
263
264 /**
265 * Sends a message to the client associated with this object.
266 *
267 * @param message the message that came from a nanoapp
268 */
269 /* package */ void sendMessageToClient(NanoAppMessage message) {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700270 invokeCallback(callback -> callback.onMessageFromNanoApp(message));
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -0700271
272 Supplier<Intent> supplier =
273 () -> createIntent(ContextHubManager.EVENT_NANOAPP_MESSAGE, message.getNanoAppId())
274 .putExtra(ContextHubManager.EXTRA_MESSAGE, message);
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800275 sendPendingIntent(supplier, message.getNanoAppId());
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800276 }
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800277
278 /**
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800279 * Notifies the client of a nanoapp load event if the connection is open.
Arthur Ishiguro0069f122017-11-20 15:07:14 -0800280 *
281 * @param nanoAppId the ID of the nanoapp that was loaded.
282 */
283 /* package */ void onNanoAppLoaded(long nanoAppId) {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700284 invokeCallback(callback -> callback.onNanoAppLoaded(nanoAppId));
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800285 sendPendingIntent(
286 () -> createIntent(ContextHubManager.EVENT_NANOAPP_LOADED, nanoAppId), nanoAppId);
Arthur Ishiguro0069f122017-11-20 15:07:14 -0800287 }
288
289 /**
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800290 * Notifies the client of a nanoapp unload event if the connection is open.
Arthur Ishiguro0069f122017-11-20 15:07:14 -0800291 *
292 * @param nanoAppId the ID of the nanoapp that was unloaded.
293 */
294 /* package */ void onNanoAppUnloaded(long nanoAppId) {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700295 invokeCallback(callback -> callback.onNanoAppUnloaded(nanoAppId));
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800296 sendPendingIntent(
297 () -> createIntent(ContextHubManager.EVENT_NANOAPP_UNLOADED, nanoAppId), nanoAppId);
Arthur Ishiguro0069f122017-11-20 15:07:14 -0800298 }
299
300 /**
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800301 * Notifies the client of a hub reset event if the connection is open.
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800302 */
303 /* package */ void onHubReset() {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700304 invokeCallback(callback -> callback.onHubReset());
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -0700305 sendPendingIntent(() -> createIntent(ContextHubManager.EVENT_HUB_RESET));
Arthur Ishiguro6d47c542017-11-17 15:49:07 -0800306 }
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800307
308 /**
309 * Notifies the client of a nanoapp abort event if the connection is open.
310 *
311 * @param nanoAppId the ID of the nanoapp that aborted
312 * @param abortCode the nanoapp specific abort code
313 */
314 /* package */ void onNanoAppAborted(long nanoAppId, int abortCode) {
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700315 invokeCallback(callback -> callback.onNanoAppAborted(nanoAppId, abortCode));
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -0700316
317 Supplier<Intent> supplier =
318 () -> createIntent(ContextHubManager.EVENT_NANOAPP_ABORTED, nanoAppId)
319 .putExtra(ContextHubManager.EXTRA_NANOAPP_ABORT_CODE, abortCode);
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800320 sendPendingIntent(supplier, nanoAppId);
Arthur Ishiguro661f5022018-10-10 12:17:29 -0700321 }
322
323 /**
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800324 * @param intent the PendingIntent to compare to
325 * @param nanoAppId the ID of the nanoapp of the PendingIntent to compare to
Arthur Ishigurod3464c72018-10-16 11:08:28 -0700326 * @return true if the given PendingIntent is currently registered, false otherwise
327 */
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800328 /* package */ boolean hasPendingIntent(PendingIntent intent, long nanoAppId) {
Arthur Ishigurod3464c72018-10-16 11:08:28 -0700329 PendingIntent pendingIntent = null;
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800330 long intentNanoAppId;
Arthur Ishigurod3464c72018-10-16 11:08:28 -0700331 synchronized (this) {
332 pendingIntent = mPendingIntentRequest.getPendingIntent();
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800333 intentNanoAppId = mPendingIntentRequest.getNanoAppId();
Arthur Ishigurod3464c72018-10-16 11:08:28 -0700334 }
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800335 return (pendingIntent != null) && pendingIntent.equals(intent)
336 && intentNanoAppId == nanoAppId;
Arthur Ishigurod3464c72018-10-16 11:08:28 -0700337 }
338
339 /**
Arthur Ishigurob5492862018-11-13 10:51:15 -0800340 * Attaches the death recipient to the callback interface object, if any.
341 *
342 * @throws RemoteException if the client process already died
343 */
344 /* package */ void attachDeathRecipient() throws RemoteException {
345 if (mCallbackInterface != null) {
346 mCallbackInterface.asBinder().linkToDeath(this, 0 /* flags */);
347 }
348 }
349
350 /**
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800351 * @return true if the client is a PendingIntent client that has been cancelled.
352 */
353 /* package */ boolean isPendingIntentCancelled() {
354 return mIsPendingIntentCancelled.get();
355 }
356
357 /**
Arthur Ishiguro661f5022018-10-10 12:17:29 -0700358 * Helper function to invoke a specified client callback, if the connection is open.
359 *
360 * @param consumer the consumer specifying the callback to invoke
361 */
Arthur Ishigurodaeed3c2018-10-01 15:42:27 -0700362 private synchronized void invokeCallback(CallbackConsumer consumer) {
363 if (mCallbackInterface != null) {
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800364 try {
Arthur Ishiguro661f5022018-10-10 12:17:29 -0700365 consumer.accept(mCallbackInterface);
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800366 } catch (RemoteException e) {
Arthur Ishiguro661f5022018-10-10 12:17:29 -0700367 Log.e(TAG, "RemoteException while invoking client callback (host endpoint ID = "
368 + mHostEndPointId + ")", e);
Arthur Ishiguro02ff50b2017-12-18 10:02:35 -0800369 }
370 }
371 }
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -0700372
373 /**
374 * Creates an Intent object containing the ContextHubManager.EXTRA_EVENT_TYPE extra field
375 *
376 * @param eventType the ContextHubManager.Event type describing the event
377 * @return the Intent object
378 */
379 private Intent createIntent(int eventType) {
380 Intent intent = new Intent();
381 intent.putExtra(ContextHubManager.EXTRA_EVENT_TYPE, eventType);
382 intent.putExtra(ContextHubManager.EXTRA_CONTEXT_HUB_INFO, mAttachedContextHubInfo);
383 return intent;
384 }
385
386 /**
387 * Creates an Intent object containing the ContextHubManager.EXTRA_EVENT_TYPE and the
388 * ContextHubManager.EXTRA_NANOAPP_ID extra fields
389 *
390 * @param eventType the ContextHubManager.Event type describing the event
391 * @param nanoAppId the ID of the nanoapp this event is for
392 * @return the Intent object
393 */
394 private Intent createIntent(int eventType, long nanoAppId) {
395 Intent intent = createIntent(eventType);
396 intent.putExtra(ContextHubManager.EXTRA_NANOAPP_ID, nanoAppId);
397 return intent;
398 }
399
400 /**
401 * Sends an intent to any existing PendingIntent
402 *
403 * @param supplier method to create the extra Intent
404 */
405 private synchronized void sendPendingIntent(Supplier<Intent> supplier) {
406 if (mPendingIntentRequest.hasPendingIntent()) {
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800407 doSendPendingIntent(mPendingIntentRequest.getPendingIntent(), supplier.get());
408 }
409 }
410
411 /**
412 * Sends an intent to any existing PendingIntent
413 *
414 * @param supplier method to create the extra Intent
415 * @param nanoAppId the ID of the nanoapp which this event is for
416 */
417 private synchronized void sendPendingIntent(Supplier<Intent> supplier, long nanoAppId) {
418 if (mPendingIntentRequest.hasPendingIntent()
419 && mPendingIntentRequest.getNanoAppId() == nanoAppId) {
420 doSendPendingIntent(mPendingIntentRequest.getPendingIntent(), supplier.get());
421 }
422 }
423
424 /**
425 * Sends a PendingIntent with extra Intent data
426 *
427 * @param pendingIntent the PendingIntent
428 * @param intent the extra Intent data
429 */
430 private void doSendPendingIntent(PendingIntent pendingIntent, Intent intent) {
431 try {
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +0000432 String requiredPermission = mHasAccessContextHubPermission
433 ? Manifest.permission.ACCESS_CONTEXT_HUB
434 : Manifest.permission.LOCATION_HARDWARE;
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800435 pendingIntent.send(
436 mContext, 0 /* code */, intent, null /* onFinished */, null /* Handler */,
Arthur Ishiguro0cf065e2020-01-22 17:05:26 +0000437 requiredPermission, null /* options */);
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800438 } catch (PendingIntent.CanceledException e) {
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800439 mIsPendingIntentCancelled.set(true);
Arthur Ishigurobb8ca1a2018-12-06 13:49:40 -0800440 // The PendingIntent is no longer valid
441 Log.w(TAG, "PendingIntent has been canceled, unregistering from client"
442 + " (host endpoint ID " + mHostEndPointId + ")");
443 close();
Arthur Ishiguro9aa88e02018-10-16 10:26:57 -0700444 }
445 }
Arthur Ishiguroa96fbfe2018-11-13 10:00:35 -0800446
447 /**
448 * @return true if the client is still registered with the service, false otherwise
449 */
450 private synchronized boolean isRegistered() {
451 return mRegistered;
452 }
Arthur Ishiguro82ed3af2018-11-09 13:20:30 -0800453
454 /**
455 * Invoked when a client exits either explicitly or by binder death.
456 */
457 private synchronized void onClientExit() {
458 if (mCallbackInterface != null) {
459 mCallbackInterface.asBinder().unlinkToDeath(this, 0 /* flags */);
460 mCallbackInterface = null;
461 }
462 if (!mPendingIntentRequest.hasPendingIntent() && mRegistered) {
463 mClientManager.unregisterClient(mHostEndPointId);
464 mRegistered = false;
465 }
466 }
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800467
Mike Maac0cae72020-01-15 17:26:24 -0800468 /**
469 * Dump debugging info as ClientBrokerProto
470 *
471 * If the output belongs to a sub message, the caller is responsible for wrapping this function
472 * between {@link ProtoOutputStream#start(long)} and {@link ProtoOutputStream#end(long)}.
473 *
474 * @param proto the ProtoOutputStream to write to
475 */
476 void dump(ProtoOutputStream proto) {
477 proto.write(ClientBrokerProto.ENDPOINT_ID, getHostEndPointId());
478 proto.write(ClientBrokerProto.ATTACHED_CONTEXT_HUB_ID, getAttachedContextHubId());
479 proto.write(ClientBrokerProto.PACKAGE, mPackage);
480 if (mPendingIntentRequest.isValid()) {
481 proto.write(ClientBrokerProto.PENDING_INTENT_REQUEST_VALID, true);
482 proto.write(ClientBrokerProto.NANO_APP_ID, mPendingIntentRequest.getNanoAppId());
483 }
484 proto.write(ClientBrokerProto.HAS_PENDING_INTENT, mPendingIntentRequest.hasPendingIntent());
485 proto.write(ClientBrokerProto.PENDING_INTENT_CANCELLED, isPendingIntentCancelled());
486 proto.write(ClientBrokerProto.REGISTERED, mRegistered);
487
488 }
489
Arthur Ishiguro672d8a72019-12-02 15:16:08 -0800490 @Override
491 public String toString() {
492 String out = "[ContextHubClient ";
493 out += "endpointID: " + getHostEndPointId() + ", ";
494 out += "contextHub: " + getAttachedContextHubId() + ", ";
495 if (mPendingIntentRequest.isValid()) {
496 out += "intentCreatorPackage: " + mPackage + ", ";
497 out += "nanoAppId: 0x" + Long.toHexString(mPendingIntentRequest.getNanoAppId());
498 } else {
499 out += "package: " + mPackage;
500 }
501 out += "]";
502
503 return out;
504 }
Arthur Ishiguro4e39aa12017-11-14 14:59:08 -0800505}