1 /*
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 package android.hardware.location;
17 
18 import android.annotation.NonNull;
19 import android.annotation.RequiresPermission;
20 import android.annotation.SystemApi;
21 import android.app.PendingIntent;
22 import android.os.RemoteException;
23 
24 import com.android.internal.util.Preconditions;
25 
26 import dalvik.system.CloseGuard;
27 
28 import java.io.Closeable;
29 import java.util.concurrent.atomic.AtomicBoolean;
30 
31 /**
32  * A class describing a client of the Context Hub Service.
33  *
34  * Clients can send messages to nanoapps at a Context Hub through this object. The APIs supported
35  * by this object are thread-safe and can be used without external synchronization.
36  *
37  * @hide
38  */
39 @SystemApi
40 public class ContextHubClient implements Closeable {
41     /*
42      * The proxy to the client interface at the service.
43      */
44     private IContextHubClient mClientProxy = null;
45 
46     /*
47      * The Context Hub that this client is attached to.
48      */
49     private final ContextHubInfo mAttachedHub;
50 
51     private final CloseGuard mCloseGuard;
52 
53     private final AtomicBoolean mIsClosed = new AtomicBoolean(false);
54 
55     /*
56      * True if this is a persistent client (i.e. does not have to close the connection when the
57      * resource is freed from the system).
58      */
59     private final boolean mPersistent;
60 
ContextHubClient(ContextHubInfo hubInfo, boolean persistent)61     /* package */ ContextHubClient(ContextHubInfo hubInfo, boolean persistent) {
62         mAttachedHub = hubInfo;
63         mPersistent = persistent;
64         if (mPersistent) {
65             mCloseGuard = null;
66         } else {
67             mCloseGuard = CloseGuard.get();
68             mCloseGuard.open("close");
69         }
70     }
71 
72     /**
73      * Sets the proxy interface of the client at the service. This method should always be called
74      * by the ContextHubManager after the client is registered at the service, and should only be
75      * called once.
76      *
77      * @param clientProxy the proxy of the client at the service
78      */
setClientProxy(IContextHubClient clientProxy)79     /* package */ void setClientProxy(IContextHubClient clientProxy) {
80         Preconditions.checkNotNull(clientProxy, "IContextHubClient cannot be null");
81         if (mClientProxy != null) {
82             throw new IllegalStateException("Cannot change client proxy multiple times");
83         }
84 
85         mClientProxy = clientProxy;
86     }
87 
88     /**
89      * Returns the hub that this client is attached to.
90      *
91      * @return the ContextHubInfo of the attached hub
92      */
93     @NonNull
getAttachedHub()94     public ContextHubInfo getAttachedHub() {
95         return mAttachedHub;
96     }
97 
98     /**
99      * Closes the connection for this client and the Context Hub Service.
100      *
101      * When this function is invoked, the messaging associated with this client is invalidated.
102      * All futures messages targeted for this client are dropped at the service, and the
103      * ContextHubClient is unregistered from the service.
104      *
105      * If this object has a PendingIntent, i.e. the object was generated via
106      * {@link ContextHubManager.createClient(PendingIntent, ContextHubInfo, long)}, then the
107      * Intent events corresponding to the PendingIntent will no longer be triggered.
108      */
close()109     public void close() {
110         if (!mIsClosed.getAndSet(true)) {
111             if (mCloseGuard != null) {
112                 mCloseGuard.close();
113             }
114             try {
115                 mClientProxy.close();
116             } catch (RemoteException e) {
117                 throw e.rethrowFromSystemServer();
118             }
119         }
120     }
121 
122     /**
123      * Sends a message to a nanoapp through the Context Hub Service.
124      *
125      * This function returns RESULT_SUCCESS if the message has reached the HAL, but
126      * does not guarantee delivery of the message to the target nanoapp.
127      *
128      * @param message the message object to send
129      *
130      * @return the result of sending the message defined as in ContextHubTransaction.Result
131      *
132      * @throws NullPointerException if NanoAppMessage is null
133      *
134      * @see NanoAppMessage
135      * @see ContextHubTransaction.Result
136      */
137     @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
138     @ContextHubTransaction.Result
sendMessageToNanoApp(@onNull NanoAppMessage message)139     public int sendMessageToNanoApp(@NonNull NanoAppMessage message) {
140         Preconditions.checkNotNull(message, "NanoAppMessage cannot be null");
141 
142         try {
143             return mClientProxy.sendMessageToNanoApp(message);
144         } catch (RemoteException e) {
145             throw e.rethrowFromSystemServer();
146         }
147     }
148 
149     @Override
finalize()150     protected void finalize() throws Throwable {
151         try {
152             if (mCloseGuard != null) {
153                 mCloseGuard.warnIfOpen();
154             }
155             if (!mPersistent) {
156                 close();
157             }
158         } finally {
159             super.finalize();
160         }
161     }
162 }
163